/** VGB: portable GameBoy emulator ***************************/
/**                                                         **/
/**                           VGB.c                         **/
/**                                                         **/
/** This file contains generic main() procedure statrting   **/
/** the emulation.                                          **/
/**                                                         **/
/** Copyright (C) Marat Fayzullin 1995                      **/
/**               Marcel de Kogel 1996                      **/
/**     You are not allowed to distribute this software     **/
/**     commercially. Please, notify me, if you make any    **/
/**     changes to this file.                               **/
/**                                                         **/
/** Edited for use with MS-DOS by Marcel de Kogel           **/
/*************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <conio.h>

#include "GB.h"
#include "Help.h"

#define MAX_CONFIG_FILE_SIZE    4096
#define MAX_FILE_NAME           256

struct colorscheme_struct
{
 char *color0;
 char *color1;
 char *color2;
 char *color3;
};

static struct colorscheme_struct defcolorschemes[] =
{
 { "white","#B0B0B0","#606060","black" },
 { "#c2e3b3","#9cb88e","#688063","#506d4c" },
 { "#ffff50","#bdbd48","#7b7bac","#292952" },
 { "#cbec50", "#a3d55a", "#5c9447", "#056d21" },
 { "#a0a000", "#707000", "#555500", "#191900" },
 { "#e6a428", "#ba8522", "#8d661b", "#614615" },

};

static struct colorscheme_struct colorschemes[256];

char *Options[]=
{
  "verbose","vperiod","uperiod","help","shm","noshm",
  "trap","saver","nosaver","color0","color1","color2",
  "color3","cheat","delay","nodelay","crc","nocrc",
  "video","sound","volume","background","ifreq","swapbuttons",
  "colorscheme","definecolorscheme","spritecolor0","spritecolor1",
  "spritecolor2","spritecolor3","spritecolorscheme","brightness",
  "spritebrightness","windowbrightness","windowcolorscheme",
  "windowcolor0","windowcolor1","windowcolor2","windowcolor3","stereo",
  "backgroundcolorscheme","backgroundcolor0","backgroundcolor1","backgroundcolor2","backgroundcolor3",
  "autoa","autob","logsnd","keys","backgroundbrightness",
  NULL
};

char *AbvOptions[]=
{
  "vb","vp","up","he","shm","noshm",
  "trap","saver","nosaver","c0","c1","c2",
  "c3","cheat","delay","nodelay","crc","nocrc",
  "video","sound","vol","bg","ifreq","swap",
  "cs","dcs","sc0","sc1","sc2","sc3","scs","br","sbr","wbr","wcs",
  "wc0","wc1","wc2","wc3","stereo",
  "bcs","bc0","bc1","bc2","bc3",
  "autoa","autob","logsnd","keys","bbr",
  NULL
};

extern int   UseSHM;
extern int   SaveCPU;
extern char *ColorNames[8];
#ifdef MSDOS
extern int videomode;
extern int soundmode;
extern byte mastervolume;
extern int swapbuttons;
extern int IFreq;
extern int IntSync;
extern int brightness,spritebrightness,windowbrightness,backgroundbrightness;
extern int stereomode;
extern char *szKeys;
#endif

#define _DefExt         ".gb"

static int _argc;
static char *_argv[4096];
static char MainConfigFile[MAX_CONFIG_FILE_SIZE];
static char SubConfigFile[MAX_CONFIG_FILE_SIZE];
static char szTempFileName[MAX_FILE_NAME];
static char *CartName="CART.GB";
static char _CartName[MAX_FILE_NAME];
static char ProgramPath[MAX_FILE_NAME];
static char CartNameNoExt[MAX_FILE_NAME];
char szGifFile[MAX_FILE_NAME];
static char _SaveName[MAX_FILE_NAME];
extern char *SaveName;

static void SelectColorScheme (int nr)
{
 ColorNames[0]=ColorNames[4]=ColorNames[8]=colorschemes[nr].color0;
 ColorNames[1]=ColorNames[5]=ColorNames[9]=colorschemes[nr].color1;
 ColorNames[2]=ColorNames[6]=ColorNames[10]=colorschemes[nr].color2;
 ColorNames[3]=ColorNames[7]=ColorNames[11]=colorschemes[nr].color3;
}

static void SelectSpriteColorScheme (int nr)
{
 ColorNames[4]=colorschemes[nr].color0;
 ColorNames[5]=colorschemes[nr].color1;
 ColorNames[6]=colorschemes[nr].color2;
 ColorNames[7]=colorschemes[nr].color3;
}

static void SelectWindowColorScheme (int nr)
{
 ColorNames[8]=colorschemes[nr].color0;
 ColorNames[9]=colorschemes[nr].color1;
 ColorNames[10]=colorschemes[nr].color2;
 ColorNames[11]=colorschemes[nr].color3;
}

static void SelectBackgroundColorScheme (int nr)
{
 ColorNames[0]=colorschemes[nr].color0;
 ColorNames[1]=colorschemes[nr].color1;
 ColorNames[2]=colorschemes[nr].color2;
 ColorNames[3]=colorschemes[nr].color3;
}

static void DefineColorScheme (int nr,char *c0,char *c1,char *c2,char *c3)
{
 if (nr>=128 && nr<=255)
 {
  colorschemes[nr].color0=c0;
  colorschemes[nr].color1=c1;
  colorschemes[nr].color2=c2;
  colorschemes[nr].color3=c3;
 }
}

static int ParseOptions (int argc,char *argv[])
{
 int N,I,J;
 int misparm;
  for(N=1,I=0;N<argc;N++)
  {
    misparm=0;
    if(*argv[N]!='-')
    {
      if(I++)
      {
       printf("Excessive filename '%s'\n",argv[N]);
       return 0;
      }
    }
    else
    {    
      for(J=0;Options[J];J++)
        if(!strcmp(argv[N]+1,Options[J])) break;
      if (!Options[J])
       for(J=0;AbvOptions[J];J++)
         if(!strcmp(argv[N]+1,AbvOptions[J])) break;
      switch(J)
      {
        case 0:  N++;
                 if(N<argc)
                 { Verbose=atoi(argv[N]);TrapBadOps=Verbose&0x04; }
                 else misparm=1;
                 break;
        case 1:  N++;
                 if(N>=argc)
                   misparm=1;
                 else
                 {
                   VPeriod=atoi(argv[N]);
                   if((VPeriod<1000)||(VPeriod>320000)) VPeriod=69905;
                 }
                 break;
        case 2:  N++;
                 if(N>=argc)
                   misparm=1;
                 else
                 {
                   UPeriod=atoi(argv[N]);
                   if(UPeriod>20) UPeriod=2;
                 }
                 break;
        case 3:  printf ("VGB MS-DOS 0.8b1\n"
                         "Core emulator code copyright (C) 1995,1996  Marat Fayzullin\n"
                         "MS-DOS port copyright (C) 1996  Marcel de Kogel\n");
                 for(J=0;HelpText[J];J++)
                 {
                  if (!strcmp(HelpText[J],""))
                  {
                   puts ("");
                   printf("-- more --"); fflush(stdout);
                   getch (); printf ("\n");
                  }
                  puts(HelpText[J]);
                 }
                 return 0;
        case 13: N++;
                 if(N>=argc)
                   misparm=1;
                 else
                   if(!AddCheat(argv[N]))
                   {
                     printf("Wrong cheat data supplied\n");
                     return 0;
                   }
                 break;
        case 14: LineDelay=1;break;
        case 15: LineDelay=0;break;
        case 16: CheckCRC=1;break;
        case 17: CheckCRC=0;break;
#ifdef DEBUG
        case 6:  N++;
                 if(N>=argc)
                   misparm=1;
                 else 
                   sscanf(argv[N],"%hX",&Trap);
                 break;
#endif
#ifdef MSDOS
        case 9:  N++;
                 if(N<argc) ColorNames[0]=ColorNames[4]=ColorNames[8]=argv[N];
                 else misparm=1;
                 break;
        case 10: N++;
                 if(N<argc) ColorNames[1]=ColorNames[5]=ColorNames[9]=argv[N];
                 else misparm=1;
                 break;
        case 11: N++;
                 if(N<argc) ColorNames[2]=ColorNames[6]=ColorNames[10]=argv[N];
                 else misparm=1;
                 break;
        case 12: N++;
                 if(N<argc) ColorNames[3]=ColorNames[7]=ColorNames[11]=argv[N];
                 else misparm=1;
                 break;
        case 18: N++;
                 if(N<argc)
                  videomode=atoi(argv[N]);
                 else
                  misparm=1;
                 break;
        case 19: N++;
                 if(N<argc)
                  soundmode=atoi(argv[N]);
                 else
                  misparm=1;
                 break;
        case 20: N++;
                 if(N<argc)
                  mastervolume=atoi(argv[N]);
                 else
                  misparm=1;
                 break;
        case 21: N++;
                 if(N<argc)
                 {
                  _fixpath (argv[N],szGifFile);
                  strlwr (szGifFile);
                  if (strchr(szGifFile,'.')==0)
                   strcat (szGifFile,".gif");
                 }
                 else
                  misparm=1;
                 break;
        case 22: N++;
                 if(N<argc)
                  IFreq=atoi(argv[N]);
                 else
                  misparm=1;
                 break;
        case 23: N++;
                 if(N<argc)
                  swapbuttons=atoi(argv[N]);
                 else
                  misparm=1;
                 break;
        case 24: N++;
                 if(N<argc)
                  SelectColorScheme (atoi(argv[N]));
                 else
                  misparm=1;
                 break;
        case 25: if((N+5)<argc)
                 {
                  DefineColorScheme (atoi(argv[N+1]),
                                     argv[N+2],
                                     argv[N+3],
                                     argv[N+4],
                                     argv[N+5]);
                  N+=5;
                 }
                 else
                  misparm=1;
                 break;
        case 26:  N++;
                 if(N<argc) ColorNames[4]=argv[N];
                 else misparm=1;
                 break;
        case 27: N++;
                 if(N<argc) ColorNames[5]=argv[N];
                 else misparm=1;
                 break;
        case 28: N++;
                 if(N<argc) ColorNames[6]=argv[N];
                 else misparm=1;
                 break;
        case 29: N++;
                 if(N<argc) ColorNames[7]=argv[N];
                 else misparm=1;
                 break;
        case 30: N++;
                 if(N<argc)
                  SelectSpriteColorScheme (atoi(argv[N]));
                 else
                  misparm=1;
                 break;
        case 31: N++;
                 if(N<argc)
                  brightness=spritebrightness=atoi(argv[N]);
                 else
                  misparm=1;
                 break;
        case 32: N++;
                 if(N<argc)
                  spritebrightness=atoi(argv[N]);
                 else
                  misparm=1;
                 break;
        case 33: N++;
                 if(N<argc)
                  windowbrightness=atoi(argv[N]);
                 else
                  misparm=1;
                 break;
        case 34: N++;
                 if(N<argc)
                  SelectWindowColorScheme (atoi(argv[N]));
                 else
                  misparm=1;
                 break;
        case 35: N++;
                 if(N<argc) ColorNames[8]=argv[N];
                 else misparm=1;
                 break;
        case 36: N++;
                 if(N<argc) ColorNames[9]=argv[N];
                 else misparm=1;
                 break;
        case 37: N++;
                 if(N<argc) ColorNames[10]=argv[N];
                 else misparm=1;
                 break;
        case 38: N++;
                 if(N<argc) ColorNames[11]=argv[N];
                 else misparm=1;
                 break;
        case 39: N++;
                 if(N<argc) stereomode=atoi(argv[N]);
                 else misparm=1;
                 break;
        case 40: N++;
                 if(N<argc)
                  SelectBackgroundColorScheme (atoi(argv[N]));
                 else
                  misparm=1;
                 break;
        case 41: N++;
                 if(N<argc) ColorNames[0]=argv[N];
                 else misparm=1;
                 break;
        case 42: N++;
                 if(N<argc) ColorNames[1]=argv[N];
                 else misparm=1;
                 break;
        case 43: N++;
                 if(N<argc) ColorNames[2]=argv[N];
                 else misparm=1;
                 break;
        case 44: N++;
                 if(N<argc) ColorNames[3]=argv[N];
                 else misparm=1;
                 break;
        case 45: N++;
                 if(N<argc) AutoA=atoi(argv[N]);
                 else misparm=1;
                 break;
        case 46: N++;
                 if(N<argc) AutoB=atoi(argv[N]);
                 else misparm=1;
                 break;
        case 47: N++;
                 if(N<argc) SndName=argv[N];
                 else misparm=1;
                 break;
        case 48: N++;
                 if(N<argc) szKeys=argv[N];
                 else misparm=1;
                 break;
        case 49: N++;
                 if(N<argc)
                  backgroundbrightness=atoi(argv[N]);
                 else
                  misparm=1;
                 break;
#endif
        default: printf("Wrong option '%s'\n",argv[N]);
                 return 0;
      }
    }
    if (misparm)
    {
     printf ("%s: missing parameter\n",argv[N-1]);
     return 0;
    }
  }
  return 1;
}

static int GetCartName (int argc,char *argv[])
{
 int N,I,J;
 for(N=1,I=0;N<argc;N++)
 {
  if(*argv[N]!='-')
   switch(I++)
   {
    case 0:  CartName=argv[N];
             break;
    default: return 0;
   }
  else
  {    
   for(J=0;Options[J];J++)
    if(!strcmp(argv[N]+1,Options[J])) break;
   if (!Options[J])
    for(J=0;AbvOptions[J];J++)
     if(!strcmp(argv[N]+1,AbvOptions[J])) break;
   switch(J)
   {
    case 3:  return 0;          /* -help */
    case 0: case 1: case 2: case 13:
    case 9: case 10: case 11: case 12:
    case 18: case 19: case 20: case 21: case 22: case 23: case 24:
    case 26: case 27: case 28: case 29: case 30: case 31: case 32:
    case 33: case 34: case 35: case 36: case 37: case 38: case 39:
    case 40: case 41: case 42: case 43: case 44: case 45: case 46:
    case 47: case 48: case 49:
