#include "ppm.h"
#include "stdlib.h" //feris
#include "windows.h" //feris

void enhanceGradient(Image *gradHx, Image *gradHy, Image * edgeimage)
{
	int LP[3] = { -1, 2, -1};
	int width = edgeimage->width;
	int height = edgeimage->height;
	double factor = 2.0;
	for(int i = 2; i <= width - 1; i++){
		for(int j = 2; j <= height - 1; j++){
			
			int pos1 = j * width + i;
			double tempx, tempy;
			//check edge mask
			//if(edgeimage->data[pos1] == 255){
				int highfreqx = 0, highfreqy = 0;
				for(int tempi = -1; tempi <= 1; tempi ++){
					highfreqx += (int)(LP[tempi + 1] * ImageGetPixelf(gradHx, i + tempi, j, 0, GRAY));
					highfreqy += (int) (LP[tempi + 1] * ImageGetPixelf(gradHy, i, j + tempi, 0, GRAY));	
				}
				//now add back
				tempx = ImageGetPixelf(gradHx, i, j, 0, GRAY) + factor * highfreqx;
				tempy = ImageGetPixelf(gradHy, i, j, 0, GRAY) + factor * highfreqy;

				ImageSetPixelf(gradHx, i, j, 0, tempx, GRAY) ; 
				ImageSetPixelf(gradHy, i, j, 0, tempy, GRAY) ; 
			//}
		}
	}
}

void smoothGradient(Image *gradHx, Image *gradHy, Image * maskimage)
{
  int size = 1;
  int width = maskimage->width, height = maskimage->height;

  for (int i= 1 + size; i <= width - size; i++) {
	  for (int j= 1 + size; j <= height - size; j++) {
		  int pos = j * width + i;
		  double minx = 100000;
		  double miny = 100000;
		  double tempx = 0, tempy = 0;
		  //if(maskimage->data[pos] == 0){//smooth gradient
			  for(int tempi = -size; tempi <= size; tempi++){
				tempx += ImageGetPixelf(gradHx, i + tempi, j, 0, GRAY);
				tempy += ImageGetPixelf(gradHy, i, j + tempi, 0, GRAY);
				
				/*if(fabs(tempx) < fabs(minx))
					minx = tempx;
				if(fabs(tempy) < fabs(miny))
					miny = tempy;*/
			  }
			  //suppress the local minimum
			  minx = tempx / (2.0 * size + 1);
			  miny = tempy / (2.0 * size + 1);
			  
			  ImageSetPixelf(gradHx, i, j, 0, minx, GRAY) ; 
			  ImageSetPixelf(gradHy, i, j, 0, miny, GRAY) ; 
		  //}
		 
	  }
  }

}
void GradientFromImageNew(Image * hor_red, Image * hor_redblur, Image * hor_blue, Image * hor_blueblur,
				 Image * ver_red, Image * ver_redblur, Image * ver_blue, Image * ver_blueblur, 
				 Image * gradHx, Image * gradHy)
{
	int width = hor_red->width;
	int height = hor_red->width;
	for(int i = 1; i < width; i++){
		for(int j = 1; j < height; j++){
			int pos = j * width + i;
			//double tempx = horimage->data[pos] / 255.0;
			//double tempy = verimage->data[pos] / 255.0;
			double tempxred = (hor_red->data[pos] - hor_redblur->data[pos])/255.0;
			double tempxblue = (hor_blue->data[pos] - hor_blueblur->data[pos])/255.0;

			double tempyred = (ver_red->data[pos] - ver_redblur->data[pos])/255.0;
			double tempyblue = (ver_blue->data[pos] - ver_blueblur->data[pos])/255.0;

			ImageSetPixelf(gradHx, i, j, 0, tempxred - tempxblue, GRAY);
			ImageSetPixelf(gradHy, i, j, 0, tempyred - tempyblue, GRAY);
		}
	}

}
void GradientFromImage(Image * horimage, Image * verimage, Image * gradHx, Image * gradHy)
{
	int width = horimage->width;
	int height = horimage->width;
	for(int i = 1; i < width; i++){
		for(int j = 1; j < height; j++){
			int pos = j * width + i;
			//double tempx = horimage->data[pos] / 255.0;
			//double tempy = verimage->data[pos] / 255.0;
			double tempx = (horimage->data[pos] - verimage->data[pos])/255.0; 
			ImageSetPixelf(gradHx, i, j, 0, tempx, GRAY);
			ImageSetPixelf(gradHy, i, j, 0, tempx, GRAY);
		}
	}
	//enhanceGradient(gradHx, gradHy, horimage);
}
//new code
void imageGradientNew(Image *image, Image *gradHx, Image *gradHy, Image * edgeimage, Image * maskimage)
{
  double thred = 1.0;
  
  int i, j;
  int width = image->width, height = image->height;

  //first clear all gradient
  for (i=1; i <= width; i++) {
	  for (j=1; j <= height; j++) {
		  ImageSetPixelf(gradHx, i, j, 0, 0, GRAY) ; 
		  ImageSetPixelf(gradHy, i, j, 0, 0, GRAY) ; 
	  }
  }
  //now for each edge pixel, set its left to be -1, right to be +1
  for (i = 2; i <= width - 1; i++) {
	  for (j = 2; j <= height - 1; j++) {
		  int pos = j * width + i;
		  if(edgeimage->data[pos] == 255){
				//left should be set to +1, right should be set to -1
				double templ = ImageGetPixelf(gradHx, i - 1, j, 0, GRAY);
				double tempr = ImageGetPixelf(gradHx, i + 1, j, 0, GRAY);
				ImageSetPixelf(gradHx, i - 1, j, 0, templ + 1, GRAY) ; 		
				ImageSetPixelf(gradHx, i + 1, j, 0, tempr - 1, GRAY) ; 
				/*
				double tempu = ImageGetPixelf(gradHy, i, j - 1, 0, GRAY);
				double tempd = ImageGetPixelf(gradHy, i, j + 1, 0, GRAY);
				ImageSetPixelf(gradHy, i, j - 1, 0, tempu + 1, GRAY) ; 		
				ImageSetPixelf(gradHy, i, j + 1, 0, tempd - 1, GRAY) ; */
		  }
	  }
  }
  //enhanceGradient(gradHx, gradHy, edgeimage);
  //smoothGradient(gradHx, gradHy, maskimage);
}


