#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mat_util.h"
#include "ppm.h"
#include <assert.h>

// program gets passed ppm image filename  and blur amount
void usage();
void blurfunc( Var *Image, int blur);

int main(int argc, char *argv[]) {
  char imagename[100];
  unsigned char *tmpptr;
  int blur;
  Var myImage;

  if (argc != 3) {
	usage();
        exit(0);
  }
 
// first character of string only
//(subtract ascii value of zero) ...  blur = *argv[2] - '0';
  blur = atoi(argv[2]);
  sprintf(imagename, "%s", argv[1]);  

  fprintf(stderr,"%s: imagename = %s, blur = %d; ... ",argv[0],imagename,blur);

  // if blur is not odd
  if ((blur % 2) == 0) {
	usage();
	exit(0);
  }
  // load ppm file into Image
  tmpptr =  (unsigned char *)load_pnm_file(imagename, &myImage); 
  myImage.image = tmpptr;

  switch( myImage.image_type ) {
   case GREY_SCALE: fprintf(stderr,"%s is a pgm\n", imagename); break;
   case RGB24     : fprintf(stderr,"%s is a ppm\n", imagename); break;
   case GREY_PDM  : fprintf(stderr,"%s is a grayscale pdm\n", imagename); break;
   case RGB_PDM   : fprintf(stderr,"%s is a color pdm\n", imagename); break;
   case GREY_PLM  : fprintf(stderr,"%s is a greyscale plm\n", imagename); break;
   case RGB_PLM   : fprintf(stderr,"%s is a color plm\n", imagename); break;
   default        : fprintf(stderr,"blur couldn't determine type of input\n");
                      return -1;
  }

  // blur it 
  blurfunc(&myImage, blur );
 
  // write image back to disk
  save_pgm_file(&myImage, imagename);  

  return(1);
}

void blurfunc( Var *Image, int blur)
{
  Var *ANS, *ANS2;
  int m,n,k;
  int tmp;
  ANS = (Var *)calloc(1, sizeof(Var));
  ANS2 = (Var *)calloc(1, sizeof(Var));
  init_var(ANS, Image->name, Image->M, Image->N,
           IMAGE, GREY_SCALE);
  init_var(ANS2, Image->name, Image->M, Image->N,
           IMAGE, GREY_SCALE);

// blur in the across direction (easy even with small amount of cache):
  for( m=0 ; m<Image->M ; m++ )
  {
    for( n=0 ; n<Image->N ; n++ )
    {
      tmp = 0;
      if( n<blur/2 ) // left edge
      {
         for( k=-n; k<=blur/2; k++ )
         {
//printf("i=%d, j=%d, k=%d val=%d\n",i,j,k,Image->image[i*Image->N + j + k]);
           tmp+=Image->image[m*Image->N +n +k];
         }
         ANS->image[m*Image->N + n] = (unsigned char)(tmp/(n+1+blur/2));
//printf("div by %d\n", (unsigned char)(n+1+blur/2) );
      }
      else if( n>=Image->N-blur/2 )  // right edge
      {
         for( k=-blur/2 ; k<Image->N-n ; k++ )
         {
//printf("i=%d, n=%d, k=%d val=%d\n",m,n,k,Image->image[m*Image->N + n + k]);
           tmp+=Image->image[m*Image->N +n +k];
         }
         ANS->image[m*Image->N + n] = (unsigned char)(tmp/(Image->N-n+blur/2));
//printf("div by %d\n", (unsigned char)(Image->N-n+blur/2) );
      }
      else  
      {  
         for( k=-blur/2 ; k<=blur/2 ; k++ )
         {
           tmp += Image->image[m*Image->N + n + k];
//   printf("m=%d, n=%d, k=%d val=%d\n",m,n,k,Image->image[m*Image->N + n + k]);
         }
         ANS->image[m*Image->N + n] = (unsigned char)(tmp/blur);
  //    printf(" result = %d\n", ANS->image[m*Image->N + n]);
  //    assert(ANS->image[m*Image->N+n] < 256 );
         
      }
    }
  }

//blur in the down direction (same order, in case small number lines in cache):
  for( m=0 ; m<Image->M ; m++ ) {
    for( n=0 ; n<Image->N ; n++ ) {
      tmp = 0; // CLA (clear the accumulator)
      if( m<blur/2 ) // top edge
      {
         for( k=-m; k<=blur/2; k++ )
         {
           tmp+=ANS->image[(m+k)*Image->N +n];
         }
         ANS2->image[m*Image->N + n] = (unsigned char)(tmp/(m+1+blur/2));
      }
      else if( m>=Image->M-blur/2 )  // bottom edge
      {
         for( k=-blur/2 ; k<Image->M-m ; k++ )
         {
           tmp+=ANS->image[(k+m)*Image->N +n];
         }
         ANS2->image[m*Image->N + n] = (unsigned char)(tmp/(Image->M-m+blur/2));
      }
      else   // not at edges
      {
         tmp = 0;
         for( k=-blur/2 ; k<=blur/2 ; k++ )
         {
           tmp += ANS->image[(m+k)*Image->N + n];

//      printf("2: m=%d, n=%d, k=%d\n",m,n,k);

         }
         ANS2->image[m*Image->N + n] = (unsigned char)(tmp/blur);
      }
    }
   
  }   

  /* - - Copy answer to original image - - */
  copy_image(ANS2, Image);
  
  /* - - Free OLD image - - */
  free(ANS2->image);
  free(ANS->image);
  
}

void usage() {
  fprintf(stderr, "Usage:  blur [image] [blur amount]\n");
  fprintf(stderr, "[image] - the name of the ppm image to be blurred\n");
  fprintf(stderr, "[blur amount] - an odd valued blur radius\n");
}