#ifdef DEBUG
    case 6:
#endif
             N++;
             if (N>=argc)
              return 0;
     break;
    case 25:
             N+=5;
             if (N>=argc)
              return 0;
    case 14: case 15: case 16: case 17:
             break;
    default: return 0;
   }
  }
 }
 return 1;
}

static void LoadConfigFile (char *szFileName,unsigned char *ptr)
{
 FILE *infile;
 infile=fopen (szFileName,"rb");
 if (infile==NULL)
  return;
 fread (ptr,1,MAX_CONFIG_FILE_SIZE,infile);
 fclose (infile);
 while (*ptr)
 {
  while (*ptr && *ptr<=' ')
   ++ptr;
  if (*ptr)
  {
   _argv[_argc++]=ptr;
   while (*ptr && *ptr>' ')
    ++ptr;
   if (*ptr)
    *ptr++='\0';
  }
 }
}

static void FixFileNames (void)
{
 char *p,*q;
 _fixpath (CartName,_CartName);
 strlwr (_CartName);
 CartName=_CartName;
 strcpy (CartNameNoExt,CartName);
 p=CartNameNoExt;
 q=strchr(CartNameNoExt,'/');
 while (q)                      /* get last '/' */
 {
  p=++q;
  q=strchr(q,'/');
 };
 q=NULL;
 while ((p=strchr(p,'.'))!=NULL) /* get last '.' */
 {
  q=p;
  ++p;
 }
 if (q)                         /* remove extension */
  *q='\0';
 else
  strcat (CartName,_DefExt);
}