void imageGradient(Image *image, Image *gradHx, Image *gradHy, Image * edgeimage, Image * maskimage)
{
  double thred = 1.0;
  
  int i, j;
  int width = image->width, height = image->height;

  double gradX, gradY;
  
  for (i=1; i <= width; i++) {
	  for (j=1; j <= height; j++) {
		  int pos = j * width + i;
		  if (i == width)
			  gradX = 0;
		  else{
			  //use more advanced algorithm
			  //if(maskimage->data[pos] == 255 || edgeimage->data[pos] > 0){
			  ////if(edgeimage->data[pos] > 0){
			  //if(maskimage->data[pos] == 0 || edgeimage->data[pos] > 0){
			  /*if(maskimage->data[pos] > 0 && edgeimage->data[pos] == 0){
				   gradX = 0;
					gradY = 0;
			  }
			  else{
			  	  gradX = (double) (ImageGetPixel(image, i+1, j, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));
				  gradY = (double) (ImageGetPixel(image, i, j+1, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));
				}*/
			  
				  
			  /*if(edgeimage->data[pos] > 0){
			  //if(maskimage->data[pos] > 0){
				  gradX = (double) (ImageGetPixel(image, i+1, j, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));
				  gradY = (double) (ImageGetPixel(image, i, j+1, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));
				  if(edgeimage->data[pos] > 40) edgeimage->data[pos] = 40;
					gradX *= (edgeimage->data[pos])/40.0;
					gradY *= (edgeimage->data[pos])/40.0;
			  }
			  else */
			  if (((maskimage->data[pos] > 0) 
				  || (maskimage->data[(j-1)*width+i] > 0) //feris
				  || (maskimage->data[(j+1)*width+i] > 0)
				  || (maskimage->data[j*width+(i-1)] > 0)
				  || (maskimage->data[j*width+(i+1)] > 0)
				  || (maskimage->data[(j-1)*width+(i-1)] > 0)
				  || (maskimage->data[(j+1)*width+(i+1)] > 0)
				  || (maskimage->data[(j+1)*width+(i-1)] > 0)
				  || (maskimage->data[(j-1)*width+(i+1)] > 0))
				  
				  
				  && (j!=height) && (i!=width) && (j!=height-1) && (i!=width-1)) { // feris 
				  //attenuate
				  gradX = (double) (ImageGetPixel(image, i+1, j, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));
				  gradY = (double) (ImageGetPixel(image, i, j+1, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));

				  
				  // feris qualitative depth

				  //if (gradX > 0) gradX = 255; else if (gradX<0) gradX = -255;
				  //if (gradY > 0) gradY = 255; else if (gradY<0)gradY = -255;

				  //feris gradX = (double) (ImageGetPixel(image, i, j, 0, GRAY) - ImageGetPixel(image, i-1, j, 0, GRAY));
				  // ferisgradY = (double) (ImageGetPixel(image, i, j, 0, GRAY) - ImageGetPixel(image, i, j-1, 0, GRAY));
				  
					  
				   //gradX = (double) (ImageGetPixel(image, i+1, j, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));
				  //gradY = (double) (ImageGetPixel(image, i, j+1, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));

			  }
			  else{
				  gradX = 0;
				  gradY = 0;
			  }
				  	//gradX = 0.1;
					//double factor = edgeimage->data[pos]/255.0;
					//gradX = (double) (ImageGetPixel(image, i+1, j, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));
					//gradX *= factor;
			//	  }
			  //else gradX = 0;

			  //gradX = (double) (ImageGetPixel(image, i+1, j, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));
		  }
		  ImageSetPixelf(gradHx, i, j, 0, gradX, GRAY) ; 
		  ImageSetPixelf(gradHy, i, j, 0, gradY, GRAY) ; 
		  
	  }
  }
// debug feris
 /* Image * feris_image = (Image *) malloc(sizeof(Image)); 	
  feris_image->width = width;
  feris_image->height = height;
  BYTE *feris_data = new BYTE[width*height];
  ZeroMemory(feris_data,width*height);
  feris_image->data = feris_data;
  for (int i=0;i<width;i++)
	  for (int j=0;j<height;j++)
		  feris_data[j*width+i] = (BYTE)fabs(ImageGetPixelf(gradHx,i+1,j+1,0,GRAY));
  ImageWriteP2(feris_image,"d:\\Rogerio\\temp\\gradx.pgm");

  ZeroMemory(feris_data,width*height);
  for (int i=0;i<width;i++)
	  for (int j=0;j<height;j++)
		  feris_data[j*width+i] = (BYTE)fabs(ImageGetPixelf(gradHy,i+1,j+1,0,GRAY));
  ImageWriteP2(feris_image,"d:\\Rogerio\\temp\\grady.pgm");*/
  //end debug feris

  /*for (i=1; i <= width; i++) {
	  for (j=1; j <= height; j++) {
		  int pos = j * width + i;
		  if (j == height)
			  gradY = 0;
		  else{
			  if(edgeimage->data[pos] >= 0){
				  //double factor = edgeimage->data[pos]/255.0;
				  //gradY = 0.1;
				  gradY = (double) (ImageGetPixel(image, i, j+1, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));
				  //gradY *= factor;
			  }
			  else gradY = 0;
			  //gradY = (double) (ImageGetPixel(image, i, j+1, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));
		  }
		  ImageSetPixelf(gradHy, i, j, 0, gradY, GRAY) ; 
	  }
  }*/
  //enhanceGradient(gradHx, gradHy, edgeimage);
  //smoothGradient(gradHx, gradHy, maskimage);
  //enhanceGradient(gradHx, gradHy, edgeimage);
}



