/////////////////////////////////////////////////////////////////////////
// (C) 2000 by Christian Schulte and Joerg Wolf
//
// This code is licenced under the GNU Public License.
// It can be redistributed and altered under the Terms of the GPL.
/////////////////////////////////////////////////////////////////////////

#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>


// ------------- some definitions for the laser routine !

#define SRCH_F_P 45  // the part to search for the laser (in %) 
#define SRCH_T_P 55

#define TRUE 1
#define FALSE 0

#define OFILEN_XSIZE 160  // for normal output file-size of 172x129
#define OFILEN_YSIZE 100

#define OFILE4_XSIZE 640  // for 4x SIZE output files
#define OFILE4_YSIZE 480

#define HELP "\n\
   -q BE QUIET !!\n\
   -l \"<first.pgm second.pgm outfile.pgm>\"   find the laser\n\
   -c \"<inputfile.pgm outfile.pgm>\"          generate contrast from file\n\
   -n do not create output files ... \n\
   -S run in HS-Mode (switches on all optimizations)\n\
   -4 work with PICTURE SIZE x 4  (640x480) \n\
   -m \"<orig.pgm INname_without_NR OUTname_without_NR first last\" \n\
      read in multiple files to compare with the first \n\
       x_orig.pgm x1.pgm x2.pgm x3.pgm x4.pgm\n\
      THEN: -m \"x_orig.pgm x 1 4\"\n\
\n\n"

 unsigned char DBG_MOD=0x01;  // like debug-level  ... 1=normal output
 unsigned int OFILE_XSIZE=OFILEN_XSIZE,OFILE_YSIZE=OFILEN_YSIZE;
 unsigned char fname1[100],fname2[100],oname1[100],CREATE_OFILE=TRUE,HS=FALSE;
FILE *odat;
 unsigned int ys,xs,xsize=0,ysize=0,res,extra,extra2,contr,contr_bit=0,contr_pixel,vec_count;

 int im_data[650][490][3],**vec_data; 
 #define IM_DATA_SIZEX 650
 #define IM_DATA_SIZEY 490
 
 int x_results[100];
 
 unsigned int contr_page[350][350];
 unsigned int list_x[10000],list_y[10000];
 unsigned int Brightness,SpektrNr=0;
 unsigned int dummy,dummy2;
 unsigned char RUN_MODE=0;

 float P1_x, P1_y, P2_x, P2_y;  // for bres_line

void open_pic(char *fnam,int layer){
  register unsigned int xcnt,ycnt;
  FILE *ffd;
  char f_type[10],tmp;
  unsigned int t_xsize=0,t_ysize=0,PGM_STYLE=0;

  if ( (ffd=fopen(fnam,"r")) == NULL) { perror(fnam); exit(1); }

  if (DBG_MOD&0x01) if (DBG_MOD&0x01) fprintf(stderr,"reading %s ",fnam);
  fscanf(ffd,"%s",(char*) &f_type);
  f_type[0]=' ';
  sscanf(f_type,"%d",&PGM_STYLE);
  if (DBG_MOD&0x01) fprintf(stderr,"(P%d)   \n",PGM_STYLE);

  if ( (PGM_STYLE!=5) && (PGM_STYLE!=2) )
  { fprintf(stderr,"Only supporting P5 and P2 until now !!! ... sorry \n\n"); exit(1); }
  
CUT_COMMENT_START:
  tmp=fgetc(ffd);
  if (tmp=='#')
  {
   while (fgetc(ffd)!=0x0a)  
   {}
   goto CUT_COMMENT_START;
  }

  if ( (tmp==' ') || (tmp==0x0a) )
  goto CUT_COMMENT_START;
  else { fseek(ffd,-1,1); }  // if not we have read in a normal character !
// --------------- end of comment-cutting-routine 


  fscanf(ffd,"%d",&t_xsize); 
  fscanf(ffd,"%d",&t_ysize);
  
  if (t_xsize==0) { fprintf(stderr," XSIZE=0 .. ERROR reading file \n"); return; }
  if (t_ysize==0) { fprintf(stderr," YSIZE=0 .. ERROR reading file \n"); return; }
  
  if (t_xsize>IM_DATA_SIZEX) { fprintf(stderr," XSIZE GREATER THAN %d \n",IM_DATA_SIZEX); return; }
  if (t_ysize>IM_DATA_SIZEY) { fprintf(stderr," YSIZE GREATER THAN %d \n",IM_DATA_SIZEY); return; }
  
  if (xsize!=0) if (t_xsize!=xsize) { fprintf(stderr,"FILES HAVE DIFFERENT SIZE %d %d \n",xsize,t_xsize); return; }
  if (ysize!=0) if (t_ysize!=ysize) { fprintf(stderr,"FILES HAVE DIFFERENT SIZE %d %d \n",ysize,t_ysize); return; }
  
  xsize=t_xsize;
  ysize=t_ysize;
  
  fscanf(ffd,"%d",&res);
  if (DBG_MOD&0x01) fprintf(stderr,"  X : %d  Y : %d Res : %d",xsize,ysize,res);
 
  while(fgetc(ffd)!=0x0a)
  {}

  dummy=0;
  if (PGM_STYLE==5)  // FOR THE BINARY FORMAT   >>P5<<
  for (ycnt=0;ycnt<ysize;ycnt++)
  {
   dummy++;if (dummy&0x08) { if (DBG_MOD&0x01) fprintf(stderr,"."); dummy=0; }
   for (xcnt=0;xcnt<xsize;xcnt++)
   {
    im_data[xcnt][ycnt][layer]=fgetc(ffd);
   }
  }

  dummy=0;
  if (PGM_STYLE==2)  // FOR THE ASCII FORMAT   >>P2<<
  for (ycnt=0;ycnt<ysize;ycnt++)
  {
   dummy++;if (dummy&0x08) { if (DBG_MOD&0x01) fprintf(stderr,"."); dummy=0; }
   for (xcnt=0;xcnt<xsize;xcnt++)
   {
    fscanf(ffd,"%d",&im_data[xcnt][ycnt][layer]);
   }
  }

 if (DBG_MOD&0x01) fprintf(stderr,"\n");
 
 fclose (ffd);
} 


