#include "includes.h"

/**************************************|****************************************
Routine   : CountType
Input  par: Transformation *T (pointer to trans)
            int type          (type to be counted)
Output par: int               (counts)
Function  : counts main-block and its subblocs of type 'type'. Does the counting
            recursivly. 
***************************************|***************************************/
 
 unsigned long CountType(Transformation *T, int type)
  {
   unsigned long count=0,i,j;
   
   if (T->Type==type) count++;
   if (T->Sub!=NULL)
    {
     for(i=0;i<2;i++)
     for(j=0;j<2;j++)
     if (T->Sub[i][j]!=NULL) count += CountType(T->Sub[i][j],type);
    }
   return count;
  }
 
/**************************************|****************************************
Routine   : CountMainSubs
Input  par: Transformation *T (pointer to trans)
Output par: unsigned int (counted mainsub configurations)
Function  : counts main-sub-configurations recursively.
***************************************|***************************************/
 
 unsigned long CountMainSubs(Transformation *T,unsigned long *PureMain,int level)
  {
   unsigned long count=1,i,j;   

   if (T->Sub!=NULL)
    {
     for(i=0;i<2;i++)
     for(j=0;j<2;j++)
     if (T->Sub[i][j]!=NULL) 
     { 
       level--;
       count +=  CountMainSubs(T->Sub[i][j],PureMain,level);
      }
    }
   else (PureMain[level])++;
   return count;
  }
 
