/* Copyright © 1995-1996 : David Atkinson */
/* V1.22 Allanim.c */
/* Calgor */

#include<hold/extra.h>
#include<hold/data.h>

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

#include<exec/types.h>

#include<graphics/rastport.h>
#include<graphics/sprite.h>

#include<clib/dos_protos.h>

#ifdef(V3)
#endif

typedef struct Rastport * RASTPTR;
typedef struct SimpleSprite * SSPTR;

TEXT txtstring[ARGLEN];

int ordersum[ARGNUM];
VARBUILD argument[ARGNUM];

extern void alert(TEXT *);
extern void clean_local(void);
extern void forward_move(MAPDEM [],MAPDEM,MAPDEM,SSPTR);
extern void backward_move(MAPDEM [],MAPDEM,MAPDEM,SSPTR);
extern void change_col(short);
extern void chill(int);
#ifdef TEST
extern void write_log(TEXT *,SHORT);
#endif

extern __aligned __chip struct SimpleSprite pulse_sprite;
extern __aligned __chip struct SimpleSprite cart_sprite;
extern PLAN array_map[FUNCMAX][MEMMAX];
extern PLAN dis_map[LEVEL][MAXACROSS];
extern PLAN ic_map[FUNCMAX][VARMAX];
extern FUNC func_index[FUNCMAX];
extern int fnum;
extern int raynum;
extern int types;
extern int dtype;
extern SHORT squeek[2];
extern BOOL keypress;
extern BOOL lmbpress;
extern UBYTE *keybufptr;
extern SHORT trip;
void whatisit(TEXT *);
void clean_args(void);
void al_clean(void);
void plan_clear(PLAN);
void itochar(int, TEXT []);
TEXT check_index(TEXT *);
PLAN lookup_ray(TEXT *,int);
PLAN lookup_var(TEXT *);
PLAN get_splan(int);
void get_road(PLAN);
int putback(TEXT *,int ,VALUE);
SHORT anim_button(void);
SHORT menu_buutton(void);

PLAN rec;
int realindex=0;

MAPDEM pathone[9] = { {290,24,START_U},{290,19,ALEFT},{270,19,ADOWN},
                         {270,73,ALEFT},{260,73,FIN_D},{260,80,TERMINAL},
                         {260,73,ALEFT},{68,73,FIN_D},{68,80,TERMINAL}
                    };

MAPDEM pathtwo[4] = { {602,190,START_D},{602,236,ALEFT},{0,0,TERMINAL},
                      {38,236,TERMINAL}
                    };

MAPDEM paththree[7] = { {602,190,START_D},{602,236,ALEFT},{0,0,TERMINAL},
                        {0,0,TERMINAL},{0,0,TERMINAL},
                        {68,236,FIN_U},{68,190,TERMINAL}
                      };


MAPDEM pathfour[3] = { {CARTX,CARTY,START_D},{0,0,FIN_R},{0,0,TERMINAL} };

MAPDEM pathfive[3] = { {38,236,ARIGHT},{68,236,FIN_U},{68,190,TERMINAL} };

MAPDEM backone[4] = { {68,190,START_D},{68,236,TERMINAL},{0,0,TERMINAL},
                     {0,0,TERMINAL}
                   };

TEXT index[MAXILEN];
TEXT oldname[MAXILEN];

void al_clean(void){
int k;

   #ifdef TEST
     write_log("al_clean STARTED\n",PRITWO);
   #endif
   for(k=0;k<ARGNUM;k++){
     if(argument[k].tname)
       free(argument[k].tname);
     if(argument[k].dexrep)
       free(argument[k].dexrep);
   }
   clean_args();
   #ifdef TEST
     write_log("al_clean PASSED\n",PRITWO);
   #endif
}


void plan_clear(PLAN aplan){
   aplan.worth.number = 0;
   aplan.p_name = NULL;
   aplan.points.x=0;
   aplan.points.y=0;
   aplan.points.way=TERMINAL;
   aplan.eol.x=0;
   aplan.eol.y=0;
   aplan.eol.way=TERMINAL;
   #ifdef TEST
     write_log("plan_clear PASSED\n",PRITHREE);
   #endif
}