void scan_pic(void){ //6 is normal
register unsigned int xcnt,ycnt;
    contr_pixel=3; contr=30;
    for (ycnt=0;ycnt<ysize;ycnt++){
      for (xcnt=0;xcnt<xsize;xcnt++){
      if((im_data[xcnt][ycnt]>254)&&(im_data[xcnt][ycnt]<256)){
        contr_bit=0;
     
        if(im_data[xcnt+1][ycnt]+contr <= im_data[xcnt][ycnt]){contr_bit=1;}
        if(im_data[xcnt][ycnt+1]+contr <= im_data[xcnt][ycnt]){contr_bit=1;}
        if(im_data[xcnt-1][ycnt]+contr <= im_data[xcnt][ycnt]){contr_bit=1;}
        if(im_data[xcnt][ycnt-1]+contr <= im_data[xcnt][ycnt]){contr_bit=1;}
      }
      if(contr_bit!=0){contr_bit=0; 
         contr_page[xcnt][ycnt]=256+150;
         list_x[contr_pixel]=xcnt;
         list_y[contr_pixel]=ycnt;
         contr_pixel++;
      }
    }
  }  
}



int open_part_pic(char *fnam,int layer)  // read only a part of a file
{
  register unsigned int ycnt,xcnt;
  FILE *ffd;
  char f_type[10],tmp;
  int t_xsize=0,t_ysize=0;
  unsigned int fy=0,ty=0,PGM_STYLE;

  if ( (ffd=fopen(fnam,"r")) == NULL) { perror(fnam); return(-1); }

  fscanf(ffd,"%s",(char*) &f_type);
  f_type[0]=' ';
  sscanf(f_type,"%d",&PGM_STYLE);
  if (PGM_STYLE!=5)
  { fprintf(stderr,"Only supporting P5 until now !!! ... sorry \n\n"); return(-2); }

CUT_COMMENT_START:
  tmp=fgetc(ffd);
  if (tmp=='#')
  {
   while (fgetc(ffd)!=0x0a)  
   {}
   goto CUT_COMMENT_START;
  }

  if ( (tmp==' ') || (tmp==0x0a) )
  goto CUT_COMMENT_START;
  else { fseek(ffd,-1,1); }  // if not we have read in a normal character !
// --------------- end of comment-cutting-routine 

  fscanf(ffd,"%d",&t_xsize); 
  fscanf(ffd,"%d",&t_ysize);
  
  if (t_xsize==0) { fprintf(stderr," XSIZE=0 .. ERROR reading file \n"); return(-2); }
  if (t_ysize==0) { fprintf(stderr," YSIZE=0 .. ERROR reading file \n"); return(-2); }
  
  if (t_xsize>IM_DATA_SIZEX) { fprintf(stderr," XSIZE GREATER THAN %d \n",IM_DATA_SIZEX); return(-2); }
  if (t_ysize>IM_DATA_SIZEY) { fprintf(stderr," YSIZE GREATER THAN %d \n",IM_DATA_SIZEY); return(-2); }
  
  if (xsize!=0) if (t_xsize!=xsize) { fprintf(stderr,"FILES HAVE DIFFERENT SIZE %d %d \n",xsize,t_xsize); return(-2); }
  if (ysize!=0) if (t_ysize!=ysize) { fprintf(stderr,"FILES HAVE DIFFERENT SIZE %d %d \n",ysize,t_ysize); return(-2); }
  
  xsize=t_xsize;
  ysize=t_ysize;

  fy=(ysize*SRCH_F_P)/100;
  ty=(ysize*SRCH_T_P)/100;

  fscanf(ffd,"%d",&res);
 
  while(fgetc(ffd)!=0x0a)
  {}

  fseek(ffd,(xsize*fy),1);   // seek to the given position in file

  if (DBG_MOD&0x01)
   fprintf(stderr,"reading parts of %s(P%d) size(%dx%d) lines(%d-%d)  \n",
   	fnam,PGM_STYLE,xsize,ysize,fy,ty);

  for (ycnt=fy;ycnt<ty;ycnt++)
   for (xcnt=0;xcnt<xsize;xcnt++)
    im_data[xcnt][ycnt][layer]=fgetc(ffd);

 fclose (ffd);
 return(0);
}




