// written by André Betz 
// http://www.andrebetz.de


#include <stdio.h>
#include <stdlib.h>
#include "pvm3.h"
#define  MSGLEN  200
#define  MANUELL 5

typedef struct Datas
{
  int      Start;
  int      Length;
  int      px;
  int      py;
  int      DimX;
  int      DimY;
  char     tp;
  double   X1Re;
  double   X2Re;
  double   Y1Im;
  double   Y2Im;
  double   CR;
  double   CI;
  unsigned long StopIter;
  double   Range;
} *pDatas,xDatas;

unsigned long Julia(pDatas pPos)
{
  unsigned long Iter = 0;
  double Re,Im;
  double Di = 0.0;
  double ZR = 0.0;
  double ZI = 0.0;
  double pR = pPos->X1Re + (pPos->X2Re - pPos->X1Re)/pPos->DimX * pPos->px;
  double pI = pPos->Y1Im + (pPos->Y2Im - pPos->Y1Im)/pPos->DimY * pPos->py;

  if(pPos->tp=='j')
  {
    ZR = pR;
    ZI = pI;
  }
  if(pPos->tp=='m')
  {
    pPos->CR = pR;
    pPos->CI = pI;
  }

  while((Iter<=pPos->StopIter)&&(Di<=(pPos->Range*pPos->Range)))
  {
    Re = ZR*ZR - ZI*ZI + pPos->CR;
    Im = 2*ZR*ZI + pPos->CI;
    Di = Re*Re + Im*Im;
    ZR = Re;
    ZI = Im;
    Iter++;
  }

  return Iter;
}

void child(int tid_my,int tid_parent)
{
  xDatas Pos;
  int count,z;
  long pixel;
  unsigned long *Buf;
  char *Msg;

  pvm_recv(tid_parent,1);     
  pvm_upkbyte((char*)&Pos,sizeof(struct Datas),1);

  Msg = (char*)malloc(MSGLEN);
  Buf = (unsigned long*)malloc(sizeof(unsigned long) * Pos.Length);
  
  sprintf(Msg,"t%x bearbeitet Pixel von %d bis %d\n",tid_my,Pos.Start,Pos.Start+Pos.Length);
  pvm_initsend(PvmDataDefault);
  pvm_pkstr(Msg);
  pvm_send(tid_parent,1);
 
  for(count=0;count<Pos.Length;count++)
  {
    pixel =  Pos.Start + count;
    Pos.px = pixel % Pos.DimX;
    Pos.py = pixel / Pos.DimX;
    z = Julia(&Pos);
    Buf[count] = z;
  }

  pvm_initsend(PvmDataDefault);
  pvm_pkbyte((char*)&Pos,sizeof(struct Datas),1);
  pvm_send(tid_parent,1);

  pvm_initsend(PvmDataDefault);
  pvm_pkbyte((char*)Buf,sizeof(unsigned long) * Pos.Length,1);
  pvm_send(tid_parent,1);

  free(Buf);
  free(Msg);
}