void clean_args(void){
int i;

   for(i=0;i<ARGNUM;i++){
     argument[i].sign[0] = '\0';
     argument[i].sign[1] = '\0';
     argument[i].sign[2] = '\0';
     argument[i].tname = (TEXT *) NULL;
     argument[i].dexrep = (TEXT *) NULL;
   }
   #ifdef TEST
     write_log("clean_args PASSED\n",PRITHREE);
   #endif
}


/* Everytime whatisit is called it mallocs memory, therefore make sure memory is
   freed from system before we malloc another lot. Values are nulled in
   control.c via clean_args */

void whatisit(TEXT *thing){

TEXT cpar;
BOOL hit;
int foo,over,measure,arnum;

   arnum=over=0;
   #ifdef TEST
     write_log("whatisit Started\n",PRITHREE);
   #endif
   al_clean();
   cpar = *(thing + over);
   while( (cpar!='\0') && (arnum<ARGNUM) && (over<ARGLEN) ){
     hit=TRUE;
     foo=0;
     while(  ( (isalpha( (UBYTE) cpar )) || (cpar =='_') ) && (foo<ARGLEN-1) ){
       txtstring[foo]=cpar;
       foo++;
       over++;
       cpar = *(thing+over);
     }
     txtstring[foo]='\0';
     if(foo>0){
       if(argument[arnum].tname){
         clean_local();
         alert("Argument[arnum].tname ALREADY ALLOCATED!! (whatisit)\n");
       }
       argument[arnum].tname=(TEXT *) malloc(sizeof(TEXT) * (foo+1));
       if(argument[arnum].tname==NULL){
         clean_local();
         alert("Failed To Allocate Memory (A) (whatisit)\n");
       }
       for(measure=0;measure<=foo;measure++){
         *( (argument[arnum].tname) + measure) = txtstring[measure];
       }
     }
     while( ((cpar = *(thing+over))!='\0') && (over<ARGLEN) && (hit==TRUE) ){
       switch(cpar){
         case '0' : case '1': case '2': case '3': case '4': case '5':
         case '6': case '7' : case '8' : case '9' :
            if(argument[arnum].dexrep){
               clean_local();
               alert("Error in intrep \n");
            }
            foo=0;
            do {
                 txtstring[foo]=cpar;
                 foo++;
                 over++;
                 cpar=*(thing+over);
               }
            while( isdigit( (UBYTE) cpar) && (foo<ARGLEN) && (over<ARGLEN) );
            txtstring[foo]='\0';
            if(argument[arnum].dexrep){
              clean_local();
              alert("Argument[arnum].dexrep 1 ALREADY ALLOCATED!! (whatisit)\n");
            }
            argument[arnum].dexrep=(TEXT *) malloc(sizeof(TEXT) * (foo+1));
            if(argument[arnum].dexrep==NULL){
              clean_local();
              alert("Failed To Allocate Memory (B) (whatisit)\n");
            }
            for(measure=0;measure<foo;measure++){
              *(argument[arnum].dexrep + measure) = txtstring[measure];
            }
            break;
         case '[' :
           if(argument[arnum].dexrep!=NULL){
                clean_local();
                alert("Error in index (whatisit)\n");
           }
           foo=0;
           over++;
           while( (cpar=*(thing+over)) != ']'){
             txtstring[foo]=cpar;
             foo++;
             over++;
           }
           if(argument[arnum].dexrep){
             clean_local();
             alert("Argument[arnum].dexrep 2 ALREADY ALLOCATED!! (whatisit)\n");
           }
           argument[arnum].dexrep=(TEXT *) malloc(sizeof(TEXT) * (foo+1));
           if(argument[arnum].dexrep==NULL){
             clean_local();
             alert("Failed To Allocate Memory (C) (whatisit)\n");
           }
           for(measure=0;measure<foo;measure++){
             *(argument[arnum].dexrep + measure) = txtstring[measure];
           }
           *(argument[arnum].dexrep + measure) = '\0';
           over++;
           break;
         case '+' : case '-' : case '*' : case '/' :
           argument[arnum].sign[0] = cpar;
           over++;
           arnum++;
           hit=FALSE;
           cpar=*(thing+over);
           while( isspace((UBYTE) cpar) ){
             over++;
             cpar = *(thing+over);
           }
           break;
         case '<' : case '>' : case '=' : case '!' :
           argument[arnum].sign[0] = cpar;
           over++;
           if (*(thing+over)== '='){
             argument[arnum].sign[1] = *(thing+over);
             over++;
           }
           arnum++;
           hit=FALSE;
           cpar=*(thing+over);
           while( isspace((UBYTE) cpar) ){
             over++;
             cpar = *(thing+over);
           }
           break;
         default :
           if(isspace( (UBYTE) cpar) != 0){
             while( isspace((UBYTE) cpar) ){
               over++;
               cpar = *(thing+over);
             }
           }
           else{
             printf("Unknown Token: %c\n",cpar);
             clean_local();
             alert("Did not recognise TOKEN (Whatisit)\n");
           }
           break;
       }
     }
   }
   #ifdef TEST
     write_log("whatisit PASSED\n",PRITHREE);
   #endif
}

