#include "cryptolib.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "pvm3.h"



int isParent(char * searchString, char * filename,int NumberOfTasks);
int isChild(char * searchString);

main(int argc,char *argv[]){
  if (pvm_parent() < 0){
    if (argc  == 3){
      printf("%s %s\n",argv[1],argv[2]);
      isParent(argv[1],argv[2],-1);
      exit(0);
    }
     else if (argc  == 4){
       
      isParent(argv[1],argv[2],atoi(argv[3]));
      exit(0);
    }
    else {
      printf("Usage: pvm_crypt <search string> <file name> [number of tasks]\n");
      exit(-1);
    }
  }
  else 
    if (argc == 2)
      isChild(argv[1]);
  exit(0);
}

int isParent(char * searchString, char * filename, int NumberOfTasks){
  typedef struct node{
    char string[BUF_SIZE+1];
    struct node  *next;
  }Node;
  
  int TaskStatus[255];
  int TaskIDs[255];
  Node *head; 
  Node *tail; 
  Node *temp;
  
  FILE *infile = NULL;
  char string[BUF_SIZE+1];
  char bufString[BUF_SIZE+1];
  int NumberOfMachines = 0;
  int NumberOfChildren = 0;
  int bogus1;
  int counter = 0;
  int result = 0;
  int total = 0;
  int returnSum = 0;
  int BufferID = 0;
  int FreeTask = 0;
  int offset = 0;
  int amountRead = 0;
  int finished = 0;
  int completelyFinished =0;
  int last = 0;
  char * args[255];
  int count,countb = 0;
  char twirl = '|';
  int twirlcount = 0;
  struct pvmhostinfo *bogus2;


  pvm_config(&NumberOfMachines,&bogus1,&bogus2);
  if (!(NumberOfTasks <= 0))
    NumberOfMachines = NumberOfTasks;
  printf("The cluster consists of %d machine(s)\n",NumberOfMachines);
  args[0] = searchString;
  NumberOfChildren = pvm_spawn("pvm_crypt",args, 0, "",NumberOfMachines ,TaskIDs );
  if (NumberOfChildren != NumberOfMachines)
    exit(-1);
  //initalize TaskStatus array, 0 = idle, 1 = busy
  for (counter = 0 ; counter < NumberOfChildren; counter++){
    TaskStatus[counter] = 0;
  }
  //open the file for reading
  if( ( infile = fopen(filename,"r")) == NULL ){
    fprintf( stderr , "Unable to open input file \"%s\"\n" ,filename ) ;
    exit( -1) ;
}

  //init queue
  head = NULL;
  tail = NULL;
  temp = NULL;
  //just keep looping
  while(1){
    countb++;
    if (countb == 4)
      countb = 0;
    twirlcount = countb % 4;
    if (twirlcount == 0)
      twirl = '|';
    else if (twirlcount == 1)
      twirl = '/';
    else if (twirlcount == 2)
      twirl = '-';
    else twirl = '\\';
    printf("\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\b\b\b\b%c  queue size %d   \t found %d \n",twirl,count,total );
    //read in from file if we aren't finished, if we finish set boolean
    if (finished == 0){
      strcpy(string,bufString);
      amountRead = fread(string+offset,1,BUF_SIZE - offset,infile);
      string[offset+amountRead] = '\0' ;
      //calculate the offset for the next string..
      if( last_n_alphas( string , strlen(searchString) - 1 , &last ) >= 0 ){
	strcpy(bufString,string+last);
	offset = offset + amountRead - last;
      }
      else {
	offset = 0;
      }
      //--------------------------------------
      
      if (amountRead == 0){
	finished = 1;
	printf("\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\b\b\b\b                                       \n");
	printf("Finished reading file\n");
	fclose(infile);
      }  
    }
  
    //see if we have any free tasks, if so set freetask to number
    //else set freetask to -1
    for (counter = 0; counter < NumberOfChildren;counter++){
      if (TaskStatus[counter] == 0){
	FreeTask = counter;
	break;
      }
      FreeTask = -1;
    }
   
     // if we don't have any free tasks add string to queue
    if ((FreeTask < 0) && (finished == 0)){
      if (tail == NULL){
	tail = (Node *)malloc(sizeof(Node));
	count++;
	head = tail;
	strcpy(head->string,string);
      }
      else {
	temp = NULL;
	head->next =  (Node *)malloc(sizeof(Node));
	count++;
	head = head->next;
	head->next = NULL;
	strcpy(head->string,string);
      }
    }

    
    //see if we have some free tasks
    else if (FreeTask >= 0){
      if (tail != NULL){
	if (finished == 0){
	  head->next = (Node *)malloc(sizeof(Node));
	  count++;
	  head = head->next;
	  head->next = NULL;
	  strcpy(head->string,string);
	}
	strcpy(string,tail->string);
	if (tail->next == NULL){
	  count--;
	  tail = NULL;
	}
	else if (tail->next != NULL){           
	  temp = tail;
	  tail = tail->next;
	  free(temp);
	  count--;
	}
      }

 
      //make sure we have something to send
      if ( strlen(string) > 0){
	pvm_initsend(PvmDataDefault);
	pvm_pkint(&FreeTask,1,1);
	pvm_pkstr(string);
	pvm_send(TaskIDs[FreeTask],bogus1);
	TaskStatus[FreeTask] = 1;
      }
  }


    //check to see if we have any returns
    BufferID = pvm_nrecv(-1,-1);
    if (BufferID > 0){       
      pvm_upkint(&counter,1,1);
      pvm_upkint(&returnSum,1,1);
      total = total + returnSum;
      TaskStatus[counter] = 0;
    }

    //finish up any remaing strings
    if ((tail == NULL) && (finished == 1)){
      free(tail);
      printf("\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\b\b\b\b                                         \n");
      printf("Finishing up                                     queue size %d   \n",count);
      FreeTask = 0;
      for (counter = 0 ; counter < NumberOfChildren; counter++){
	if (TaskStatus[counter] == 1)
	  FreeTask++;	
      }
      for (counter = 0; counter < FreeTask; counter++){
	pvm_recv(-1,-1);
	pvm_upkint(&bogus1,1,1);
	pvm_upkint(&returnSum,1,1);
	total = total + returnSum;
      }
      //set result to kill child signal
      result = -1;
      //kill all the children
      for (counter = 0; counter < NumberOfChildren; counter++){
	pvm_initsend(PvmDataDefault);
	pvm_pkint(&result,1,1);
	pvm_send(TaskIDs[counter],bogus1);
      }
      printf("Number of Occurences of \"%s\" in %s is %d \n",searchString,filename,total);
      return 0;
    }
  }
}

