#include <exec/types.h>
#include <intuition/intuition.h>

struct paar { int knotentyp;
              WORD *CAR,*CDR;
            };
struct atom { int knotentyp;
              char zeichenkette[2];
            };
struct bruch { int knotentyp;
               char kennung[2];
               int zaehler,nenner;
             };
struct dezimal{int knotentyp;
               char kennung[2];
               float wert;
              };
extern WORD *wahr;

#define new(a) a=neu((ULONG)sizeof(int)+8L)
#define pi 6.2832

extern BYTE genug_parameter();
extern void fehler();
extern void delete(),dispose();
extern WORD *neu(),*evaluate();
extern WORD *leeres_atom;
extern float sin(),cos(),getfloat();
extern int getint();

/* Modul für Turtle - Graphics */

extern LONG OpenLibrary();
extern struct Window *OpenWindow();
extern struct Screen *OpenScreen();
struct Screen *GScreen;
extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
extern void Move(),Draw(),WritePixel();

struct NewWindow NewGWindow =
{ 200,0,440,204,2,1,NULL,NULL,NULL,NULL,"",NULL,NULL,
  440,204,440,204,WBENCHSCREEN };

struct NewScreen NewGScreen =
{ 0,0,640,256,2,1,2,HIRES,CUSTOMSCREEN,NULL,"",NULL,NULL };

struct Window *GWindow1=0L;

float richtung; /*Zeichenrichtung in Grad*/
float tx,ty;    /*Koordinaten der Schildkröte*/

/* runden rundet einen float-Wert und gibt eine ganze Zahl zurück*/

int runden(wert)
float wert;
{  int zurueck;
   zurueck=(int)wert;
   if(wert-((float)zurueck)>=0.5)
      zurueck++;
   else
     if(wert-((float)zurueck)<=-0.5)
       zurueck--;
   return(zurueck);
}

/* pic öffnet das Grafikfenster und initialisiert die Grafikwerte */

struct paar *pic(parameter)
struct paar *parameter;
{  if(parameter)
   {  fehler(3,parameter);
      delete(parameter);
      return(-1L);
   }
   else
   {  if(GWindow1)
      {  fehler(19,0L);
         return(-1L);
      }
      else
      {  extern struct Window *Window,*Dialog;
         if((GWindow1=OpenWindow(&NewGWindow))==NULL)
         {  fehler(22,0L);
            return(-1L);
         }
         SetAPen(GWindow1->RPort,0);
         RectFill(GWindow1->RPort,2,2,437,20); /*oberen Rand löschen*/
         SetAPen(GWindow1->RPort,1);
         if(GScreen=OpenScreen(&NewGScreen))
         {  ScreenToBack(GScreen);
            SetAPen(&GScreen->RastPort,0);
            RectFill(&GScreen->RastPort,2,2,436,20);
            SetAPen(&GScreen->RastPort,1);
         }
         else
            GScreen=0L; /*Es konnte nur ein Window geöffnet werden*/
         richtung=0.0;
         tx=ty=0.0;
         Move(GWindow1->RPort,220,102);  /*Turtle zur Bildmitte*/
         return(leeres_atom);
      }
   }
}

/* endpic schließt das Zeichenfenster wieder */

struct paar *endpic(parameter)
struct paar *parameter;
{  if(parameter)
   {  fehler(3,parameter);
      delete(parameter);
      return(-1L);
   }
   else
   {  if(!GWindow1)
      {  fehler(23,0L);
         return(-1L);
      }
      else
      {  CloseWindow(GWindow1);
         if(GScreen)
            CloseScreen(GScreen);
         GWindow1=0;GScreen=0;
         return(leeres_atom);
      }
   }
}

/* universeller Linienbefehl */

#define pruefe(a,b) if((a>218.0)||(a<-218.0)){fehler(25,0L);return(-1L);} else if((b>200.0)||(b<-200.0)){ fehler(24,0L);return(-1L);}
#define nextp hilf=evaluate(parameter->CAR);merke=parameter;parameter=parameter->CDR;dispose(merke)
#define zahl (hilf>0L)&&(hilf->knotentyp==2)&&(hilf->zeichenkette[0]==za)
#define sonst {if(hilf!=-1L){fehler(2,hilf);delete(hilf);}delete(parameter);return(-1L);}
char za='æ'; /*Kennung für Zahlen*/