/* Check_index Goes through the function array, checking the expected
   name with the function name, returning the function index.  Check
   for NULL as strcmp doesn't like to be given them */

TEXT check_index(TEXT *title){
int q;
TEXT times = 'A';
   for(q=0;q<FUNCMAX;q++){
     if((func_index[q].f_label!=NULL) && (title!=NULL)){
       if ( strcmp(func_index[q].f_label,title) == 0 )
         ++times;
     }
   }
   #ifdef TEST
     write_log("check_index PASSED\n",PRITHREE);
   #endif
   return times;
}

PLAN lookup_ray(TEXT *target,int con){

   plan_clear(rec);
   if((array_map[raynum][con].p_name!=NULL) && (target!=NULL) ){
     if( strcmp(array_map[raynum][con].p_name,target) == 0 ){
       if( (raynum>= ARRAYMAX) || (con>=MAXACROSS) ){  /* Should be con>=MEMMAX in V1.21 */
         clean_local();
         alert("Exceeded Limits (lookup_ray)\n");
       }
       rec = dis_map[raynum][con];
       rec.p_name=array_map[raynum][con].p_name; /* Get Name */
       rec.worth.number=array_map[raynum][con].worth.number;  /* Get Value */
     }
   }
   #ifdef TEST
     write_log("lookup_ray PASSED\n",PRITHREE);
   #endif
   return rec;
}

PLAN lookup_var(TEXT *target){
int m;

   plan_clear(rec);
   for(m=0;m<VARMAX;m++){
     if( (target!=NULL) && (ic_map[fnum][m].p_name!=NULL)){
       if(strcmp(target,ic_map[fnum][m].p_name) == 0 )
          rec=ic_map[fnum][m];
     }
   }
   #ifdef TEST
     write_log("lookup_var PASSED\n",PRITHREE);
   #endif
   return rec;
}

int putback(TEXT *prop,int post,VALUE part){
int err=0;
int r;

   if( (prop!=NULL) && (array_map[raynum][post].p_name!=NULL) ){
     if(strcmp(prop,array_map[raynum][post].p_name)==0){
       array_map[raynum][post].worth.number=part.number;
       err=1;
     }
   }
   for(r=0;r<VARMAX;r++){
     if( (prop!=NULL) && (ic_map[fnum][r].p_name!=NULL) ){
       if(strcmp(prop,ic_map[fnum][r].p_name)==0){
         ic_map[fnum][r].worth.number=part.number;
         err=1;
       }
     }
   }
   #ifdef TEST
     write_log("PutBack PASSED\n",PRITHREE);
   #endif
   return err;
}


void itochar(int subject, TEXT hold[])
{
int calc,newnum,element,neg;

   neg=element=calc=newnum=0;
   if(subject<0){
     hold[0]='-';
     element++;
     neg=1;
   }
   newnum=abs(subject);
   do {
      newnum /= 10;
      element++;
      } while(newnum>0);

   if (element <=OBVAR ){
     hold[element]='\0';
     newnum=abs(subject);
     element--;
     while(element >= neg){
       calc = newnum % 10;
       newnum /= 10;
       hold[element] = (TEXT) (calc+48);
       element--;
     }
  }
  else{
    hold[0]='-';
    hold[1]='\0';
  }
  #ifdef TEST
    write_log("itochar PASSED\n",PRITHREE);
  #endif
}

