#include "bigloop.h"
extern int IDENT;
extern int PORT;
extern char *SERVER;
extern ullong FIRST, STEP, LAST;
extern int NBSTEP;
//struct in_addr ADDRSERV;
extern struct sockaddr_in CLIENT;

#define NBPROC 1024
#define NOT    0
#define RUN    1
#define RDY    2
int  cputime = 0, runtime;
int  actif   = 0;
int jobcount = 0;
int  proc    = 0;
ullong work  = 0;
time_t  initial;
extern ticket current;

typedef struct job_{
  ullong deb;
  ullong fin;
  int    run;
  struct job_ * next;
} job_t;

typedef struct proc_{
  int   pid;
  int   status;
  int   qte;  
  time_t date;
  ullong wkf;
  ullong run;
  struct  in_addr mac;
  job_t * job;
  float  perf;
} proc_t;

proc_t proctable[ NBPROC ];


void openproc( void )
{ 
  actif++;
  proctable[ proc].mac    = CLIENT.sin_addr;
  proctable[ proc].status = RDY;
  proctable[ proc].job    = NULL;
  proctable[ proc].wkf    = 0;
  proctable[ proc].run    = 0;
}

void initjob( ullong s, ullong f )
{
  int pid;
  job_t *aux;
  pid = current.pid;
  proctable[ pid ].qte++;
  proctable[ pid ].date   = time(NULL);
  proctable[ pid ].status = RUN;
  aux = ( job_t* ) malloc( sizeof(job_t) );
  aux->deb = s;
  aux->fin = f;
  aux->next = proctable[ pid ].job;
  proctable[ pid ].job = aux;
  jobcount++;
  printf("\njob started %s on %s", ctime(  & proctable[pid].date ), inet_ntoa( proctable[pid].mac) );
}

void savejob( )
{ 
  int run;
  int pid;
  pid   = current.pid;
  work += current.scr;
  proctable[pid].wkf += current.scr;
  run = difftime( time(NULL), proctable[pid].date );
  proctable[pid].run += run;
  proctable[pid].status = RDY;
  cputime += run;
  proctable[pid].job->run = run;
  printf("\njob took  %dsec on %s", run , inet_ntoa( proctable[pid].mac) );
}

void savevalue( void )
{ int pid; 
  ullong val;
  char name[64];
  FILE *dst;
  sprintf(name, "bigloop-%d.out", IDENT);
  dst = fopen( name, "a");  
  pid = current.pid;
  val = current.scr;
  fprintf(dst, "value=%Ld\n", val );
  fclose( dst );
}



void initproc( void )
{ int pid;
  for( pid = 0; pid < NBPROC; pid++){
    proctable[pid].job    = NULL;
    proctable[pid].status = NOT;
    proctable[pid].qte    = 0;
  }
  initial = time( NULL );
}

void report( void )
{ int pid, i, j;
  proc_t tmp;
  double perf;
  struct hostent * info;
  char name[64];
  FILE *dst;
  sprintf(name, "bigloop-%d.txt", IDENT);
  dst = fopen( name, "a");  
  
  for( pid = 0; pid < proc; pid++) {
    proctable[pid].perf = proctable[pid].wkf;
    if ( proctable[pid].run > 0 )
      proctable[pid].perf /= proctable[pid].run;
    else proctable[pid].perf = 0;
  }
  fprintf(dst, "\nrunning time  : %d", runtime );
  fprintf(dst, "\ncpu     time  : %d", cputime );  
  fprintf(dst, "\njob count     : %d", jobcount);   
  fprintf(dst, "\nprocessors    : %d",  proc);
  fprintf(dst, "\nwork factor   : %Ld", work);
  perf = work; perf /= cputime;
  fprintf(dst, " -> %E w/sec", perf);
  for( i = 0; i < proc; i++ )
    for( j = i+1; j < proc; j++ )
      if ( proctable[i].perf < proctable[j].perf ){
	tmp = proctable[i];
	proctable[i] = proctable[j];
	proctable[j] = tmp;
      }

  fprintf(dst, "\n#performance           host     job");
  for( pid = 0; pid < proc; pid++) 
    if ( proctable[pid].wkf != 0){
      fprintf(dst, "\n%8.3f %16s %8d", proctable[pid].perf, inet_ntoa( proctable[pid].mac ), proctable[pid].qte);
	info = gethostbyaddr( & proctable[pid].mac, 4, AF_INET);
	fprintf(dst, " %s", info->h_name );
    }
  fclose(dst);
}
//begin=prologue
//kwds= initbigloop, initserver
int main( int argc, char*argv[])
{
  double perf;
  ullong s, f;
  long long score = 0;
  if ( ! bigloopargs( argc, argv ) )
      exit(1);    
  initbigloop();
  initserver(); 
  bigloopparms();
  initproc();
  s = FIRST;
  //end
  //begin=boucle
  //kwds= READY, GET, VALUE, END
  while ( s < LAST || actif ){
    if ( getticketfromclient( &current ) ){
      pticket( current );  fflush(stdout);
      switch ( current.op ) {
        case READY :
	  openproc(); sendpid( proc ); proc++; break;
         case GET   :
	   if ( s < LAST ) {
	     f = s + STEP;  if ( f > LAST) f = LAST;
             initjob(s, f );
             sendjob(s, f, score );
             s += STEP;
           } else { sendstop( ); actif--; }    break; 
        case VALUE :
	  savevalue(  ); break;
        case END :  
          savejob(  );   break;
      }
    }
    printf("\nstep=%d/%d actifs : %d", jobcount, NBSTEP, actif);
  }     
  //end
  //begin=epilogue
  //kwds=getticketfromzombie
  runtime = difftime( time(NULL), initial );
  printf("\nrunning time  : %d",  runtime );
  printf("\ncpu     time  : %d",  cputime );  
  printf("\njob count     : %d",  jobcount);   
  printf("\nprocessus     : %d",  proc );
  printf("\nwork factor   : %Ld", work );
  perf = work; perf /= cputime;
  printf("\n%E operations per seconde", perf);
  report();
  printf("\nwaiting for zombies...");  
  fflush(stdout);  
  while ( getticketfromzombie( &current ) ) {
    pticket( current );
    sendstop( );
  }     
  printf("\neoj\n");
  stopserver();
  //end   
  return 0;
}
