/*
 To work the first commented out byte (a counter) of each register must
 be uncommented.
 The counter to how many different bytes are used within the
 'SHANNON'-coding...
*/

//#include <fstream.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>

#define PHRASES_MAX 100
#define MAX_PHRASE_LEN 100
struct phrase
{
    int  phrasemem[MAX_PHRASE_LEN];
    int  len;
    int  count;
};
phrase phrases[PHRASES_MAX];

const int MAXBUFF = 2000000;
//START inclusive
#define ENCODE_START 0
//END exclusive
#define ENCODE_END 1

FILE *inFile;
FILE *outFile;
FILE *outFile2;
unsigned char buf[MAXBUFF];
unsigned char out_buf[MAXBUFF/11+11][11];
int len;
int vbl_len;
int byte_pointer_read = 0;
int byte_pointer_write = 0;

int current_bit_counter = -1;
int current_out_byte=0;


#define MAP_BIT_MAX 127
#define MAP_CODE_MAX 255

int map[MAP_BIT_MAX][MAP_CODE_MAX];

int GET_BYTE()
{
 current_bit_counter = -1;
 return buf[byte_pointer_read++];
}
void WRITE_BYTE(int byte)
{
  fprintf(outFile," DB $%02X \n",byte);
  fwrite(&byte,1,1,outFile2);
}

int GET_BIT()
{
 if (current_bit_counter == -1)
 {
  current_out_byte = GET_BYTE();
  current_bit_counter = 7;
 }
 if (current_out_byte&(1<<(current_bit_counter--)))
 {
  return 1;
 }
 return 0;
}

int total_unpack_count = 0;

int main( int argc, char* argv[] )
{
  printf("\nCalling ");
 for (int ii=0;ii<argc;ii++)
   printf(" %s", argv[ii]);
 printf(" \n \n");
 if ( argc != 2 )
 {
  printf("Usage: decode <infile>  \n");
  return 0;
 }
 inFile=fopen(argv[1],"rb");
 if( !inFile )
 {
  printf("A file error occured with %s! \n", argv[1]);;
  return 2;
 }
 len=fread( buf, sizeof(char),sizeof(char)*MAXBUFF,inFile );
 fclose(inFile);
 printf("Length of file: %i \n",len);

 vbl_len = GET_BYTE()*256+GET_BYTE();
 printf("Length of track: %i \n",vbl_len);
 int ym_register;

 outFile=fopen("out_int.asm","wb+");
 if (!outFile)
 {
  printf("File Open Error! \n");
  return 1;
 }
 outFile2=fopen("out_int.bin","wb+");
 if (!outFile2)
 {
  printf("File Open Error! \n");
  return 1;
 }

 fprintf(outFile," DW %i ; length of track \n", vbl_len);


 for (ym_register=ENCODE_START; ym_register< ENCODE_END; ym_register++)
 {
  int to_map = GET_BYTE();
  int i;
  printf("Register %i has %i different 'bytes' \n", ym_register, to_map);
  // initialize mapper
  fprintf(outFile,"; mapper for ym_register %i \n", ym_register);
  fprintf(outFile," DB $%02X ; uses different bytes \n", to_map);
  for (i=0; i < MAP_BIT_MAX; i++)
  {
   for (int j=0; j < MAP_CODE_MAX; j++)
   {
    map[i][j] = -1;
   }
  }
  int no_phrases=0;
  for (i=0; i < to_map; i++)
  {
   int bits = GET_BYTE();
   int code = GET_BYTE();
   int real_byte = GET_BYTE();

   fprintf(outFile," DB %02X, %02X, %02X ; bits, code, realbyte \n", bits, code, real_byte);
   if ((bits&127) > MAP_BIT_MAX)
   {
    printf("Bit overflow - bye! \n");
    exit(1);
   }

   map[bits&127][code] = real_byte;
   if (bits&128)
   {
    no_phrases++;
    map[bits&127][code]+=256;
   }
  }
  fprintf(outFile,"; Phrases follow (%i) \n",no_phrases);
  // load phrases
  for (i=0;i<no_phrases;i++)
  {
   phrases[i].len = GET_BYTE();
   fprintf(outFile," DB %02X", phrases[i].len);
   int j;
   for (j=0;j < phrases[i].len; j++)
   {
    phrases[i].phrasemem[j] = GET_BYTE();
    fprintf(outFile,", %02X", phrases[i].phrasemem[j]);
   }
   fprintf(outFile," \n");
  }

  fprintf(outFile,"; Data follows...\n");
  // done... now start decoding!
  int byte_decrunched_count = 0;
  while (byte_decrunched_count < vbl_len)
  {
   int RLE_count = 0;

   if (GET_BIT() == 0)
   {
    // one byte
    RLE_count = 1;
   }
   else
   {
    // rle encoded
    int count_bits = 1; // already got a 1, see above
    while (GET_BIT() == 1)
    {
     count_bits++;
    }
    count_bits+=2; // plus two, since we start coding with 3 bits

    // the following count_bits represent the RLE count
    // lsb first
    for (i=0; i < count_bits; i++)
    {
     RLE_count+=((GET_BIT()) << i);
    }
   }

   // in RLE_count now the number of times we should repeat the
   // following bit data...
// msb first
   int bits = 0;
   int code = 0;
   int is_phrase = 0;
   int unpacked_byte = 0;
   while (1)
   {
    code <<= 1;
    code += GET_BIT();
    bits++;
    if (map[bits][code] != -1)
    {
     unpacked_byte = map[bits][code];
     if (unpacked_byte>=256)
     {
      is_phrase = 1;
      unpacked_byte -= 256;
     }
     break;
    }
   }
/*
   fprintf(outFile,"; byte_decrunched_count %i \n",byte_decrunched_count);
   if (is_phrase == 0)
    fprintf(outFile,"; byte %02X, times %i \n",unpacked_byte,RLE_count);
   else
    fprintf(outFile,"; phrase %02X, times %i \n",unpacked_byte,RLE_count);
*/
   for (i=0; i<RLE_count; i++)
   {
    if (is_phrase == 0)
    {
     WRITE_BYTE(unpacked_byte);
     byte_decrunched_count++;
     total_unpack_count++;
    }
    else
    {
     int j;
     for (j=0;j<phrases[unpacked_byte].len;j++)
     {
      WRITE_BYTE(phrases[unpacked_byte].phrasemem[j]);
      byte_decrunched_count++;
      total_unpack_count++;
     }
    }
   }
  }
 }
 printf("Bytes unpacked: %i \n", total_unpack_count);
 fclose(outFile);
 fclose(outFile2);

 return 0;
}



