/*!\file:  HoleFillerx.cpp
 * \brief  plug missing values of a double* array, using interpolation techniques. This 
 * is an adaptation of Dr. Crippen's routine (Jet Propulsion Lab)
 */ 

#include <stdio.h>
#include <time.h>
#include "./HoleFillerx.h"
#include "../../shared/shared.h"

int HoleFillerx(double** pimageout,double* image, int lines,int samps,int smooth){

	long			infinit;
	double          temp;
	long			i, j, k, l, ii, jj;
	long			iii, jjj;
	long			test;
	float			nsteps, ssteps, wsteps, esteps;
	float			nwsteps, nesteps, swsteps, sesteps;
	float			north, south, east, west;
	float			nw, sw, ne, se, elev, range;
	float			nnesteps, enesteps, esesteps, ssesteps;
	float			sswsteps, wswsteps, wnwsteps, nnwsteps;
	float			nne, ene, ese, sse;
	float			ssw, wsw, wnw, nnw;	
	float			sum;

	time_t			t1, t2;

	/*output: */
	double*         imageout=NULL;

	double*         image2=NULL;
	double*         image3=NULL;
	double*         image4=NULL;

	 /*^^^^^^^^^^^^^  Remove pixels close to the holes ^^^^^^^^^^^^^*/
	image2 = xNew<double>(lines*samps);
	memcpy(image2,image,lines*samps*sizeof(double));

  	for ( i = 0; i < lines; i++ ){
  		for ( j = 0; j < samps; j++ ){
 			if ( *(image+i*samps+j) == 0 ){ 
  				if ( (j > 3) && (j < samps-4) && (i > 3) && (i < lines-4)){
					for ( k = 0; k < 4; k++ ){
						for ( l = 0; l < 4; l++ ){
							*(image2+samps*(i+k)+j+l)=0;
							*(image2+samps*(i-k)+j+l)=0;
							*(image2+samps*(i+k)+j-l)=0;
							*(image2+samps*(i-k)+j-l)=0;

						}
					}
				}
			}
		}
	}

	image3 = xNew<double>(lines*samps);
	memcpy(image3,image2,lines*samps*sizeof(double));

	#ifdef _DEBUG2_
		counter=0;
		for ( i = 0; i < lines; i++ ) {
			for ( j = 0; j < samps; j++ ){
				if ( *(image2+i*samps+j) != 0 ) { 
					counter++;
				}
			}
		}
		_printLine_( "" );
		_printString_("Number of zeroes remaining: " << lines*samps-counter);
		fflush( stdout );
	#endif

	goto afterfirst2;

	again2:	

	#ifdef _DEBUG2_
		counter=0;
		for ( i = 0; i < lines; i++ ) {
			for ( j = 0; j < samps; j++ ){
				if ( *(image2+i*samps+j) != 0 ) { 
					counter++;
				}
			}
		}
		//        n u m b e r   o f   z e r o e s   r e m a i n i n g :   1 2 3 4 5 6 7 8 9 10        
		_printString_( "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" );
		_printString_("Number of zeroes remaining: " << lines*samps-counter);
		fflush( stdout );
	#endif

	afterfirst2:

/***************** FIRST RUN *********************/
/*
fprintf ( stdout, "First  Application:  " ); time(&t2); _printString_( ctime(&t2) );
*/
	for ( i = 0; i < lines; i++ ){
		for ( j = 0; j < samps; j++ ){
			if ( *(image2+i*samps+j) != 0 ){ 
				*(image3+samps*i+j) = *(image2+i*samps+j); 
				continue; 
			} 

	/* Count All Neighbors Test */
			test = 0;		
			for ( ii = i-1; ii < i+2; ii++ ){
				for ( jj = j-1; jj < j+2; jj++ ){
					if (( ii < 0 ) || ( ii >= lines )) continue;
					if (( jj < 0 ) || ( jj >= samps )) continue;
					if ( *(image2+ii*samps+jj) != 0 ) test += 1;			
				}
			}
			if ( test < 3 ){ 
				*(image3+samps*i+j) = 0; 
				continue; 
			} 

			/* For void edge pixels: */			

			nsteps = 0.0; ssteps = 0.0; esteps = 0.0; wsteps = 0.0;
			nwsteps = 0.0; nesteps = 0.0; swsteps = 0.0; sesteps = 0.0;
			north = 0.0; south = 0.0; east = 0.0; west = 0.0;
			nw = 0.0; ne = 0.0; sw = 0.0; se = 0.0;

			nnesteps = 0.0; enesteps = 0.0; esesteps = 0.0; ssesteps = 0.0;
			sswsteps = 0.0; wswsteps = 0.0; wnwsteps = 0.0; nnwsteps = 0.0;
			nne = 0.0; ene = 0.0; ese = 0.0; sse = 0.0;
			ssw = 0.0; wsw = 0.0; wnw = 0.0; nnw = 0.0;

/** NSEW **/
			for ( ii = i - 1; ii >= 0; ii-- ){   /* North */
				if ( ii <= 0 ) { north = 0; nsteps = 0; break;}
				if ( *(image2+ii*samps+j) != 0 ){ north = *(image2+ii*samps+j); nsteps = i - ii; break;}
			}

			for ( ii = i + 1; ii < lines; ii++ ){ /* South */ 
				if ( ii >= lines-1 ){ south = 0; ssteps = 0; break;}
				if ( *(image2+ii*samps+j) != 0 ){ south = *(image2+ii*samps+j); ssteps = ii - i; break;}
			}

			for ( jj = j - 1; jj >= 0; jj-- ){   /* West */
				if ( jj <= 0 ) { west = 0; wsteps = 0; break;}
				if ( *(image2+i*samps+jj) != 0 ){ west = *(image2+i*samps+jj); wsteps = j - jj; break;}
			}

			for ( jj = j + 1; jj < samps; jj++ ){ /* East */
				if ( jj >= samps-1 ){ east = 0; esteps = 0; break;}
				if ( *(image2+i*samps+jj) != 0 ){ east = *(image2+i*samps+jj); esteps = jj - j; break;}
			}

/** Diagonals  **/						
			/* Southeast */
			for ( k = 1; k < infinit; k++ ){
				ii = i + k; jj = j + k;
				if (( ii == lines ) || ( jj == samps )){ se = 0; sesteps = 0; break;}
				if ( *(image2+ii*samps+jj) != 0 ){ se = *(image2+ii*samps+jj); sesteps = 1.4142 * k; break;}
			}

			/* Northeast */
			for ( k = 1; k < infinit; k++ ){
				ii = i - k; jj = j + k;
				if (( ii == -1 ) || ( jj == samps )){ ne = 0; nesteps = 0; break;}
				if ( *(image2+ii*samps+jj) != 0 ){ ne = *(image2+ii*samps+jj); nesteps = 1.4142 * k; break;}
			}

			/* Northwest */
			for ( k = 1; k < infinit; k++ ){
				ii = i - k; jj = j - k;
				if (( ii == -1 ) || ( jj == -1 )){ nw = 0; nwsteps = 0; break;}
				if ( *(image2+ii*samps+jj) != 0 ){ nw = *(image2+ii*samps+jj); nwsteps = 1.4142 * k; break;}
			}

			/* Southwest */
			for ( k = 1; k < infinit; k++ ){
				ii = i + k; jj = j - k;
				if (( ii == lines ) || ( jj == -1 )){ sw = 0; swsteps = 0; break;}
				if ( *(image2+ii*samps+jj) != 0 ){ sw = *(image2+ii*samps+jj); swsteps = 1.4142 * k; break;}
			}

/** Other 8 **/
			/* NNE */
			for ( k = 1; k < infinit; k++ ){
				ii = i - (k*2); jj = j + k;
				if (( ii <= -1 ) || ( jj >= samps )){ nne = 0; nnesteps = 0; break;}
				if ( *(image2+ii*samps+jj) != 0 ){ nne = *(image2+ii*samps+jj); nnesteps = 2.2361 * k; break;}
			}

			/* ENE */
			for ( k = 1; k < infinit; k++ ){
				ii = i - k; jj = j + (k*2);
				if (( ii <= -1 ) || ( jj >= samps )){ ene = 0; enesteps = 0; break;}
				if ( *(image2+ii*samps+jj) != 0 ){ ene = *(image2+ii*samps+jj); enesteps = 2.2361 * k; break;}
			}

			/* ESE */
			for ( k = 1; k < infinit; k++ ){
				ii = i + k; jj = j + (k*2);
				if (( ii >= lines ) || ( jj >= samps )){ ese = 0; esesteps = 0; break;}
				if ( *(image2+ii*samps+jj) != 0 ){ ese = *(image2+ii*samps+jj); esesteps = 2.2361 * k; break;}
			}

			/* SSE */
			for ( k = 1; k < infinit; k++ ){
				ii = i + (k*2); jj = j + k;
				if (( ii >= lines ) || ( jj >= samps )){ sse = 0; ssesteps = 0; break;}
				if ( *(image2+ii*samps+jj) != 0 ){ sse = *(image2+ii*samps+jj); ssesteps = 2.2361 * k; break;}
			}

			/* SSW */
			for ( k = 1; k < infinit; k++ ){
				ii = i + (k*2); jj = j - k;
				if (( ii >= lines ) || ( jj <= -1 )){ ssw = 0; sswsteps = 0; break;}
				if ( *(image2+ii*samps+jj) != 0 ){ ssw = *(image2+ii*samps+jj); sswsteps = 2.2361 * k; break;}
			}

			/* WSW */
			for ( k = 1; k < infinit; k++ ){
				ii = i + k; jj = j - (k*2);
				if (( ii >= lines ) || ( jj <= -1 )){ wsw = 0; wswsteps = 0; break;}
				if ( *(image2+ii*samps+jj) != 0 ){ wsw = *(image2+ii*samps+jj); wswsteps = 2.2361 * k; break;}
			}

			/* WNW */
			for ( k = 1; k < infinit; k++ ){
				ii = i - k; jj = j - (k*2);
				if (( ii <= -1 ) || ( jj <= -1 )){ wnw = 0; wnwsteps = 0; break;}
				if ( *(image2+ii*samps+jj) != 0 ){ wnw = *(image2+ii*samps+jj); wnwsteps = 2.2361 * k; break;}
			}

			/* NNW */
			for ( k = 1; k < infinit; k++ ){
				ii = i - (k*2); jj = j - k;
				if (( ii <= -1 ) || ( jj <= -1 )){ nnw = 0; nnwsteps = 0; break;}
				if ( *(image2+ii*samps+jj) != 0 ){ nnw = *(image2+ii*samps+jj); nnwsteps = 2.2361 * k; break;}
			}

			elev = 0; range = 0;
/*NSEW*/			
			if ( nsteps > 0.5 ){ elev += north /  nsteps; range +=  1.00 /  nsteps;}
			if ( ssteps > 0.5 ){ elev += south /  ssteps; range +=  1.00 /  ssteps;}
			if ( esteps > 0.5 ){ elev +=  east /  esteps; range +=  1.00 /  esteps;}
			if ( wsteps > 0.5 ){ elev +=  west /  wsteps; range +=  1.00 /  wsteps;}
/*Diag*/
			if ( nwsteps > 0.5 ){ elev +=    nw / nwsteps; range +=  1.00 / nwsteps;}
			if ( nesteps > 0.5 ){ elev +=    ne / nesteps; range +=  1.00 / nesteps;}
			if ( swsteps > 0.5 ){ elev +=    sw / swsteps; range +=  1.00 / swsteps;}
			if ( sesteps > 0.5 ){ elev +=    se / sesteps; range +=  1.00 / sesteps;}

/*Other 8*/
			if ( nnesteps > 0.5 ){ elev += nne / nnesteps; range +=  1.00 / nnesteps;}
			if ( enesteps > 0.5 ){ elev += ene / enesteps; range +=  1.00 / enesteps;}
			if ( esesteps > 0.5 ){ elev += ese / esesteps; range +=  1.00 / esesteps;}
			if ( ssesteps > 0.5 ){ elev += sse / ssesteps; range +=  1.00 / ssesteps;}
			if ( sswsteps > 0.5 ){ elev += ssw / sswsteps; range +=  1.00 / sswsteps;}
			if ( wswsteps > 0.5 ){ elev += wsw / wswsteps; range +=  1.00 / wswsteps;}
			if ( wnwsteps > 0.5 ){ elev += wnw / wnwsteps; range +=  1.00 / wnwsteps;}
			if ( nnwsteps > 0.5 ){ elev += nnw / nnwsteps; range +=  1.00 / nnwsteps;}

			//temp = ( elev / range ) + 0.5 ;
			temp = ( elev / range );
			//+ 0.5 ;
			//if ( temp > 10000 ) temp = 10000;
			//if ( temp <     0 ) temp =     0;

			#ifdef _DEBUG2_
				//_printLine_(temp << " " << elev << " " << range << " ");
			#endif

			*(image3+samps*i+j) = temp ;			
		}
	}

	for ( i = 0; i < lines; i++ ){
		for ( j = 0; j < samps; j++ ){
			*(image2+samps*i+j)= *(image3+samps*i+j);
		}
	}

	for ( i = 0; i < lines; i++ ){
		for ( j = 0; j < samps; j++ ){
			if ( *(image2+samps*i+j) == 0 ) goto again2;
		}
	}

	if ( smooth == 0 ) goto there2;		

/************************ SMOOTH THE RESULT ***********************/		

	image4 = xNew<double>(lines*samps);
	memcpy(image4,image3,lines*samps*sizeof(double));

	for ( i = 0; i < lines; i++ ) {
		for ( j = 0; j < samps; j++ ) {
			if ( *(image4+i*samps+j) != 0 ) { *(image3+i*samps+j) = *(image2+i*samps+j) ; continue; }

			for ( k = 1; k < infinit; k++ ) { /* Find the smallest box size with data */ 
				for ( ii = i-k; ii <= i+k; ii++ ){
					if ( ii <      0 ) continue;
					if ( ii >= lines ) break;
					for ( jj = j-k; jj <= j+k; jj++ ) {
						if ( jj <      0 ) continue;
						if ( jj >= samps ) continue;
						if ( *(image4+ii*samps+jj) != 0 ) goto k_nowset;
					}
				}
			}

			k_nowset:
			k = k / 4; if ( k < 1 ) k = 1; /* Errrrr.  Make it fourth size */
			sum = 0;
			for ( ii = i-k; ii <= i+k; ii++ ) {
				if ( ii <      0 ) iii = -1 - ii; else iii = ii;
				if ( ii >= lines ) iii = lines - (ii - lines + 1);
				for ( jj = j-k; jj <= j+k; jj++ ) {
					if ( jj <      0 ) jjj = -1 - jj; else jjj = jj;
					if ( jj >= samps ) jjj = samps - (jj - samps + 1);
					sum += *(image2+samps*iii+jjj) ;
				}
			}
			k = (k*2)+1;
			*(image3+samps*i+j) = ( sum / k / k ) ;//+ 0.5;
		}

	}

there2:		

	/*Allocate output image: */
	imageout=xNew<double>(samps*lines);
	memcpy(imageout,image3,lines*samps*sizeof(double));

	time(&t2);	

	#ifdef _DEBUG2_
		_printString_( "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" );
		_printLine_("Number of zeroes remaining:          0\n");
		printf ( "\n");
	#endif

	end:

	/*Assign output pointers: */
	*pimageout=imageout;
	return 1;
}