void Split(xDatas Pos,char* Pic,char* Datei)
{
  int  z,r,g,b;
  int  run;
  long PixPart;
  long PixRest;
  long pixel;
  long count;
  int  *tid_childs;
  unsigned long *Buf;
  char *Msg;
  struct pvmhostinfo *hostp;
  int narch;
  int parts;

#ifdef MANUELL
  parts = MANUELL;
#else
  info = pvm_config(&parts,&narch,&hostp);
#endif
    
  pixel   = Pos.DimX * Pos.DimY;
  PixPart = pixel / parts;
  PixRest = pixel % parts;

  tid_childs = (int*)malloc(sizeof(int)*parts);
  Buf        = (unsigned long*)malloc(sizeof(unsigned long) * (PixPart+PixRest));
  Msg        = (char*)malloc(MSGLEN);
  
  pvm_spawn(Datei,(char**)0,PvmTaskDefault,"",parts,tid_childs);

  printf("Rechnung ist in %d Teile aufgespalten\n",parts);

  for(run=0;run<parts;run++)
  {
#ifndef MANUELL
    printf("Starten von t%x auf %s\n",tid_childs[run],hostp[run].hi_name);
#endif
    
    Pos.Start   = PixPart * run;
    Pos.Length  = PixPart;
    if((pixel - Pos.Start)<2*PixPart) Pos.Length  = PixPart + PixRest;

    pvm_initsend(PvmDataDefault);
    pvm_pkbyte((char*)&Pos,sizeof(struct Datas),1);
    pvm_send(tid_childs[run],1);

    pvm_recv(tid_childs[run],1);
    pvm_upkstr(Msg);
    printf(Msg);
  }

  printf("Warte auf Rückmeldung\n");

  for(run=0;run<parts;run++)
  {
    pvm_recv(tid_childs[run],1);
    pvm_upkbyte((char*)&Pos,sizeof(struct Datas),1);
    
    pvm_recv(tid_childs[run],1);
    pvm_upkbyte((char*)Buf,sizeof(unsigned long) * Pos.Length,1);

    printf("Daten von t%x erhalten\n",tid_childs[run]);
    for(count=0;count<Pos.Length;count++)
    {
      pixel = Pos.Start + count;
      z = Buf[count]; 
      z = (unsigned long)((double)16777216 * (double)Pos.StopIter / (double)z);
      Pic[pixel*3]   = (z & 0x00FF0000) >> 16;
      Pic[pixel*3+1] = (z & 0x0000FF00) >> 8;
      Pic[pixel*3+2] = z & 0x000000FF;
    }
  }

  free(tid_childs);
  free(Buf);
  free(Msg);
}

int main(int argc,char **argv)
{
  FILE *InputFile;
  FILE *PicFile;
  char *Pic;
  xDatas Pos;
  int tid_my;
  int tid_parent;
  int pvm_err;
  int parts;

  tid_my     = pvm_mytid();
  tid_parent = pvm_parent();

  if(tid_parent == PvmNoParent)
  {
    if(argc!=3)
    {
      printf("Type: m\n");
      printf("DimX: 400\n");
      printf("DimY: 400\n");
      printf("MinRe: -2\n");
      printf("MaxRe: 1\n");
      printf("MinIm: -1\n");
      printf("MaxIm: 1\n");
      printf("CR: 0.5\n");
      printf("CI: 0.5\n");
      printf("Tiefe: 200\n");
      pvm_exit();
      exit(1);
    }
  
    InputFile = fopen(argv[1],"r");
    fscanf(InputFile,"Type: %c\n",  &(Pos.tp));  
    fscanf(InputFile,"DimX: %d\n",  &(Pos.DimX));
    fscanf(InputFile,"DimY: %d\n",  &(Pos.DimY));
    fscanf(InputFile,"MinRe: %lf\n",&(Pos.X1Re));
    fscanf(InputFile,"MaxRe: %lf\n",&(Pos.X2Re));
    fscanf(InputFile,"MinIm: %lf\n",&(Pos.Y1Im));
    fscanf(InputFile,"MaxIm: %lf\n",&(Pos.Y2Im));
    fscanf(InputFile,"CR: %lf\n",   &(Pos.CR));
    fscanf(InputFile,"CI: %lf\n",   &(Pos.CI));
    fscanf(InputFile,"Tiefe: %d\n", &(Pos.StopIter));
    Pos.Range = 2;
    fclose(InputFile);

    Pic = (char*)malloc(Pos.DimX*Pos.DimY*3);  
    Split(Pos,Pic,argv[0]);

    PicFile = fopen(argv[2],"w");
    fprintf(PicFile,"P6\n");
    fprintf(PicFile,"%d %d\n",Pos.DimX,Pos.DimY);
    fprintf(PicFile,"%d\n",255);
    fwrite(Pic,Pos.DimX*Pos.DimY*3,1,PicFile);
    fclose(PicFile);
    free(Pic);
  }
  else
  {
    child(tid_my,tid_parent);
  }

  pvm_exit();
}

