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

#define NUMBER	"*number*"
#define IMAGE	"*image*"
#define CANVAS	' '
#define BACK	'-'
#define	FORE	'#'	

int showimage=1;

char *dict[]={
      "A",NUMBER,	/* Base 6 Numeral */
      "B",NUMBER,	/* Base 6 Numeral */
      "C",NUMBER,	/* Base 6 Numeral */
      "D",NUMBER,	/* Base 6 Numeral */
      "E",NUMBER,	/* Base 6 Numeral */
      "F",NUMBER,	/* Base 6 Numeral */
      "G"," | ",	/* Phrase delimiter */
      "H"," :PLUS: ",	/* aHbHc 	a+c=b */
      "I"," :SUB+: ",	/* aIbIc	mod (a-c)=b */
      "J"," :SUB-: ",	/* aJbJc	-mod (a-c)=b */
      "K",NUMBER,	/* Kak		Negation (-a) */
      "L"," :MULT: ",	/* aLbLc	a*c=b */
      "M"," :DIV+: ",	/* aMbMc	max(a,c)/min(a,c)=b */
      "N"," :DIV/: ",	/* aNbNc	min(a,c)/max(a,c)=b */
      "O",NUMBER,	/* Oa0		Reciprocal (1/a) */
      "P"," :EQ: ",	/* aPb		a is equivalent to b */
      "Q",NUMBER,	/* Q...Q	... is interpreted as a number */
      "R"," :TRUE: ",	/* R...R	Statement ... is TRUE */
      "S"," :FALSE: ",	/* S...S	Statement ... is FALSE */
      "T"," :SUB<: ",	/* aTbTc	c-a=b */
      "U"," :SUB>: ",	/* aUbUc	a-c=b */
      "V"," :IF: ",	/* V...V	IF ... */
      "W"," :THEN: ",	/* W...W	THEN ... */
      "X","X",		/* Variable */
      "Y","Y",		/* Variable */
      "Z","Z",		/* Variable */
      "a","a",		/* Variable */
      "b","b",		/* Variable */
      "c","c",		/* Variable */
      "d",NUMBER,	/* d		Heximal Point */
      "e"," :DIV>: ",	/* aebec	a/c=b */
      "f"," :DIV<: ",	/* aebec	c/a=b */
      "g","ang",	/* g...g	... is interpreted as an angle */
      "h"," :SIN: ",	/* ahbha	a=sin(b) */
      "i"," :AND: ",	/* aibic	a AND c = b */
      "j"," :OR: ",	/* ajbjc	a OR c = b */
      "k"," :COS: ",	/* akbka	a=cos(b) */
      "l","PI",		/* l		PI */
      "m","UDEF",	/* m		Undefined/Infinity */
      "n",IMAGE,	/* n...n	... is a hexagonal raster image */
      "o",IMAGE,	/* o...o	... is a rectangular raster image */
      "p"," :RADIUS:",	/* 		UNKNOWN OPERATOR */
      "q"," :START:",	/* 		UNKNOWN OPERATOR */
      "r"," :END:",	/* 		UNKNOWN OPERATOR */
      "s"," :GT: ",	/* asbsa	b>a */
      "t"," :LT: ",	/* atbta	b<a */
      "u"," :GT=: ",	/* aubua	b>=a */
      "v"," :LT=: ",	/* avbva	b<=a */
      /* xyz1234 	Tone Vocabulary */
      "5"," :POW: ",	/* Power operator */
      "6"," :NEQ: ",	/* a6b		a is not equivalent to b */
      /* 7890		Tone Vocabulary */
      "0","'Cetean'",	/* WORD - A Cetean */
      "1y1","'Planet'",	/* WORD - A Cetean */
      "2","'TC I'",	/* WORD - A Cetean */
      "797","'TC II'",	/* WORD - A Cetean */
      "898","'TC III'",	/* WORD - A Cetean */
      "323","'TC IV'",	/* WORD - A Cetean */
      "434","'TC V'",	/* WORD - A Cetean */
      "4y4","'TC VI'",	/* WORD - A Cetean */
      "xzx","'zxz'",	/* WORD - A Cetean */
      "wyw","'wyw'",	/* WORD - A Cetean */
      "zyz","'zyz'",	/* WORD - A Cetean */
      "%","TIME",	/* Time */
      "!%!","time",	/* A number of ticks */
      "@","DIST",	/* Distance */
      "!@!","dist",	/* A number of cetemeters */
      "$","SPD",	/* Speed */
      "!$!","spd",	/* A number of cetemeters/second */
      "#","e",		/* Scientific Notation */
      "*","c",		/* Physical Constant - Speed of Light */
      "!Q!","num",	/* An abstract number */
            };