void find_laser(int num)
{
 register signed int max=-255,min=255,tmp;
 register int xc,yc;
 float b_scale=1.0;
 unsigned int avg_bright=0,maxX=0,maxY=0;
 unsigned int SRCH_F=0,SRCH_T=0;

 SRCH_F=(ysize*SRCH_F_P)/100;
 SRCH_T=(ysize*SRCH_T_P)/100;

 if (DBG_MOD&0x01) fprintf(stderr,"searching from:%d to:%d   ",SRCH_F,SRCH_T);
 
 for (yc=SRCH_F;yc<SRCH_T;yc++)
  for (xc=0;xc<xsize;xc++)
  {
   tmp=im_data[xc][yc][1]-im_data[xc][yc][0];
   if (max<tmp) { max=tmp; maxX=xc; maxY=yc; }
   if (min>tmp) min=tmp;
   im_data[xc][yc][2]=tmp;
  } 
  
  tmp+=im_data[maxX][maxY][1];  
  tmp+=im_data[maxX][maxY+1][1];  
  tmp+=im_data[maxX+1][maxY][1];  
  tmp+=im_data[maxX+1][maxY+1][1];  
  tmp/=4; 
  
  if (tmp>170)
  {
   for (xc=1;xc<20;xc++)
    if ( (im_data[maxX+xc][maxY][1]*1.1) < tmp ){yc=xc; xc=99;}  // 100 if good before
   if (xc==100)
    for (xc=1;xc<20;xc++)
     if ( (im_data[maxX-xc][maxY][1]*1.1) < tmp ) {yc+=xc; xc=99; }
  }
  else xc=0;
  
  if (xc==100){
   printf ("(%u) ",maxX);
   if (DBG_MOD&0x01) fprintf(stderr,"(%u) ",maxX);
   im_data[maxX][maxY][2]=500;
   x_results[num]=maxX;
  } else{
   x_results[num]=-1;
   if (DBG_MOD&0x01) fprintf(stderr,"I{%u}%u ",maxX,im_data[maxX][maxY][1]);
  }

if (HS==TRUE) return;  // simply stop this when running in HS-Mode

 for (yc=SRCH_F;yc<SRCH_T;yc++)   // removing negative offset if existing
  for (xc=0;xc<xsize;xc++)
   im_data[xc][yc][2]-=min;
 
 for (yc=SRCH_F;yc<SRCH_T;yc++)   // generating average of brightness
  for (xc=0;xc<xsize;xc++)
   avg_bright+=im_data[xc][yc][2];
 
 max-=min;  // removing brightness-offset if existent
 min=0;
 
 avg_bright=avg_bright/(xsize*(SRCH_T-SRCH_F));
 if (DBG_MOD&0x01) fprintf(stderr,"AVG:%d \n",avg_bright);

 if (avg_bright>10) fprintf(stderr," VERY HIGH AVG ... FILE OK ?? \n"); 
 if (max==0) { fprintf(stderr,"MAX=0 !!!  (aborting this picture)\n"); return;}

 b_scale=256.0/(float)max;
 b_scale*=0.75;
 
 if (DBG_MOD&0x01) fprintf(stderr,"scaling brightness x%f",b_scale);
 for (yc=SRCH_F;yc<SRCH_T;yc++)
  for (xc=0;xc<xsize;xc++)
   if (im_data[xc][yc][2]<256) im_data[xc][yc][2]*=b_scale;

  SRCH_F--;
  SRCH_T++;

  for (yc=0;yc<SRCH_F;yc++)
   for (xc=0;xc<xsize;xc++)
    im_data[xc][yc][2]=im_data[xc][yc][0];
  for (yc=SRCH_T;yc<ysize;yc++)
   for (xc=0;xc<xsize;xc++)
    im_data[xc][yc][2]=im_data[xc][yc][0];

}