/**************************************|****************************************
Routine   : HeadInfo
Input  par: Transformation ***T (pointer to trans array)
            LimboHeader *Head   (pointer to header structure)
Output par: none
Function  : Produce info-statistic on Limbo-Header (fractal code header).
***************************************|***************************************/
 
 void HeadInfo(Transformation ***T, LimboHeader *Head)
  {
   Parameter *Par=GimmeAParameter();
   int i,j,x,y;
   unsigned long edg=0,sha=0,mainsubs=0;
   unsigned long *PureMain;
   
   vprintf(stderr,"\nFractal code info...");
   
   Par->XBits=Head->XBits;
   Par->YBits=Head->YBits;
   
   Par->SBits=Head->SBits;
   Par->ABits=Head->ABits;
   Par->AMax =Head->AMax/100.0;
   Par->AMin =Head->AMin/100.0;
   Par->DBits=Head->DBits;
   Par->GBits=Head->GBits;
   Par->TBits=Head->TBits;
   
   x=Head->MSBx*256+Head->LSBx;
   y=Head->MSBy*256+Head->LSBy;
   
   PureMain=(void *)GimmeALongArray(Head->NSquare+1);
   for (i=0;i<Head->NSquare;i++) PureMain[i]=0;

   for (i=0;i<x/(Head->B<<Head->NSquare);i++) /* count edges + shades */
   for (j=0;j<y/(Head->B<<Head->NSquare);j++)
    {
     edg += CountType(T[i][j],EDGEBLOCK);
     sha += CountType(T[i][j],SHADEBLOCK);
     mainsubs += CountMainSubs(T[i][j],PureMain,Head->NSquare);
    }
   
    {
     unsigned long he=(sizeof(LimboHeader)+LIMBOSTRINGSIZE)*8;
     unsigned long edgbit=1+Par->XBits+Par->YBits+Par->ABits+Par->DBits+1+Par->TBits;
     unsigned long shabit=1+Par->GBits;
     unsigned long ed=edg*edgbit;
     unsigned long sh=sha*shabit;
     unsigned long to=ed+sh+Par->SBits*mainsubs;
     unsigned long ratio=(x*y*8*100)/to;
     unsigned long SNR=Head->MSBSNR*256+Head->LSBSNR;
     unsigned long cpu=Head->MSBCPU*256+Head->LSBCPU;
     
     vprintf(stderr,"\n   Size:(%d,%d)  Offset:(%d,%d)",x,y,
             Head->MSBox*256+Head->LSBox,Head->MSBoy*256+Head->LSBoy);
     for (i=Head->NSquare;i>=0;i--) 
     vprintf(stderr,"\n   Block size:  Domain:%2d  Range:%2d  Delta:%2d  Pure main blocks:%d ",
             Head->B<<(1+i),Head->B<<i,Head->Delta,PureMain[i]);
/*
     vprintf(stderr,"\n   Type:%d  Colors:%d  KeepDelta:%d ",
             Head->Type,Head->Col,Head->KeepDelta,Head->Type);
*/
     vprintf(stderr,"\n   Bits:  X:%d  Y:%d  Sub:%d  Alpha:%d  DeltaG:%d  G0:%d  TN:%d",
             Par->XBits,Par->YBits,Par->SBits,Par->ABits,Par->DBits,
             Par->GBits,Par->TBits);
     vprintf(stderr,"\n   Range:  Alpha max:%1.2f  Alpha min:%1.2f",Par->AMax,Par->AMin);
     vprintf(stderr,"\n   Header:                                         %7d [bit]",he);
     vprintf(stderr,"\n   Mainsub: %9u blocks of size %2u [bit] = %10u [bit]",
             mainsubs,Par->SBits,mainsubs*Par->SBits);
     vprintf(stderr,"\n   Shades:  %9u blocks of size %2u [bit] = %10u [bit]",sha,shabit,sh);
     vprintf(stderr,"\n   Edges:   %9u blocks of size %2u [bit] = %10u [bit]",edg,edgbit,ed);
     vprintf(stderr,"\n   Total:                                           %u [bit] = %u [byte]",
             to+he,(to+he+7)/8);
     vprintf(stderr,"\n   Ratio:   %3.2f:1 = %3.2f%% = %1.3f [bpp]",
             (float)ratio/100.0,10000.0/(float)ratio,(float)to/(float)(x*y));
     vprintf(stderr,"\n   PSNR:    %3.2f [dB]\n   CPU Time:%5u [sec]",(float)SNR/100.0,cpu);
    }

   FreeMeAULongArray(PureMain);
  } 


 void BitMapAnalyze(char *filename, int Iterations)
  {
   int x,y,i,j,B,delta;
   Transformation ***T;
   LimboHeader *Head;
   BitMap *Sha,*Edg,*Blc,*Self,*Tot,*Err,*Org,*Dst,*JPEG,*ErrJPEG;
   char file[99];
   char jpegfilename[MAXFILE];
   FILE *jpeg;
   int jpegfound=TRUE;

   Head=LoadFC(&T,filename);    /* header load */
   /*HeadInfo(T,Head);*/
   x=Head->MSBx*256+Head->LSBx;
   y=Head->MSBy*256+Head->LSBy;
   B=Head->B;
   delta=B<<Head->NSquare;
   
   Dst=Decode(T,Head->Type,x,y,Head->B<<Head->NSquare,Iterations,0); /* decoding */

   Edg=GimmeABitMap(x,y,GRAYIMG);
   /*CopyBitMap(Dst,Edg); */ Color(Edg,EDGEBLOCK_COLOR); 
   Sha=GimmeABitMap(x,y,GRAYIMG);
   /*CopyBitMap(Dst,Sha); */ Color(Sha,SHADEBLOCK_COLOR);
   Blc=GimmeABitMap(x,y,GRAYIMG);
   /*CopyBitMap(Dst,Blc); */ Color(Blc,255); 
   Self=GimmeABitMap(x,y,GRAYIMG);
   /*CopyBitMap(Dst,Self);*/  Color(Self,EDGEBLOCK_COLOR); 
   
   Tot=GimmeABitMap(x,y,GRAYIMG);
   Color(Tot,255);
   Err=GimmeABitMap(x,y,GRAYIMG);
   ErrJPEG=GimmeABitMap(x,y,GRAYIMG);
   
   Org=LoadBitMap(filename,x,y,0,0,delta<<1,""); /* load orginal bitmap image */


   strcpy(jpegfilename,ORGGFX);   /* test the existence of a encoded/decoded jpeg */
   strcat(jpegfilename,filename); /* bitmap in pgm/ppm format */
   strcat(jpegfilename,".jpg");
   vprintf(stderr,"\n   Searching for JPEG file '%s'...",jpegfilename);
   if (!(jpeg=fopen(jpegfilename,"rb"))) /* first try no suffix */
    {
     strcat(jpegfilename,PPMSFX);  /* try ppm */
     if (!(jpeg=fopen(jpegfilename,"rb")))   
      {
       strcpy(jpegfilename,ORGGFX);
       strcat(jpegfilename,file);
       strcat(jpegfilename,PGMSFX); /* try pgm then */
       if (!(jpeg=fopen(jpegfilename,"rb"))) jpegfound=FALSE;
      }
    }
   
   if (jpegfound) 
    {
     vprintf(stderr," found");
     fclose(jpeg);
     strcpy(jpegfilename,filename); /* bitmap in pgm/ppm format */
     strcat(jpegfilename,".jpg");
   
     JPEG=LoadBitMap(jpegfilename,x,y,0,0,1,"");
     vprintf(stderr,"\n   Orginal image/JPEG PSNR:%3.2f",PSNR(Org,JPEG));

     for(i=0;i<x;i++)   /* build error image  error = 5*(a-b)^2  or 5*abs(a-b) */ 
     {
      for(j=0;j<y;j++) 
       {
        float temp=Org->Map[i][j]-JPEG->Map[i][j];
          /* temp = 5.0*temp*temp; or*/ temp = 5*abs(temp);
        RectFill(ErrJPEG,i,j,1,1,(unsigned int)temp);
       }
     }
   }
  else vprintf(stderr," not found");
   
   for(i=0;i<x;i++)   /* build error image  error = 5*(a-b)^2  or 5*abs(a-b) */ 
    {
     for(j=0;j<y;j++) 
      {
       float temp=Org->Map[i][j]-Dst->Map[i][j];
         /* temp = 5.0*temp*temp; or*/ temp = 5*abs(temp);
       RectFill(Err,i,j,1,1,(unsigned int)temp);
      }
    }
   vprintf(stderr,"\nPSNR=%3.2f [dB]",PSNR(Org,Dst));
   
   for(i=0;i<x;i+=delta) /* build shade, edge blocks in bitmap */
    {
     for(j=0;j<y;j+=delta)
      {
       RecursiveRect(T[i/delta][j/delta],Sha,i,j,SHADEBLOCK,0);
       RecursiveRect(T[i/delta][j/delta],Edg,i,j,EDGEBLOCK,0);
       
       RecursiveRect(T[i/delta][j/delta],Blc,i,j,SHADEBLOCK,0);
       RecursiveRect(T[i/delta][j/delta],Blc,i,j,EDGEBLOCK,0);
       
       RecursiveRect(T[i/delta][j/delta],Tot,i,j,SHADEBLOCK,0);
       RecursiveRect(T[i/delta][j/delta],Tot,i,j,EDGEBLOCK,0);
       
/*       RecursiveSelfTransArrow(T[i/delta][j/delta],Self,i,j,EDGEBLOCK,-1);*/
      }
    }
   
   /* save all bitmaps */
   strcpy(file,filename);
   strcat(file,"_sha");
   SaveAndView(file,Sha);
   strcpy(file,filename);
   strcat(file,"_edg");
   SaveAndView(file,Edg);
   strcpy(file,filename);
   strcat(file,"_blc");
   SaveAndView(file,Blc);
   strcpy(file,filename);
   strcat(file,"_tot");
   SaveAndView(file,Tot);
   strcpy(file,filename);
   strcat(file,"_err");
   SaveAndView(file,Err);
   strcpy(file,filename);
   strcat(file,"_errjpeg");
   SaveAndView(file,ErrJPEG);
   strcpy(file,filename);
   strcat(file,"_self");
   SaveAndView(file,Self);
  }