int ndict=sizeof(dict)/sizeof(dict[0])/2;

int decodefile (FILE *fP);
int decodestr (char *string,int line,int length,int indent);
int substitute (char *str);
int decodenumber (char *str, int length);
int checksym (char *numstr, int length);
int decodeimage (char *str);
int imagehex (char *img, int length);
int imagerect (char *img, int length);

int main (int argc, char *argv[])
{
   FILE *fP;		/* Pointer to file to decode */
   int curfile=1;	/* Sequential Number of file decoding */
   
   if (argc<2)
   {
      fprintf (stderr,"Need At Least One File To Open\n");
      return (1);
   }
   else
   {
      while (curfile<argc)
      {
         if ( (fP=fopen (argv[curfile],"r")) == NULL)
	 {
	    printf ("Unable to open [%s]\n",argv[curfile]);
	 }
	 else
	 {
            printf ("\n----- DECODING FILE [%s] -----\n",argv[curfile]);
	    if (decodefile (fP)!=0)
	    {
	       printf ("Errors occured during decode\n");
	    }  
	 }
         curfile++;
      }
   }	    
   
   return (0);
}

int decodefile (FILE *fP)
{
   int retval=0;
   char string[1024];
   int idx;
   int line=0;
   int indent=0;
   
   while (1)
   {
      line++;
      idx=0;
      
      while ( (string[idx]=fgetc (fP)) != 'G')
      {
         if (feof(fP)) goto done;
      }
      
      idx++;
      
      while ( (string[idx]=fgetc (fP)) == 'G' || isspace(string[idx]))
      {
      }

      idx++;
      
      while ( (string[idx]=fgetc (fP)) != 'G')
      {
         if (isspace (string[idx]))
	 {
	    idx--;
	 }
         if (feof(fP))
	 {
	    printf ("Line [%d] is unfinished\n",line);
	    retval=1;
	    goto done;
	 }
	 idx++;
      }
      
      idx++;
      
      string[idx]='\0';         
      
      /* We have a string - decode it */
      decodestr (string,line,(idx-1),indent);

  }
	       
   done:
   return (retval);
}
   
int decodestr (char *string,int line,int length,int indent)
{
   int retval=0;
   int front=0;		/* Position at start of message line */
   int back=length;	/* Position at end of message line */
   int subs;
   int rem;

   printf ("%03d ",line);

   while (front<=length)
   {
      if ( (subs=substitute(&string[front])) > 0)
      {
         front+=subs;
      }   
      else 
      {
         printf ("%c",string[front]);
	 front++;
      }
   }
   
   printf ("\n");

   return (retval);
}

int substitute (char *str)
{
   int n;	
   int length;
   int isunary=0;	/* Special Case For String Of 'B's */
	       
   for (n=0;n<(ndict*2);n+=2)
   {
      if (strncmp (dict[n],str,strlen(dict[n]))==0)
      {
         if (strcmp (dict[n+1],NUMBER)==0)
	 {
	    /* Found a number */
	    length=strlen (dict[n]);
	    while (n>=0)
	    {
               for (n=0;n<(ndict*2);n+=2)
               {
                  if (strncmp (dict[n],(str+length),strlen(dict[n]))==0)
                  {
                     if (strcmp (dict[n+1],NUMBER)==0)
	             {
		        length+=strlen (dict[n]);
			break;
	             }
		     else
		     {
                        n=-1;
			break;
	             }
		  }
	       }
	    }
 
	    while (checksym (str,length)!=0)
	    {
	       length--;
            }
	    
	    decodenumber (str, length);   
	    return (length);
	 }
	 else if (strcmp (dict[n+1],IMAGE)==0)
         {
	    /* Found an image */
	    return (decodeimage (str));
	 }
	 else
	 {       
            /* Just a piece of vocabulary */
	    printf ("%s",dict[n+1]);
            return (strlen (dict[n]));
         }
      }
   }
   
   done:
   return (0);

}

int checksym (char *str, int length)
{
   int n;

   if (length==1) return 0;

   for (n=0;n<(length+1)/2;n++) 
   {
      if ( *(str+n)!=*(str+(length-1-n)) )
      {
         return 1;
      }
   }
   return (0);
}