void write_contr_pic(char *fnam,int layer){
  register unsigned int xcnt,ycnt;
  if ((odat=fopen(fnam,"w+"))==NULL) { perror("fopen"); exit(-1);}
  fprintf(odat,"P3\n%d %d\n255\n",xsize,ysize);
  extra2=0;
  for (ycnt=0;ycnt<ysize;ycnt++){
    for (xcnt=0;xcnt<xsize;xcnt++){
       if(contr_page[xcnt][ycnt]>255){extra=255;extra2=255;}else{extra=contr_page[xcnt][ycnt];extra2=0;}
       fprintf(odat,"%d ",extra2);   //  fprintf(odat,"%d ",extra2);     fprintf(odat,"%d ",extra2);
       fprintf(odat,"%d ",contr_page[xcnt][ycnt]-extra2);
       fprintf(odat,"%d ",contr_page[xcnt][ycnt]-extra2);
    }
  }
  fclose(odat);
}


void write_layer_to_file(char *fnam,int layer)
{
  register unsigned xcnt,ycnt;
  unsigned int xf=0,xt=0,yf=0,yt=0;
  signed int xdiff,ydiff;

  xdiff=xsize-OFILE_XSIZE;   // calculate the window to cut out of the data-field 
  ydiff=ysize-OFILE_YSIZE;
  
  xf=xdiff/2;
  xt=xsize-(xdiff-(xdiff/2));
  yf=ydiff/2;
  yt=ysize-(ydiff-(ydiff/2));

  if (DBG_MOD&0x01) fprintf(stderr,"writing output layer Nr.%d to FILE:%s (%dx%d)\n",layer,fnam,OFILE_XSIZE,OFILE_YSIZE);
  if (DBG_MOD&0x01) fprintf(stderr,"cutting out upper-left(%d/%d)  to  lower-right(%d/%d) \n",xf,yf,xt,yt);

  dummy=0;  
  if ((odat=fopen(fnam,"w+"))==NULL) { perror("fopen"); exit(-1);}
  fprintf(odat,"P6\n# CREATOR: Christian Schulte and Joerg Wolf \n");
  fprintf(odat,"%d %d\n255\n",OFILE_XSIZE,OFILE_YSIZE);
  for (ycnt=yf;ycnt<yt;ycnt++){ 
    dummy++;if (dummy&0x08) { if (DBG_MOD&0x01) fprintf(stderr,"."); dummy=0; }
    for (xcnt=xf;xcnt<xt;xcnt++){
      if (im_data[xcnt][ycnt][layer]<255) {
       fputc(im_data[xcnt][ycnt][layer],odat); 
       fputc(im_data[xcnt][ycnt][layer],odat);
       fputc(im_data[xcnt][ycnt][layer],odat);
      }
      else {
       fputc(im_data[xcnt][ycnt][layer]-255,odat); 
       fputc(0,odat);
       fputc(0,odat);
      }
    }
  }
  fclose(odat);
  if (DBG_MOD&0x01) fprintf(stderr,"\n");
}

write_x_results(int num)
{
 FILE *fout;
 int xc;

 if ((fout=fopen("tmp/imgdata/x.line","w+"))==NULL) { perror("fopen"); exit(-1);}
 fprintf (fout,"%d ",num+1); 
 for (xc=0;xc<=num;xc++)
  fprintf(fout,"%d ",x_results[xc]);
}


