/*********************************************************************
 * EDGE DETECTOR XP, Slave program fo a parallel implementation of
 *                   Sobel, Prewitt & Laplace Edge Detection Operators
 * 
 * Levent Besik, levent@cs.earlham.edu
 * Hassan Halta, hassan@cs.earlham.edu
 **********************************************************************/ 

#include <stdio.h>
#include <pvm3.h>
#include <stdlib.h>
#include <math.h>
#include "pEdge.h"
#include "pixel_chunk.h"

/* Functions for edge detection operators */
int sobel(int chunk[3][3]) {
   int i = 0, j = 0, a = 0, b = 0, mid = 0;
   a = -1*chunk[j][i] + -2*chunk[j][i+1] + -1*chunk[j][i+2]
     + chunk[j+2][i] + 2*chunk[j+2][i+1] + chunk[j+2][i+2];
   b = -1*chunk[j][i] + chunk[j][i+2] + -2*chunk[j+1][i]
     + 2*chunk[j+1][i+2] + -1*chunk[j+2][i] + chunk[j+2][i+2];
   
   mid = sqrt( (a*a) + (b*b) );
   
   return mid;
}

int prewitt(int chunk[3][3]) {
   int i = 0, j = 0, a = 0, b = 0, mid = 0;
   a = -1*chunk[j][i] + -1*chunk[j][i+1] + -1*chunk[j][i+2]
     + chunk[j+2][i] + chunk[j+2][i+1] + chunk[j+2][i+2];
   b = -1*chunk[j][i] + chunk[j][i+2] + -1*chunk[j+1][i]
     + chunk[j+1][i+2] + -1*chunk[j+2][i] + chunk[j+2][i+2];
   
   mid = sqrt( (a*a) + (b*b) );
   
   return mid;
}

int laplace(int chunk[3][3]) {
   int i = 0, j = 0, mid = 0;
   mid = 4*chunk[j+1][i+1] - chunk[j+1][i]
     - chunk[j][i+1] - chunk[j+2][i+1]
     - chunk[j+1][i+2];
      
   return mid;
}

int main(void)
{     
   int mytid;           /* my task id */
   int master;          /* integer id of master program */
   int chunk[MAX_ARRAY_SIZE][MAX_ARRAY_SIZE];   /* Array that holds chunk from master */
   int result[MAX_ARRAY_SIZE][MAX_ARRAY_SIZE];  /* Array that holds transformed chunk */ 
   int chunk_3x3[3][3];                         /* Array for transforming the pixel in the middle */     
   int chunk_x_size = 0, chunk_y_size = 0, i = 0, j = 0, k = 0, l = 0;
   int chunk_begin = 0, msgtype, slave_die = 0;
   char edge_operator;
     
   /* Enroll in PVM, find who the master is around here */
   mytid = pvm_mytid();
   master = pvm_parent();
   
   /* While we're asked to do work */
   while(1){
      
      /* Receive the next interval to work on from the master */
      msgtype = 0;
      pvm_recv(-1, msgtype);
      pvm_upkint(&slave_die, 1, 1);
      
      /* If "slave_die" is 1, it means master asked us to exit. */        
      if ( slave_die ){
	 if(DEBUG) printf("SLAVE %d: Got die from master. Bye.\n", mytid);
	 fflush(NULL);
         break;
      }
      
      /* Else continue unpacking... */
      pvm_upkstr(&edge_operator);
      upk_pixel_chunk(chunk);  
      pvm_upkint(&chunk_begin, 1, 1);
      pvm_upkint(&chunk_x_size, 1, 1);
      pvm_upkint(&chunk_y_size, 1, 1);
      
      /* Do the calculations for the requested operator on the given chunk */
      for(j=1; j<=chunk_y_size; j++){     /* For all rows */
	 for(i=1; i<chunk_x_size-1; i++){  /* For all columns */
	    for(k=0; k<3; k++){       /* Find the 3x3 matrix surrounding each pixel */
	       for(l=0; l<3; l++){ 
		  
		  chunk_3x3[l][k] = chunk[j+l][i+k];
		  switch(edge_operator){
		     
		   case 's':
		     result[j][i] = sobel(chunk_3x3);
		     break;
		   case 'p':
		     result[j][i] = prewitt(chunk_3x3);
		     break;
		   case 'l':
		     result[j][i] = laplace(chunk_3x3);
		     break;
		   default:
		     /* If it's none of the above, we got a problem */
		     printf("SLAVE %d: Undefined operator type! Skipping.\n", mytid);
		     fflush(NULL);
		     break;
		  }
	       }
	    }
	 }
      }
      
      /* Send results back */
      msgtype = 5;
      pvm_initsend(PvmDataDefault);
      pvm_pkint(&mytid, 1, 1);
      pvm_pkint(&chunk_begin, 1, 1);
      pk_pixel_chunk(result);
      pvm_pkint(&chunk_y_size, 1, 1);
      pvm_send(master, msgtype);
      
   }
   
   /* Program Finished.  Exit PVM */
   pvm_exit();
   return(0);
}