/* PLAN get_splan takes an integer which is the index to the VARBUILD argument
   array and returns coordinates of the evaluted expression.
   Get_splan evaluates integers, integer variables, array with integer index,
   array with variable index but only to the first level. A quick fix has been made
   so array index with integer offset is now possible.  Due to this fix the argument
   array may be altered, so whatisit will have to be called to restantiate
   the argument array */

PLAN get_splan(int jump){
int sheep;
int contents;
BOOL set=TRUE;

   plan_clear(rec);
   if (argument[jump].tname==NULL){
     /*  String is a number */
     /*  For version V1.21 take a look at negative sign and assign value here */
     /*  At the moment if this was done, get 1-(-1) giving incorrect answer */
     rec.p_name="absolute";
     if(argument[jump].dexrep!=NULL)
        rec.worth.number=atoi(argument[jump].dexrep);
     else
        rec.worth.number = 0;
     rec.points.x=68;
     rec.points.y=236;
     rec.points.way=FIN_U;
     rec.eol.x=68;
     rec.eol.y=190;
     rec.eol.way=TERMINAL;
     types = ICABS;
     realindex=0;
   }
   if( (argument[jump].tname!=NULL) && (argument[jump].dexrep!=NULL) ){
     /* The string is an array */
     for(sheep=0;sheep<strlen(argument[jump].dexrep);sheep++){
       contents = (int) *(argument[jump].dexrep+sheep);
       index[sheep] = *(argument[jump].dexrep+sheep);
       if( isdigit((UBYTE)contents) == 0 ){
         set=FALSE;
       }
     }
     index[sheep] = '\0';
     for(sheep=0;sheep<strlen(argument[jump].tname);sheep++){
       oldname[sheep] = *(argument[jump].tname+sheep);
     }
     oldname[sheep] = '\0';

     if(set==TRUE){
       /* the index is an absolute number */
       realindex=atoi(argument[jump].dexrep);
       rec=lookup_ray(argument[jump].tname,realindex);
     }
     else{
       /* the index is a variable or variable with offset */
       /* al_clean(); */
       whatisit(index);
       switch(argument[0].sign[0]){
         case '\0' :
           /* Index is variable */
           rec=lookup_var(argument[0].tname);
           realindex=rec.worth.number;
           rec=lookup_ray(oldname,realindex);
           break;
         case '+' :
           /* Index is varible with addition offset */
           rec=lookup_var(argument[0].tname);
           realindex=rec.worth.number+atoi(argument[1].dexrep);
           rec=lookup_ray(oldname,realindex);
           break;
         case '-' :
           /* Index is variable with negative offset */
           rec=lookup_var(argument[0].tname);
           realindex=rec.worth.number - atoi(argument[1].dexrep);
           rec=lookup_ray(oldname,realindex);
           break;
         case '*' :
           /* Index is variable with product offset */
           rec=lookup_var(argument[0].tname);
           realindex=rec.worth.number * atoi(argument[1].dexrep);
           rec=lookup_ray(oldname,realindex);
           break;
         case '/' :
           /* Index is variable with divide offset */
           rec=lookup_var(argument[0].tname);
           realindex=rec.worth.number / atoi(argument[1].dexrep);
           rec=lookup_ray(oldname,realindex);
           break;
         default :
           clean_local();
           alert("Sign not recognised (get_splan)\n");
           break;
       }
     }
     if(rec.p_name==NULL){
       clean_local();
       alert("Error in assigning index to array (get_splan)\n");
     }
     types=ICRAY;
     al_clean();
     #ifdef TEST
       write_log("get_splan pt A PASSED\n",PRITHREE);
     #endif
     return rec;
   }
   if( (argument[jump].tname!=NULL) && (argument[jump].dexrep==NULL) ){
    /* String is a variable */
     rec=lookup_var(argument[jump].tname);
     if(rec.p_name==NULL){
       clean_local();
       alert("Error in assigning variable (get_splan)\n");
     }
     types=ICVAR;
     realindex=0;
   }
   al_clean();
   #ifdef TEST
     write_log("get splan pt B PASSED\n",PRITHREE);
   #endif
   return rec;
}