void maskGradient(Image *mask, Image *gradHx, Image *gradHy)
{

	int i,j;
	int n = mask->width-1;

	for (i=1; i <= n; i++) {
		for (j=1; j <= n; j++) {
			//if (ImageGetPixel(mask, i, j, 0, GRAY) == 0)
			//	u[i][j] = 0.0;
			//if ((ImageGetPixel(mask, i, j, 0, GRAY) == 0) && (fabs(u[i][j]) > 0.03))
			if (ImageGetPixel(mask, i, j, 0, GRAY) == 0) {
				ImageSetPixelf(gradHx, i, j, 0, 0.0, GRAY) ; //set value to zero
				ImageSetPixelf(gradHy, i, j, 0, 0.0, GRAY) ; 
			}
		}
	}


}

void imageGradientTodivG(Image *gradHx, Image *gradHy, Image *divG)
{
	
	int i,j;
	int width = gradHx->width, height = gradHx->height;
	double gradSumX, gradSumY;

	for (i=1; i <= width; i++) {
		for (j=1; j <= height; j++) {
			
			if (i == 1) gradSumX = 0;
			else gradSumX = (double) (ImageGetPixelf(gradHx, i, j, 0, GRAY) - ImageGetPixelf(gradHx, i-1, j, 0, GRAY));
			if (j == 1) gradSumY = 0;
			else gradSumY = (double) (ImageGetPixelf(gradHy, i, j, 0, GRAY) - ImageGetPixelf(gradHy, i, j-1, 0, GRAY));
			
			ImageSetPixelf(divG, i, j, 0, (gradSumX + gradSumY), GRAY) ; 
		}
	}
}


void imageToGradientToLaplace(Image *image, Image *gradHx, Image *gradHy, Image *divG)
{


  int i, j;
  int width = image->width, height = image->height;

  double gradX, gradY, gradSumX, gradSumY;

  for (i=1; i <= width; i++) {
	  for (j=1; j <= height; j++) {
		  
		  if (i == width)
			  gradX = 0;
		  else
			  gradX = (double) (ImageGetPixel(image, i+1, j, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));
		  
		  ImageSetPixelf(gradHx, i, j, 0, gradX, GRAY) ; 
	  }
  }

  for (i=1; i <= width; i++) {
	  for (j=1; j <= height; j++) {
		  
		  if (j == height)
			  gradY = 0;
		  else
			  gradY = (double) (ImageGetPixel(image, i, j+1, 0, GRAY) - ImageGetPixel(image, i, j, 0, GRAY));
		  
		  ImageSetPixelf(gradHy, i, j, 0, gradY, GRAY) ; 
	  }
  }
  
  for (i=1; i <= width; i++) {
	  for (j=1; j <= height; j++) {
		  
		  if (i == 1) gradSumX = 0;
		  else gradSumX = (double) (ImageGetPixelf(gradHx, i, j, 0, GRAY) - ImageGetPixelf(gradHx, i-1, j, 0, GRAY));
		  if (j == 1) gradSumY = 0;
		  else gradSumY = (double) (ImageGetPixelf(gradHy, i, j, 0, GRAY) - ImageGetPixelf(gradHy, i, j-1, 0, GRAY));
		  
		  ImageSetPixelf(divG, i, j, 0, (gradSumX + gradSumY), GRAY) ; 
	  }
  }
}