struct paar *draw(parameter)
struct paar *parameter;
{ if(GWindow1)
  {if(genug_parameter(parameter,5,5))
   {  struct atom *hilf;
      struct dezimal *hilf1,*hilf2;
      struct paar *merke;
      BYTE absolut,winkel;
      float x,y,xneu,yneu;
      int farbe;
      nextp;
      if((hilf!=0L)&&(hilf!=wahr)) sonst
      absolut=(hilf!=0L); /*t falls absolut */
      nextp;
      if((hilf!=0L)&&(hilf!=wahr)) sonst
      winkel=(hilf!=0L); /*t falls Koordinaten*/
      nextp;
      if(zahl)
      {  farbe=getint(hilf); dispose(hilf);
         if(farbe >= 0)
           SetAPen(GWindow1->RPort,farbe);
      }
      else sonst
      nextp;
      if(zahl)
      {   x=getfloat(hilf);hilf1=hilf; }
      else sonst
      hilf=evaluate(parameter->CAR);
      dispose(parameter);
      if(zahl)
      {   y=getfloat(hilf);hilf2=hilf; }
      else sonst
      hilf1->kennung[1]=hilf2->kennung[1]='F';
      if(absolut)
      {  if(winkel)
         {  pruefe(x,y)      /*absolute Koordinaten*/
            if(farbe >= 0)
            { Move(GWindow1->RPort,220+runden(tx),102-(runden(ty)>>1));
              Draw(GWindow1->RPort,220+runden(x),102-(runden(y)>>1));}
            else
              Move(GWindow1->RPort,220+runden(x),102-(runden(y)>>1));
            hilf1->wert=tx;hilf2->wert=ty;
            new(merke); merke->knotentyp=1;merke->CAR=hilf1;merke->CDR=hilf2;
            tx=x;ty=y;
            return(merke);
         }
         else              /*absolute Winkel*/
         {  dispose(hilf2);hilf1->wert=richtung;
            richtung=x;
            xneu=y*cos(richtung*pi/360.0)+tx;
            yneu=y*sin(richtung*pi/360.0)+ty;
            pruefe(xneu,yneu)
            if(farbe >= 0)
            { Move(GWindow1->RPort,220+runden(tx),102-(runden(ty)>>1));
              Draw(GWindow1->RPort,220+runden(xneu),102-(runden(yneu)>>1));
            }
            else
              Move(GWindow1->RPort,220+runden(xneu),102-(runden(yneu)>>1));
            tx=xneu;ty=yneu;
            return(hilf1);
         }
      }
      else
      {  if(winkel)
         {  pruefe(x+tx,y+ty)      /*relative Koordinaten*/
            if(farbe >= 0)
            { Move(GWindow1->RPort,220+runden(tx),102-(runden(ty)>>1));
              Draw(GWindow1->RPort,220+runden(x+tx),102-(runden(y+ty)>>1)); }
            else
              Move(GWindow1->RPort,220+runden(x+tx),102-(runden(y+ty)>>1));
            hilf1->wert=tx;hilf2->wert=ty;
            new(merke); merke->knotentyp=1;merke->CAR=hilf1;merke->CDR=hilf2;
            tx+=x;ty+=y;
            return(merke);
         }
         else                      /*relative Winkel*/
         {  dispose(hilf2);hilf1->wert=richtung;
            richtung=richtung+x-(float)((int)(richtung+x)/360)*360.0;
            xneu=y*cos(richtung*pi/360.0)+tx;
            yneu=y*sin(richtung*pi/360.0)+ty;
            pruefe(xneu,yneu)
            if(farbe >= 0)
            { Move(GWindow1->RPort,220+runden(tx),102-(runden(ty)>>1));
              Draw(GWindow1->RPort,220+runden(xneu),102-(runden(yneu)>>1));
            }
            else
              Move(GWindow1->RPort,220+runden(xneu),102-(runden(yneu)>>1));
            tx=xneu;ty=yneu;
            return(hilf1);
         }
      }
   }
   else
   {  delete(parameter);return(-1L);
   }
  }else {delete(parameter); fehler(23,0L); return(-1L); }
}