int decodenumber (char *str, int length)
{
   int n,m;
   char numstr[1024];
   char *pos=&numstr[0];
   char qseen=0;
   int predp=0;
   int aftdp=0;
   int preval=0;
   float aftval=0;
   int unary=1;
   
   strncpy (&numstr,str,length);
   numstr[length]='\0';
   
   /* printf ("(%s, ",numstr); */

   while (*pos=='K' || *pos=='O' || *pos=='Q')
   {
      if (*pos=='K') printf ("-"), pos++;
      if (*pos=='O') printf ("1/"), pos++;
      if (*pos=='Q') qseen=1, pos++;
   }
   
   while (*(pos+predp)>='A' && *(pos+predp)<='F')
   {
      if ( *(pos+predp) != 'B' ) unary=0;
      predp++;
   }
   
   if (unary==1 && qseen==0)
   {
      preval=predp;
      pos+=predp;
   }
   else
   {
      for (n=((predp+1)/2);n>0;n--)
      {
         preval+=(*pos-'A')*pow (6,(n-1));
         pos++;
      }
      pos+=predp/2;
   }
      
   if (*pos=='d')
   {
      *pos++;
      while (*(pos+aftdp)>='A' && *(pos+aftdp)<='F')
      {
         aftdp++;
      }
      for (n=0;n<((aftdp+1)/2);n++)
      {
         aftval+=(*pos-'A')/pow (6,(n+1));
         pos++;
      }
      pos+=aftdp/2;
   }
      
   if (aftdp==0)
   {
      if (predp!=0)
      {
         printf ("%d",preval);
      }
   }
   else
   {
      printf ("%.3f",(float) aftval+preval);
   }

   /* printf (")"); */
   
   return;
}

int decodeimage (char *str)
{
   char *tmp=str;
   int length=0;

   str++;
   while (*str!=*tmp) str++, length++;
   
   if (showimage==0)
   {
      printf (" :IMG[%c%03d]: ",*tmp,length);
   }
   else
   {
      /* Display Image Here */
      if (*tmp=='o')
      {
         imagehex (tmp+1,length);
      }
      else if (*tmp=='n')
      {
         imagerect (tmp+1,length);
      }
      else
      {
         printf (" :IMG[%c%03d]: ",*tmp,length);
      }  
   
   }

   return (length+2);
}

int imagehex (char *img, int length)
{
   int width=0;
   int height=0;
   int n,m,i;
   int mag=0;
   int x,y;
   char *result=NULL;
   static int xd[]={-1,-2,-1,+1,+2,+1};
   static int yd[]={+1,0,-1,-1,0,+1};
   
   while (mag<length)
   {
      if (height==0)
      {
         height++;
	 mag++;
      }
      else
      {
	 mag+=(int) (6.0*(1.0*height+1.0)/2.0);
         height+=2;
      }
   }
      
   if (mag!=length)
   {
      printf ("\n:[IMG-ERROR]:\n");
      return;
   }
   width=(height*2);
    
   result=(char *) malloc (sizeof (char)*((width*height)+1));
   memset (result,CANVAS,width*height);

   for (n=1;n<height;n++)
   {
      result[width*n-1]='\n';
   }
   result [width*height-1]='\n';
   result [(width*height)]='\0';

   printf ("\n");
   
   x=(int) 1.0*width/2.0-1;
   y=(int) 1.0*height/2.0;
      
   if (*img=='B') result[(y*width)+x]=FORE;
   else result[(y*width)+x]=BACK;
   img++; 
      
   for (n=0;n<=(int) (1.0*height/2.0);n++)
   {
      for (m=0;m<6;m++)
      {
	 for (i=1;i<=n;i++)
	 {
	    if (*img=='B')  result[(y*width)+x]=FORE;
	    else result[(y*width)+x]=BACK;
	    img++;
	    x+=xd[m];
	    y+=yd[m];
	 }
      }
      x+=xd[4];
      y+=yd[4];
   }
   
   printf ("%s",result);
   free (result);

   return;
   
}

int imagerect (char *img, int length)
{
   int width=length;
   int height=1;
   int n,m;
   
   while ((width--)>0)
   {
      if (length%width==0) break;
   }
   
   if (width<2)
   {
      height=1;
      width=length;
   }
   else
   {
      height=length/width;
   }

   printf ("\n");
   
   for (n=1;n<=height;n++)
   {
      for (m=1;m<=width;m++)
      {
         if (*img=='B') printf ("%c",FORE),printf ("%c",CANVAS);
	 else printf ("%c",BACK),printf ("%c",CANVAS);
         img++;
      }
      printf ("\n");
   }
   
   return;
   
}