static void GetPath (char *szFile,char *szPath)
{
 char *p,*q;
 strcpy (szPath,szFile);
 p=szPath;
 q=strchr(p,'/');
 while (q)                      /* get last '/' */
 {
  p=++q;
  q=strchr(q,'/');
 };
 *p='\0';                       /* remove filename */
}

int main(int argc,char *argv[])
{
 TrapBadOps=0;LineDelay=1;CheckCRC=1; 
 VPeriod=69905;UPeriod=0;
 Verbose=1;

 memset (colorschemes,0,sizeof(colorschemes));
 memcpy (colorschemes,defcolorschemes,sizeof(defcolorschemes));
 SelectColorScheme (0);

 memset (MainConfigFile,0,sizeof(MainConfigFile));
 memset (SubConfigFile,0,sizeof(SubConfigFile));
 strlwr (argv[0]);
 GetPath (argv[0],ProgramPath);
 _argc=1;
 _argv[0]=argv[0];
/* Load Config Files */
 strcpy (szTempFileName,ProgramPath);
 strcat (szTempFileName,"vgb-dos.cfg");
 strcpy (szGifFile,ProgramPath);
 strcat (szGifFile,"vgb-dos.gif");
 LoadConfigFile (szTempFileName,MainConfigFile);
 if (!ParseOptions(_argc,_argv))
  return 1;
 GetCartName (argc,argv);
 FixFileNames ();
 strcpy (_SaveName,CartNameNoExt);
 strcat (_SaveName,".sav");
 SaveName=_SaveName;
 strcpy (szTempFileName,CartNameNoExt);
 strcat (szTempFileName,".cfg");
 _argc=1;
 LoadConfigFile (szTempFileName,SubConfigFile);
 if (!ParseOptions(_argc,_argv))
  return 1;
 if (!ParseOptions(argc,argv))
  return 1;

 IntSync=1;
 if (!IFreq)
 {
  IFreq=60;
  IntSync=0;
  if (!UPeriod) UPeriod=2;
 }
 if (IFreq<5) IFreq=5;
 if (IFreq>500) IFreq=500;

 StartGB(CartName);
 TrashGB();
 return(0);
}