int main (int argc,char **argv)
{
extern char *optarg;
unsigned int cnt1=0,cnt2=0,pn;
char pn_name[50];
time_t ts;
struct tm *lt;

  while( (dummy=getopt(argc,argv,"l:c:x:4nSm:q")) != -1)
  switch(dummy)
  {
   case('q'):DBG_MOD=0;break;
   case('l'):
   	sscanf(optarg,"%s %s %s",(char*) &fname1,(char*) &fname2,(char*) &oname1);
   	if (DBG_MOD&0x01) fprintf(stderr,"comparing %s AND %s  \nOUTPUT:%s \n\n",fname1,fname2,oname1);
   	if (RUN_MODE!=0) { fprintf(stderr,"only one option please !! \n\n"); exit(1); }
   	RUN_MODE|=0x01;  // set the LSB !!
   	break;
   case('c'):
   	sscanf(optarg,"%s %s",(char*) &fname1,(char*) &oname1);
   	if (DBG_MOD&0x01) fprintf(stderr,"generating contrast of %s  \n-> OUTPUT:%s \n\n",fname1,oname1);
   	if (RUN_MODE!=0) { fprintf(stderr,"only one option please !! \n\n"); exit(1); }
   	RUN_MODE|=0x02; // set the second bit 00000010b
        open_pic(fname1,0);
   	break;
   case('x'):
   	sscanf(optarg,"%s %s %s",(char*) &fname1,(char*) &fname2,(char*) &oname1);
   	if (DBG_MOD&0x01) fprintf(stderr,"comparing %s with %s  OUTPUT:%s \n",fname1,fname2,oname1);
   	if (RUN_MODE!=0) { fprintf(stderr,"only one option please !! \n"); exit(1); }
   	RUN_MODE|=0x04; // set the third  bit 00000100b
   	break;
   case('S'):if (DBG_MOD&0x01) fprintf(stderr,"running in HIGH-SPEED mode \n");HS=TRUE;break;
   case('4'):if (DBG_MOD&0x01) fprintf(stderr,"using 4x file size .. OK \n");
             OFILE_XSIZE=OFILE4_XSIZE;
             OFILE_YSIZE=OFILE4_YSIZE;
             break;
   case('n'):if (DBG_MOD&0x01) fprintf(stderr,"running without creating output file ... \n\n");
   	     CREATE_OFILE=FALSE;
   	     break;
   case('m'):sscanf(optarg,"%s %s %s %d %d",(char*) &fname1,(char*) &fname2,(char*) &oname1,&cnt1,&cnt2);
             if (DBG_MOD&0x01) fprintf(stderr,"comparing \"%s\"      with \"%s[%d-%d].pgm\" \n\n",fname1,fname2,cnt1,cnt2);
             if (RUN_MODE!=0) { fprintf(stderr,"only one option please !! \n\n"); exit(1); }
             RUN_MODE|=0x04;
             break;
   default:{fprintf(stderr,"\nUNKNOWN OPTION ... SORRY \n\n %s",HELP);exit(1); }
  }

  time(&ts);
  lt=localtime(&ts);
  fprintf (stderr,"%u.%u.%u-%u:%u:%u: FINDLASER\n",
    lt->tm_mday,lt->tm_mon,lt->tm_year,lt->tm_hour,lt->tm_min,lt->tm_sec);
  
//  vec_data = (unsigned int **)im_data;

  if (RUN_MODE&0x02)
  {
   if (DBG_MOD&0x01) fprintf(stderr,"scan...\n");
   scan_pic();
   if (CREATE_OFILE==TRUE) write_contr_pic(oname1,0);
  }

  if (RUN_MODE&0x01)
  {
   open_part_pic(fname1,0);
   open_part_pic(fname2,1);
   find_laser(0);
   if (CREATE_OFILE==TRUE) write_layer_to_file(oname1,2);
  }
  
  if (RUN_MODE&0x04)
  {
   open_part_pic(fname1,0);
   for (pn=cnt1;pn<=cnt2;pn++)
   {
    sprintf(pn_name,"%s%4.4d.pgm",fname2,pn);
    if (open_part_pic(pn_name,1)==0)
    {
     find_laser(pn);
     if (CREATE_OFILE==TRUE) { sprintf(pn_name,"%s%d.pgm",oname1,pn);  write_layer_to_file(pn_name,2); }
     if (DBG_MOD&0x01) fprintf(stderr,"\n");
    }
   }
   fprintf(stderr,"\n OK findlaser(quitting)\n");
   write_x_results(cnt2-cnt1);
  }   
  exit (0);
}

