/*******************************************************************
 ******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>    
#include <math.h>    
#include <pvm3.h>  

#include "pEdge.h"
#include "pixel_chunk.h"

int main(int argc, char **argv) {
   int image_data[MAX_ARRAY_SIZE][MAX_ARRAY_SIZE];             /* data array */
   int result[MAX_ARRAY_SIZE][MAX_ARRAY_SIZE];             /* data array */
   char image_header[HEADER_PARAMS][MAX];   /* Image type, x_size, y size, max value */
   int chunk[3][3];
   int  counter=0, i=0, j=0, k=0, l=0;
   int image_x_size=0, image_y_size=0;				 
   char char_value[MAX];
   char fn_input[MAX];                /* array used for path name */
   char fn_output_sobel[MAX];                /* array used for path name */
   char fn_output_prewitt[MAX];                /* array used for path name */
   char fn_output_laplace[MAX];                /* array used for path name */
   
   FILE *fp_input;                    /* pointer to the input file */
   FILE *fp_output_sobel;                    /* pointer to the input file */
   FILE *fp_output_prewitt;                    /* pointer to the input file */
   FILE *fp_output_laplace;                    /* pointer to the input file */
   int value=0;  
   
   int mytid;                  /* my task id */
   int tids[MAX_PROC];         /* slave task ids */
   int nproc = MAX_PROC;       /* number of processes */
   struct timeval tv1, tv2;    /* for timing */
   int time_usec;              /* accum. time */
   struct pvmhostinfo *hostp;  /* Struct containing the detailed info on PVM hosts */
   int nhost = 0;              /* number of hosts added to PVM */
   int slave_die = 0;          /* Flag that is raised when it's time for the slave to die */
   int x_coor=0, y_coor=0, killed=0, numt = 0, who=0, msgtype, pixel_value=0;
   char edge_operator;
   
   /* Check command line arguments */ 
   if (argc!=2){
      printf("-> Invalid arguments. Usage: pEdge <input file name>\n\n");
      exit(1);
   }
   else
     strcpy(fn_input,argv[1]); 
   
   printf("\n-> IMAGE EDGE DETECTOR Using Sobel,Prewitt & Laplace Operators\n");
   fflush(NULL);
      
   /* Get Proper Path For Output File */
   strcpy(fn_output_sobel, getenv("HOME"));
   strcat(fn_output_sobel, output_file_prefix); 
   strcat(fn_output_sobel, "sobel.pnm\0"); 
   
   strcpy(fn_output_prewitt, getenv("HOME"));
   strcat(fn_output_prewitt, output_file_prefix); 
   strcat(fn_output_prewitt, "prewitt.pnm\0"); 
   
   strcpy(fn_output_laplace, getenv("HOME"));
   strcat(fn_output_laplace, output_file_prefix); 
   strcat(fn_output_laplace, "laplace.pnm\0"); 
   
   
   /* Open Input and Output File */
   if ((fp_input = fopen(fn_input,"r")) == NULL) {
     printf("Can't open the input file: %s\n\n", fn_input);
     exit(1);
   }
   
   if ((fp_output_sobel = fopen(fn_output_sobel,"w")) == NULL) {
     printf("Can't open the output file: %s\n\n", fn_output_sobel);
      exit(1);
   }
   if ((fp_output_prewitt = fopen(fn_output_prewitt,"w")) == NULL) {
      printf("Can't open the output file: %s\n\n", fn_output_prewitt);
      exit(1);
   }
   if ((fp_output_laplace = fopen(fn_output_laplace,"w")) == NULL) {
      printf("Can't open the output file: %s\n\n", fn_output_laplace);
      exit(1);
   }
   
   
   /* Read the image header */  
   for(i=0; i<2; i++){
      
      fgets(char_value, 128, fp_input);
      strcpy(image_header[i], char_value);        
      }
   
   for(i=2; i<HEADER_PARAMS; i++){
      
      fscanf(fp_input, "%s", char_value);
      strcpy(image_header[i], char_value);        
      }

   /* Check image type - has to be grayscale = P2 and 255*/
   if (strcmp(image_header[0], "P2\n")!=0 || atoi(image_header[4])!=255) {
      printf("Input image is not grayscale! (It is instead %s with %s colors)\n\n", image_header[0], image_header[4]);
      exit(1);
   }
   else{
      printf("-> Input image is grayscale. Type %s\n", image_header[0]);
     fflush(NULL);
   }

      
   /* Retrieve and check the image sizes */
   image_x_size = atoi(image_header[2]);
   image_y_size = atoi(image_header[3]);
   
   if (image_x_size > MAX_ARRAY_SIZE || image_y_size > MAX_ARRAY_SIZE) {
      printf("Input image is too big! Reduce resolution lower than %d.\n\n", MAX_ARRAY_SIZE);
      exit(1);
   }
   else{
      printf("-> Input file's resolution is %d x %d.\n", image_x_size, image_y_size);				
      fflush(NULL);
   }
   
   /* Print image comment */
   printf("-> Image comment: %s \n", image_header[1]);				
   fflush(NULL);
   
   /* Enroll In PVM */
   mytid = pvm_mytid();
   
   /* Call pvm_config to see how many hosts we have. */
   if(pvm_config(&nhost, 0, &hostp ) < 0){
      printf("* Trouble getting PVM configuration. Aborting.\n");
      exit(1);
   }
   
   /* Calculate the number of slaves we'll need.
    *  Previous experiments show that 3 processes per host is optimal.*/
   nproc = nhost * 3;
   
   /* Make sure this is not more than the max_proc since otherwise
    * we'll run over our tids[] array */
   if(nproc > MAX_PROC) nproc = MAX_PROC;
   
   /* Start Slave Tasks */
   numt = pvm_spawn(SLAVENAME, (char**)0, 0, "", nproc, tids);
   
   if (numt < nproc) {
      printf("* Trouble spawning slaves. Aborting. Error codes are: \n");
      for (i=numt; i<nproc; i++)
	printf("  TID %d %d\n", i, tids[i]);
      for (i=0; i<numt; i++)
	pvm_kill(tids[i]);
      pvm_exit();
      exit(1);
   }
      
   /* Write the image header to all 3 output files */  
   printf("* Writing the image header info to output files.\n");
   for(i=0; i<HEADER_PARAMS; i++){
      fprintf(fp_output_sobel, "%s\n", image_header[i]);
      fprintf(fp_output_prewitt, "%s\n", image_header[i]);
      fprintf(fp_output_laplace, "%s\n", image_header[i]);
   }
   
   
   /* Read the image data */  
   for(j=0; j<image_y_size; j++){
      for(i=0; i<image_x_size; i++){
	 
	 if (fscanf (fp_input, "%d", &value) == EOF) 
	   printf("\n WARNING: End of file is reached before the array is filled!\n");  
	 
	 if(DEBUG==2) printf("Read %d for (%d, %d) in image_data matrix\n", value, j, i); 
	 
	 image_data[j][i] = value;
      }
   }
   
   printf("* Reading the contents of the file is completed.\n");
   fflush(NULL);
   
   
   /* SOBEL */
   printf("\n* Using Sobel to transform pixel:\n");
   fflush(NULL);
   edge_operator='s';
      
   for(j=1; j<image_y_size-1; j++){
      
         for(i=1; i<image_x_size-1; i++){
	 for(k=0; k<3; k++){
	    for(l=0; l<3; l++){
	       
	       /* Wait for the result from the slave. When contacting the master
		*  for the first time, slaves send pixel_value = -1 */
	       msgtype = 5;
	       pvm_recv(-1, msgtype);
	       pvm_upkint(&who, 1, 1);
	       pvm_upkint(&pixel_value, 1, 1);
	       pvm_upkint(&x_coor, 1, 1);
	       pvm_upkint(&y_coor, 1, 1);
	        
	       /* Record the result from the slave unless this is the first time they are contacting us*/
	       if(pixel_value != -1) result[y_coor][x_coor]=pixel_value;;
	       
	       /* Determine the new chunk to be sent to the slave and send it */
	       chunk[l][k] = image_data[j+l][i+k];
	       
	       pvm_initsend(PvmDataDefault);
	       pvm_pkint(&slave_die, 1, 1);
	       pk_pixel_chunk(chunk);
	       pvm_pkstr(&edge_operator);
	       pvm_pkint(&i, 1, 1);
	       pvm_pkint(&j, 1, 1);
	       pvm_send(who, 0);
	       
	       if(DEBUG){ 
		  printf("(%4d, %4d)\n", j, i);
		  fflush(NULL);
	       }
	    }
	 }
      }
   }

   /* When all of the pixels are covered, we start sending -exit- commands to
    * each of the slaves. We do this by raising "slave_die" flag in
    * our messages to the slaves. Before we kill them though, we need to
    *  collect the result of the last interval they were assigned */
   
   killed=0;
   slave_die=1;
   
   while(killed<nproc){
      
      /* Collect the results for the last interval */
      msgtype = 5;
      pvm_recv(-1, msgtype);
      pvm_upkint(&who, 1, 1);
      pvm_upkint(&pixel_value, 1, 1);
      pvm_upkint(&x_coor, 1, 1);
      pvm_upkint(&y_coor, 1, 1);
      
      result[y_coor][x_coor]=pixel_value;;
      
      i=0;
      j=0;
      
      /* Sending "Thanks for working for us. Goodbye" to slaves */
      pvm_initsend(PvmDataDefault);
      pvm_pkint(&slave_die, 1, 1);
      pk_pixel_chunk(chunk); 
      pvm_pkstr(&edge_operator);
      pvm_pkint(&i, 1, 1);
      pvm_pkint(&j, 1, 1);
      pvm_send(who, 0);
      
      killed++;
      
   }
   
   /* We're done when all of the results are collected, and all of the slaves are
    * killed. */
    
   
   printf("\n* Writing the image data to output file %s\n", fn_output_sobel);
   fflush(NULL);
   for(j=0; j<image_y_size; j++){
      for(i=0; i<image_x_size; i++){
	 
	 if(j==0 || j==image_y_size-1 || i==0 || i==image_x_size-1){
	    fprintf(fp_output_sobel, "%d \n", image_data[j][i]);
	 }
	 else{
	    fprintf(fp_output_sobel, "%d \n", result[j][i]);
	 }
      }
   }
   
   
   
   
    /*
   printf("\n* Using Prewitt to transform pixel:\n");
   
   for(j=1; j<image_y_size-1; j++){
      for(i=1; i<image_x_size-1; i++){
	 for(k=0; k<3; k++){
	    for(l=0; l<3; l++){
	       
	       chunk[l][k] = image_data[j+l][i+k];
	       result[j][i]=prewitt(chunk);
	       if(DEBUG) printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b(%4d, %4d)", j, i);
	       
	    }
	 }
      }
   }
   
   printf("\n* Writing the image data to output file %s\n", fn_output_prewitt);
   for(j=0; j<image_y_size; j++){
      for(i=0; i<image_x_size; i++){
	 
	 if(j==0 || j==image_y_size-1 || i==0 || i==image_x_size-1){
	    fprintf(fp_output_prewitt, "%d \n", image_data[j][i]);
	 }
	 else{
	    fprintf(fp_output_prewitt, "%d \n", result[j][i]);
	 }
      }
   }
   
   

   printf("\n* Using Laplace to transform pixel:\n");
   
   for(j=1; j<image_y_size-1; j++){
      for(i=1; i<image_x_size-1; i++){
	 for(k=0; k<3; k++){
	    for(l=0; l<3; l++){
	       
	       chunk[l][k] = image_data[j+l][i+k];
	       result[j][i]=laplace(chunk);
	       if(DEBUG) printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b(%4d, %4d)", j, i);
	       
	    }
	 }
      }
   }

   
   printf("\n* Writing the image data to output file %s\n", fn_output_laplace);
   for(j=0; j<image_y_size; j++){
      for(i=0; i<image_x_size; i++){
	 
	 if(j==0 || j==image_y_size-1 || i==0 || i==image_x_size-1){
	    fprintf(fp_output_laplace, "%d \n", image_data[j][i]);
	 }
	 else{
	    fprintf(fp_output_laplace, "%d \n", result[j][i]);
	 }
      }
   }
   
*/      
   printf("* Finished. Finalizing the files and exiting.\n\n");


  fclose(fp_input);
  fclose(fp_output_sobel);
  fclose(fp_output_prewitt);
  fclose(fp_output_laplace);

  return(0);
  }