/* Zum Zeichnen einer Ellipse */

struct paar *ellipse(parameter)
struct paar *parameter;
{ if(GWindow1)
  {if(genug_parameter(parameter,5,5))
   {  struct atom *hilf;
      struct paar *merke;
      int i;
      float a[5];
      for(i=0;i<5;i++)
      { nextp;
        if(zahl)
        {  a[i]=getfloat(hilf); dispose(hilf); }
        else sonst
      }
      if(a[0]>=0.0)
      {  SetAPen(GWindow1->RPort,(int)a[0]);
         pruefe(a[1],a[2])
         pruefe(a[1]+a[3],a[2]+a[4])
         pruefe(a[1]-a[3],a[2]-a[4])
         DrawEllipse(GWindow1->RPort,220+runden(a[1]),102-(runden(a[2])>>1),
            runden(a[3]),runden(a[4]));
         return(leeres_atom);
      }
   }
   else {delete(parameter); return(-1L);}
  }else {delete(parameter); fehler(23,0L); return(-1L); }
}

struct TmpRas tmp;

/* Zum Ausfüllen von Flächen */
struct paar *fill(parameter)
struct paar *parameter;
{ if(GWindow1)
  {if(genug_parameter(parameter,3,3))
   {  struct atom *hilf;
      struct paar *merke;
      int i;
      float a[3];
      for(i=0;i<3;i++)
      { nextp;
        if(zahl)
        {  a[i]=getfloat(hilf); dispose(hilf); }
        else sonst
      }
      if(a[0]>=0.0)
      {  SetAPen(GWindow1->RPort,(int)a[0]);
         pruefe(a[1],a[2])
         if(GScreen)
         { GWindow1->RPort->TmpRas=(struct TmpRas*)InitTmpRas(&tmp,
             GScreen->BitMap.Planes[0],RASSIZE(640,256));
           Flood(GWindow1->RPort,1,220+runden(a[1]),102-(runden(a[2])>>1));
           return(leeres_atom);
         }
      }
   }
   else {delete(parameter); return(-1L);}
  }else {delete(parameter); fehler(23,0L); return(-1L); }
}
/* Diese Funktion ermittelt Zufallszahlen */

struct paar *zufall(parameter)
struct paar *parameter;
{  static long int wert=4711L;
   WORD *rasterstrahl=0xdff006;
   if(genug_parameter(parameter,1,1))
   {  struct dezimal *hilf;
      hilf=evaluate(parameter->CAR);
      dispose(parameter);
      if((hilf!=-1L)&&(hilf->knotentyp==2)&&(hilf->kennung[0]=='æ'))
      {  float bereich;
         bereich=getfloat(hilf);
         wert=(wert*17L+(ULONG)(*rasterstrahl))%11973L;
         if(wert<0L) wert *=-1L;
         hilf->wert=(float)(wert%10000L)*bereich/10000.0;
         hilf->kennung[1]='F';
         return(hilf);
      }
      else
      {  if(hilf!=-1L)
         {  fehler(2,hilf);
            delete(hilf);
         }
         return(-1L);
      }
   }
   else
   {  delete(parameter);
      return(-1L);
   }
}
/* clear löscht den Grafikbildschirm */

struct paar *clear(parameter)
struct paar *parameter;
{  if(GWindow1)
   if(parameter)
   {  fehler(3,parameter);
      delete(parameter);
      return(-1L);
   }
   else
   {  SetAPen(GWindow1->RPort,0);
      RectFill(GWindow1->RPort,2,2,437,202);
      SetAPen(GWindow1->RPort,1);
      return(leeres_atom);
   }
   else
   {  fehler(23,0L);
      delete(parameter);
      return(-1L);
   }
}

/* wird vor Verlassen des Interpreters aufgerufen */
/* und schließt die Grafikscreens und geöffnete Dateien*/

void beenden()
{  WORD *dummy;
   extern int dateir,dateiw;
   if(GWindow1)
      dummy=endpic(0L);
   if(dateiw!=-1L)
      close(dateiw);
}