int isChild(char * searchString){
  int found_count = 0;
  int thisID = 0;
  char string[BUF_SIZE +1];
  while (1){
    pvm_recv(-1,-1);
    pvm_upkint(&thisID,1,1);
    //if kill signal exit (int lesss than 0)
    if (thisID < 0)
      exit(0);
    pvm_upkstr(string);
    //count words
    cryptocount( string , searchString , &found_count ) ;
    pvm_initsend(PvmDataDefault);
    pvm_pkint(&thisID,1,1);
    pvm_pkint(&found_count,1,1);
    //set found count to zero
    found_count = 0;
    //send back result, and who it's from
    if (pvm_send(pvm_parent(),1) == PvmBadParam)
      exit (0);
  }
  return -1;
}

/* sample output */

/* pvm@deltabell:/home/pvm/src>./pvm_crypt entropy text1.dat 12 */
/* The cluster consists of 12 machine(s) */
/* Number of Occurences of "entropy" in text1.dat is 85  */
/* pvm@deltabell:/home/pvm/src> */
/* pvm@deltabell:/home/pvm/src>./pvm_crypt gin text1.dat 12 */
/* The cluster consists of 12 machine(s) */
/* Number of Occurences of "gin" in text1.dat is 322  */
/* The cluster consists of 12 machine(s) */
/* Number of Occurences of "fred" in text1.dat is 1 */