void get_road(PLAN route){

   change_col( (short) GET);
   switch(types){
     case ICVAR :
       paththree[2]=route.points;
       paththree[2].way=ADOWN;
       paththree[3]=route.eol;
       paththree[3].way = AUP;
       paththree[4]=route.points;
       paththree[4].way=ALEFT;
       forward_move(paththree,paththree[0],paththree[6],&pulse_sprite);
       break;
     case ICRAY :
       pathtwo[2].x=68;
       pathtwo[2].y=236;
       pathtwo[2].way=FIN_L;
       pathtwo[3].x=38;
       pathtwo[3].y=236;
       pathtwo[3].way=TERMINAL;
       pathfour[1]=route.points;
       pathfour[2]=route.eol;
       forward_move(pathtwo,pathtwo[0],pathtwo[3],&pulse_sprite);
       forward_move(pathfour,pathfour[0],pathfour[2],&cart_sprite);
       chill(LSTILL/trip);
       backward_move(pathfour,pathfour[2],pathfour[0],&cart_sprite);
       forward_move(pathfive,pathfive[0],pathfive[2],&pulse_sprite);
       break;
     case ICABS :
       pathtwo[2]=route.points;
       pathtwo[3]=route.eol;
       forward_move(pathtwo,pathtwo[0],pathtwo[3],&pulse_sprite);
       break;
     default :
       clean_local();
       alert("ERROR In (get_road)\n");
       break;
  }
  #ifdef TEST
    write_log("get_road PASSED\n",PRITHREE);
  #endif
}

/* anim_button examines the coordinates from the mouse handler and returns
   the according button value */

SHORT anim_button(void){
    #ifdef TEST
      write_log("anim_button Entered\n",PRITHREE);
    #endif
    if(lmbpress==TRUE){
      if ( (squeek[0] >= Kstop.min.xc) && (squeek[0] <= Kstop.max.xc) &&
           (squeek[1] >= Kstop.min.yc) && (squeek[1] <= Kstop.max.yc) )
           return STOPBUT;
      if ( (squeek[0] >= Kplay.min.xc) && (squeek[0] <= Kplay.max.xc) &&
           (squeek[1] >= Kplay.min.yc) && (squeek[1] <= Kplay.max.yc) )
           return PLAYBUT;
      if ( (squeek[0] >= Keject.min.xc) && (squeek[0] <= Keject.max.xc) &&
           (squeek[1] >= Keject.min.yc) && (squeek[1] <= Keject.max.yc) )
           return EJECTBUT;
      if ( (squeek[0] >= Kpause.min.xc) && (squeek[0] <= Kpause.max.xc) &&
           (squeek[1] >= Kpause.min.yc) && (squeek[1] <= Kpause.max.yc) )
           return PAUSEBUT;
      if ( (squeek[0] >= Kinfo.min.xc) && (squeek[0] <= Kinfo.max.xc) &&
           (squeek[1] >= Kinfo.min.yc) && (squeek[1] <= Kinfo.max.yc) )
           return INFOBUT;
      if ( (squeek[0] >= Kffor.min.xc) && (squeek[0] <= Kffor.max.xc) &&
           (squeek[1] >= Kffor.min.yc) && (squeek[1] <= Kffor.max.yc) )
           return FFORBUT;
    }
    if(keypress==TRUE){
      if(keybufptr!=NULL){
        if ( *(keybufptr+0)==0x31 )
          return NUM1KEY;
        if ( *(keybufptr+0)==0x32 )
          return NUM2KEY;
        if ( *(keybufptr+0)==0x33 )
          return NUM3KEY;
        if ( *(keybufptr+0)==0x34 )
          return NUM4KEY;
        if ( *(keybufptr+0)==0x35 )
          return NUM5KEY;
        if(  *(keybufptr+0)==0x1B )
          return ESCKEY;
      }
    }
    #ifdef TEST
      write_log("anim_button Returned NOBUT\n",PRITHREE);
    #endif
    return NOBUT;
}

