#include "xmris.h"

/************************************************************************/

const ULONG StackSize=20000;

/************************************************************************/

struct DosLibrary *DOSBase;
struct Library *UtilityBase;

/************************************************************************/

static struct RDArgs *RDArgs;
static struct
{
  char *ASCIIFile;
  char *GardenFile;
} Arguments;

static BPTR ASCIIFile;
static BPTR GardenFile;

static unsigned TheNumber;
static char TheString[CELLS_ACROSS+1];

/************************************************************************/

#define TOKEN_EOF	-1
#define TOKEN_NUMBER	-2
#define TOKEN_STRING	-3

/************************************************************************/

static void CloseAll(int, LONG, const char *) NORETURN;

static void CloseAll(int RC, LONG Error, const char *String)

{
  if (GardenFile!=MKBADDR(NULL))
    {
      if (!Close(GardenFile))
	{
	  if (RC==RETURN_OK)
	    {
	      RC=RETURN_ERROR;
	      Error=IoErr();
	    }
	  DeleteFile(Arguments.GardenFile);
	}
      else
	{
	  SetProtection(Arguments.GardenFile,FIBF_EXECUTE);
	}
    }
  if (ASCIIFile!=MKBADDR(NULL))
    {
      Close(ASCIIFile);
    }
  if (RC!=RETURN_OK)
    {
      if (Error!=0)
	{
	  PError(Error,String);
	}
      else
	{
	  VFPrintf(ErrorHandle(),"%s\n",&String);
	}
    }
  if (RDArgs!=NULL)
    {
      FreeArgs(RDArgs);
    }
  CloseStdErr();
  CloseLibrary(UtilityBase);
  CloseLibrary(&DOSBase->dl_lib);
  MyExit(RC,Error);
}

/************************************************************************/

static int ReadToken(int Expected)

{
  int Token;
  LONG c;

  while ((c=FGetC(ASCIIFile))==' ' || c=='\t' || c=='\n')
    ;

  if (c==-1)
    {
      LONG Error;

      Error=IoErr();
      if (Error==0)
	{
	  Token=TOKEN_EOF;
	  goto Done;
	}
      CloseAll(RETURN_ERROR,Error,Arguments.ASCIIFile);
    }

  if (c=='/')
    {
      c=FGetC(ASCIIFile);
      if (c=='*')
	{
	  do
	    {
	      while ((c=FGetC(ASCIIFile))!='*' && c!=-1)
		;
	    }
	  while (c!=-1 && (c=FGetC(ASCIIFile))!='/');
	  if (c==-1)
	    {
	      LONG Error;

	      Error=IoErr();
	      if (Error==0)
		{
		  Token=TOKEN_EOF;
		  goto Done;
		}
	      CloseAll(RETURN_ERROR,Error,Arguments.ASCIIFile);
	    }
	  return ReadToken(Expected);
	}
      UnGetC(ASCIIFile,c);
      Token='/';
      goto Done;
    }

  if (c=='"')
    {
      int i;

      i=0;
      while ((c=FGetC(ASCIIFile))!='"' && i<sizeof(TheString) && c!=-1)
	{
	  TheString[i++]=c;
	}
      if (c=='"' && i==12)
	{
	  Token=TOKEN_STRING;
	  goto Done;
	}
      if (c==-1)
	{
	  LONG Error;

	  Error=IoErr();
	  if (Error!=0)
	    {
	      CloseAll(RETURN_ERROR,Error,Arguments.ASCIIFile);
	    }
	}
      CloseAll(RETURN_ERROR,0,"String is too long or not terminated. Must be exactly 12 characters.");
    }

  if (isdigit(c))
    {
      TheNumber=c-'0';
      while ((c=FGetC(ASCIIFile))>='0' && c<='9' && c!=-1)
	{
	  TheNumber=10*TheNumber+(c-'0');
	}
      UnGetC(ASCIIFile,c);
      Token=TOKEN_NUMBER;
      goto Done;
    }

  Token=c;

 Done:
  if (Expected!='\0' && Token!=Expected)
    {
      CloseAll(RETURN_ERROR,0,"Syntax error");
    }
  return Token;
}

/************************************************************************/

static void WriteData(void *Data, LONG Size)

{
  if (FWrite(GardenFile,Data,Size,1)!=1)
    {
      CloseAll(RETURN_ERROR,IoErr(),Arguments.GardenFile);
    }
}

/************************************************************************/

static INLINE void ConvertGarden(void)

{
  int i;
  int Token;
  BOARD Board;

  ReadToken(TOKEN_NUMBER);
  Board.fill=TheNumber;
  ReadToken(',');
  ReadToken(TOKEN_NUMBER);
  Board.colors=TheNumber;
  ReadToken(',');
  ReadToken(TOKEN_NUMBER);
  Board.apples=TheNumber;
  ReadToken(',');
  ReadToken('{');
  for (i=0; i<CELLS_DOWN; i++)
    {
      ReadToken(TOKEN_STRING);
      strcpy(Board.map[i],TheString);
      ReadToken(',');
    }
  Token=ReadToken(0);
  if (Token==',')
    {
      Token=ReadToken(0);
    }
  if (Token!='}')
    {
      CloseAll(RETURN_ERROR,0,"Syntax error");
    }
  WriteData(&Board,sizeof(Board));
}

/************************************************************************/

static INLINE void ConvertFile(void)

{
  int Token;

  do
    {
      Token=ReadToken(0);
      if (Token=='{')
	{
	  ConvertGarden();
	  ReadToken('}');
	  Token=ReadToken(0);
	}
    }
  while (Token==',');
  if (Token!=TOKEN_EOF)
    {
      CloseAll(RETURN_ERROR,0,"Syntax error");
    }
}

/************************************************************************/

static INLINE void Init(void)

{
  if (WorkbenchMessage!=NULL ||
      (DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",ROM_VERSION))==NULL)
    {
      MyExit(RETURN_CATASTROPHY,0);
    }
  if ((UtilityBase=OpenLibrary("utility.library",ROM_VERSION))==NULL)
    {
      CloseAll(RETURN_CATASTROPHY,0,NULL);
    }
  if ((RDArgs=ReadArgs("ASCIIFILE/A,GARDENFILE/A",(LONG *)&Arguments,NULL))==NULL)
    {
      CloseAll(RETURN_FAIL,IoErr(),NULL);
    }
  if ((ASCIIFile=Open(Arguments.ASCIIFile,MODE_OLDFILE))==MKBADDR(NULL))
    {
      CloseAll(RETURN_ERROR,IoErr(),Arguments.ASCIIFile);
    }
  if ((GardenFile=Open(Arguments.GardenFile,MODE_NEWFILE))==MKBADDR(NULL))
    {
      CloseAll(RETURN_ERROR,IoErr(),Arguments.GardenFile);
    }
}

/************************************************************************/

void AmigaMain(void)

{
  Init();
  WriteData("mris Garden!",12);
  ConvertFile();
  CloseAll(RETURN_OK,0,NULL);
}
