#include <stdio.h>
#include <stdlib.h>

#include "readbmp.h"
#include "rle.h"

extern unsigned char *infile,*outfile; 
extern unsigned char *iadrmax;

#define allign4(a) chunklen = ftell(a);if((chunklen & 0x3) != 0) {chunklen = 4 - (chunklen & 0x3);fwrite(&dummy,chunklen,1,a);}
  
enum DATA_MODES
{
    DATA_MODE_LINEAR = 0,   // z.b. für Mode 4
    DATA_MODE_TILE          // für Mode 0/1/2/3 
};

int main(int argc, char *argv[])
{
  FILE *rh,*wh;
  long   filecount,i;
  struct bmpdata_s **bmpdata; 
  struct RLE16_s RLE16,RLE16Color;
  long   lencount,chunklen,dummy;
  unsigned long std_width,std_height,std_depth,std_mode=DATA_MODE_LINEAR;
  
  long   animtype = 2;
  
  puts("\n GOLDMOMOs ANIM-TYPE(1-2) Compressor");
  puts(" -----------------------------------\n");
  
  // teste eingabe
  
  if(argc<=3)
  {
    // korregiere Dateinamen von prg, da unter windows (cygwin) immer mit pfad
  
    char *prgname = strrchr(argv[0],'\\');
    if (prgname==NULL) prgname= argv[0];
    else               prgname++;
     
    printf("type: %s {1[t]|2[t]} [files.bmp] {outputfile}\n",prgname);
    puts("");
    printf("example:\n\n");
    printf("%s 1 frames/*.bmp output.anim1\n",prgname);
    printf("%s 2 frames/*.bmp output.anim2\n",prgname);
    printf("%s 2t frames/*.bmp output.anim2\n",prgname);
    return (0);
  }
  
  filecount=argc-3;    // - prg,type,output
  
  animtype = atoi(argv[1]);
  if(argv[1][1]=='t')  // tilemodus
  {
    std_mode=DATA_MODE_TILE;
    printf(".using tilemodus\n");
  }
  
  printf(".start compress %d files to %s (type %d)\n",filecount,argv[argc-1],animtype);
  
  // ausgabefile
  wh = fopen(argv[argc-1],"wb");
  if(wh==0)
  {
   puts("cant write to this dir!");
   exit(0);
  }
  

  
  // lade daten
  
  bmpdata  = malloc(filecount*sizeof(struct bmpdata_s *));
  
  printf(".reading files %d\n",filecount);
  
  for(i=0;i<filecount;i++)
  {  
      unsigned short *cmapshort;
      unsigned long *tf;
  
      rh = fopen(argv[i+2],"rb");
      if(rh==0)
      {
          puts("cant open file");return(-1);
      }
      
      printf(".reading and decoding file %s\r",argv[i+1]);
      bmpdata[i] = malloc(sizeof(struct bmpdata_s));
      readbmp(rh,bmpdata[i]);
     
      
      if(i==0)
      {
             std_width      = bmpdata[0]->width;
             std_height     = bmpdata[0]->height;
             std_depth      = bmpdata[0]->depth;
             
             printf("\n.using format %dx%dx%d\n",std_width,std_height,std_depth);
      }
      
      if(DATA_MODE_TILE==std_mode) // benutzte tilemodus wenn gewünscht
      {
            tf=(unsigned long *)tilefilter(bmpdata[i]->data,std_width,std_height);
            free(bmpdata[i]->data);
            bmpdata[i]->data=(void *)tf;
      }
      
      cmapshort = (unsigned short *) color32to15(bmpdata[i]->cmap);
      free(bmpdata[i]->cmap);                                   // free 32bit cmap
      bmpdata[i]->cmap = (unsigned long *) cmapshort;          // set to 16bit cmap
      
      fclose(rh);
  }

  puts("");

  // schreibe framecounter
  {
    char ID1[]={"GOLDMOMO"};
    char ID2[]={"ANIMTYPX"};

    if(animtype==1)    ID2[7] = '1';
    if(animtype==2)    ID2[7] = '2';

       
    fwrite(ID1,8,1,wh);               // Werbung :)
    fwrite(ID2,8,1,wh);               // Formattyp
    fwrite(&std_width,4,1,wh);        // breite
    fwrite(&std_height,4,1,wh);       // höhe
    fwrite(&std_depth,4,1,wh);        // farbtiefe
    fwrite(&std_mode,4,1,wh);         // datenformat
    fwrite(&filecount,4,1,wh);        // framecount
  }

  // schreibe First FRAME

  puts(".make first frame");
  simpleRLE16(bmpdata[0]->data,bmpdata[0]->len/2,&RLE16);
  simpleRLE16(bmpdata[0]->cmap,512/2,&RLE16Color);
  
  // schreibe first PALETTE
  
  fwrite(&RLE16Color.simpleRLE16len,4,1,wh);                            // write len
  fwrite(&RLE16Color.simpleRLE16key,2,1,wh);                            // key
  fwrite(&dummy,2,1,wh);                                                // dummy
  fwrite(RLE16Color.simpleRLE16data,RLE16Color.simpleRLE16len,1,wh);    // rle datas
  allign4(wh);
  
  // schreibe FIRST FRAME
                                          //chunklen
  fwrite(&RLE16.simpleRLE16len,4,1,wh);                                 // write len
  fwrite(&RLE16.simpleRLE16key,2,1,wh);                                 // key
  fwrite(&dummy,2,1,wh);                                                // dummy
  fwrite(RLE16.simpleRLE16data,RLE16.simpleRLE16len,1,wh);              // rle datas
  allign4(wh);

     
  free(RLE16.simpleRLE16data);
  free(RLE16Color.simpleRLE16data);
  
  // schreibe REST FRAMES
  
  puts(".frame compress");
  
  for(i=0;i<filecount-1;i++)
  {
    
    unsigned short *delta;
    unsigned char  *outfileorg;
    long deltalen,dummy=0;
    FILE *trh,*trw;
 
  
    printf(".compress %d with %d (delta+rle%s)\r",i,i+1,(animtype==2)?"+lzss":"");
        
    delta  = (unsigned short *) deltaframes(bmpdata[i]->data,bmpdata[i+1]->data,bmpdata[i+1]->len/2);        
    simpleRLE16(delta,bmpdata[i+1]->len/2,&RLE16);
    free(delta);    //free delta buffer
    
    // wenn animtype 2  dann noch eine lszz Kompression auf die xor/rle daten
    
    if(animtype==2) 
    {   
    // type 2 LZSS
   
    infile  = (unsigned char*) RLE16.simpleRLE16data;
    iadrmax = (unsigned char*) infile + RLE16.simpleRLE16len;
    outfile = (unsigned char*) malloc(RLE16.simpleRLE16len*2);
    outfileorg = outfile;
    
    deltalen = Encode();     // lzss
    free(RLE16.simpleRLE16data); // free old rle/delta
    RLE16.simpleRLE16data = (void*)outfileorg;
    
    }

    // schreibe PALETTE (nur RLE/XOR in jeden Modus)
     
    delta  = (unsigned short *) deltaframes(bmpdata[i]->cmap,bmpdata[i+1]->cmap,512/2); 
    simpleRLE16(delta,512/2,&RLE16Color);
    free(delta);
    
 
    fwrite(&RLE16Color.simpleRLE16len,4,1,wh);                            // write len
    fwrite(&RLE16Color.simpleRLE16key,2,1,wh);                            // key
    fwrite(&dummy,2,1,wh);                                                // dummy
    fwrite(RLE16Color.simpleRLE16data,RLE16Color.simpleRLE16len,1,wh);    // rle datas
    allign4(wh);

    // weiter GFX DATAS
  
    if(animtype==2) // wenn Type 2 dann noch LZSSData länge speichern
    {  
        fwrite(&deltalen,4,1,wh);                                     //datalen 
    }
   
    fwrite(&RLE16.simpleRLE16len,4,1,wh);                        // rle len
    fwrite(&RLE16.simpleRLE16key,2,1,wh);                        // key
    fwrite(&dummy,2,1,wh);                                       // allign
    
    if(animtype==1) // wenn Type 1 dann speichere RLE mit ihrer Länge
    {     
        fwrite(RLE16.simpleRLE16data,RLE16.simpleRLE16len,1,wh);  // rle datas
    }
    if(animtype==2) // wenn Type 2 dann speichere LZSS mit ihrer Länge 
    {
        fwrite(RLE16.simpleRLE16data,deltalen,1,wh);               // lzss datas
    }   
    allign4(wh);
    
    free(RLE16.simpleRLE16data);
    free(RLE16Color.simpleRLE16data);
      
  }
  
  puts("");
  
  lencount = ftell(wh);
  
  puts("\nStatistics");
  printf(" Frames         = %d\n",filecount);
  printf(" Inputsize      = %d bytes\n",bmpdata[0]->len*filecount);
  printf(" Outputfilesize = %d bytes\n",lencount);
  printf(" Compressed to    %d %%\n",lencount*100/(bmpdata[0]->len*filecount));
  printf(" Size per Frame ~ %d bytes (%3.2lf^2 Pixel)\n",lencount/filecount,sqrt(lencount/filecount));
  
  for(i=0;i<filecount;i++)
  {
     free(bmpdata[i]);
  }
  
  
  free(bmpdata);
  fclose(wh);
  

  return 0;
}