SHORT menu_button(void){
  #ifdef TEST
    write_log("menu_button Entered\n",PRITHREE);
  #endif
  if(lmbpress==TRUE){
    if ( (squeek[0] > Kf1.min.xc) && (squeek[0] < Kf1.max.xc) &&
         (squeek[1] > Kf1.min.yc) && (squeek[1] < Kf1.max.yc) )
         return F1BUTTON;
    if ( (squeek[0] > Kf2.min.xc) && (squeek[0] < Kf2.max.xc) &&
         (squeek[1] > Kf2.min.yc) && (squeek[1] < Kf2.max.yc) )
         return F2BUTTON;
    if ( (squeek[0] > Kf3.min.xc) && (squeek[0] < Kf3.max.xc) &&
         (squeek[1] > Kf3.min.yc) && (squeek[1] < Kf3.max.yc) )
         return F3BUTTON;
    if ( (squeek[0] > Kf4.min.xc) && (squeek[0] < Kf4.max.xc) &&
         (squeek[1] > Kf4.min.yc) && (squeek[1] < Kf4.max.yc) )
         return F4BUTTON;
    if ( (squeek[0] > Kf5.min.xc) && (squeek[0] < Kf5.max.xc) &&
         (squeek[1] > Kf5.min.yc) && (squeek[1] < Kf5.max.yc) )
         return F5BUTTON;
    if ( (squeek[0] > Kn1.min.xc) && (squeek[0] < Kn1.max.xc) &&
         (squeek[1] > Kn1.min.yc) && (squeek[1] < Kn1.max.yc) )
         return NUM1KEY;
    if ( (squeek[0] > Kn2.min.xc) && (squeek[0] < Kn2.max.xc) &&
         (squeek[1] > Kn2.min.yc) && (squeek[1] < Kn2.max.yc) )
         return NUM2KEY;
    if ( (squeek[0] > Kn3.min.xc) && (squeek[0] < Kn3.max.xc) &&
         (squeek[1] > Kn3.min.yc) && (squeek[1] < Kn3.max.yc) )
         return NUM3KEY;
    if ( (squeek[0] > Kn4.min.xc) && (squeek[0] < Kn4.max.xc) &&
         (squeek[1] > Kn4.min.yc) && (squeek[1] < Kn4.max.yc) )
         return NUM4KEY;
    if ( (squeek[0] > Kn5.min.xc) && (squeek[0] < Kn5.max.xc) &&
         (squeek[1] > Kn5.min.yc) && (squeek[1] < Kn5.max.yc) )
         return NUM5KEY;
    if ( (squeek[0] > KES.min.xc) && (squeek[0] < KES.max.xc) &&
         (squeek[1] > KES.min.yc) && (squeek[1] < KES.max.yc) )
         return ESCKEY;
  }
  if(keypress==TRUE){
    if(keybufptr!=NULL){
      if ( (*(keybufptr+0)==0x9B) && (*(keybufptr+1)==0x30) && (*(keybufptr+2)==0x7e) )
        return F1BUTTON;
      if ( (*(keybufptr+0)==0x9B) && (*(keybufptr+1)==0x31) && (*(keybufptr+2)==0x7e) )
        return F2BUTTON;
      if ( (*(keybufptr+0)==0x9B) && (*(keybufptr+1)==0x32) && (*(keybufptr+2)==0x7e) )
        return F3BUTTON;
      if ( (*(keybufptr+0)==0x9B) && (*(keybufptr+1)==0x33) && (*(keybufptr+2)==0x7e) )
        return F4BUTTON;
      if ( (*(keybufptr+0)==0x9B) && (*(keybufptr+1)==0x34) && (*(keybufptr+2)==0x7e) )
        return F5BUTTON;
      if ( *(keybufptr+0)==0x31 )
        return NUM1KEY;
      if ( *(keybufptr+0)==0x32 )
        return NUM2KEY;
      if ( *(keybufptr+0)==0x33 )
        return NUM3KEY;
      if ( *(keybufptr+0)==0x34 )
        return NUM4KEY;
      if ( *(keybufptr+0)==0x35 )
        return NUM5KEY;
      if(  *(keybufptr+0)==0x1B )
        return ESCKEY;
    }
  }
  #ifdef TEST
    write_log("menu_button Returned NOBUT\n",PRITHREE);
  #endif
  return NOBUT;
}
