#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;
extern struct paar *PNeu();
struct TmpRas tmp;
#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();
ULONG  GScreen=0L;
extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
extern void Move(),Draw(),WritePixel();

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

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);
         }
         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;
{  extern BYTE UMFORMAT;
   extern int schreibscreen;
   extern void darstellen();
   if(parameter)
   {  fehler(3,parameter);
      delete(parameter);
      return(-1L);
   }
   else
   {  if(!GWindow1)
      {  fehler(23,0L);
         return(-1L);
      }
      else
      {  CloseWindow(GWindow1);
         if(GScreen)
            FreeRaster(GScreen,440,204);
         GWindow1=0;GScreen=0;
         if(UMFORMAT)
         {  darstellen(schreibscreen); UMFORMAT=0; }
         return(leeres_atom);
      }
   }
}

/* universeller Linienbefehl */

BYTE pruefe(a,b)
float a,b;
{  if((a>218.0)||(a<-218.0))
   { fehler(25,0L); return(1); }
   if((b>190.0)||(b<-190.0))
   { fehler(24,0L); return(1); }
   return(0);
}
#define nextp hilf=evaluate(parameter->CAR);merke=parameter;parameter=parameter->CDR;dispose(merke)
#define zahl (hilf!=0L)&&(hilf!=-1L)&&(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)
         {  if(pruefe(x,y))      /*absolute Koordinaten*/
            {  dispose(hilf1); dispose(hilf2); return(-1L); }
            if(farbe >= 0)
            { Move(GWindow1->RPort,220+runden(tx),107-(runden(ty)>>1));
              Draw(GWindow1->RPort,220+runden(x),107-(runden(y)>>1));}
            else
              Move(GWindow1->RPort,220+runden(x),107-(runden(y)>>1));
            hilf1->wert=tx;hilf2->wert=ty;
            merke=PNeu(); 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;
            if(pruefe(xneu,yneu))
            {  dispose(hilf1); return(-1L); }
            if(farbe >= 0)
            { Move(GWindow1->RPort,220+runden(tx),107-(runden(ty)>>1));
              Draw(GWindow1->RPort,220+runden(xneu),107-(runden(yneu)>>1));
            }
            else
              Move(GWindow1->RPort,220+runden(xneu),107-(runden(yneu)>>1));
            tx=xneu;ty=yneu;
            return(hilf1);
         }
      }
      else
      {  if(winkel)
         {  if(pruefe(x+tx,y+ty))      /*relative Koordinaten*/
            { dispose(hilf1); dispose(hilf2);  return(-1L);}
            if(farbe >= 0)
            { Move(GWindow1->RPort,220+runden(tx),107-(runden(ty)>>1));
              Draw(GWindow1->RPort,220+runden(x+tx),107-(runden(y+ty)>>1)); }
            else
              Move(GWindow1->RPort,220+runden(x+tx),107-(runden(y+ty)>>1));
            hilf1->wert=tx;hilf2->wert=ty;
            merke=PNeu(); 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;
            if(pruefe(xneu,yneu))
            { dispose(hilf1); return(-1L); }
            if(farbe >= 0)
            { Move(GWindow1->RPort,220+runden(tx),107-(runden(ty)>>1));
              Draw(GWindow1->RPort,220+runden(xneu),107-(runden(yneu)>>1));
            }
            else
              Move(GWindow1->RPort,220+runden(xneu),107-(runden(yneu)>>1));
            tx=xneu;ty=yneu;
            return(hilf1);
         }
      }
   }
   else
   {  delete(parameter);return(-1L);
   }
  }else {delete(parameter); fehler(23,0L); return(-1L); }
}

struct AreaInfo areainfo;
WORD areabuffer[250];

struct paar *polygon(parameter)
struct paar *parameter;
{ if(GWindow1)
  {if(genug_parameter(parameter,5,-1))
   {  struct atom *hilf;
      struct dezimal *hilf1,*hilf2;
      struct paar *merke;
      float x,y;
      BYTE flag=0;
      int i=0;
      nextp;
      if(!GScreen)
        GScreen=AllocRaster(440,204);
      if(!GScreen)
      {  delete(parameter); delete(hilf); fehler(8,0L); return(-1L); }
      GWindow1->RPort->TmpRas=(struct TmpRas *)
         InitTmpRas(&tmp,GScreen,RASSIZE(440,204));
      InitArea(&areainfo,areabuffer,100);
      GWindow1->RPort->AreaInfo=&areainfo;
      if(zahl)
      {  x=getfloat(hilf); dispose(hilf);
         if(x >= 0.0)
           SetAPen(GWindow1->RPort,runden(x));
         SetDrMd(GWindow1->RPort,JAM1);
      }
      else sonst
      while((parameter>0L)&&(i<99))
      {  if(parameter->knotentyp!=1)
         {  fehler(2,parameter); delete(parameter); return(-1L); }
         nextp;
         if(zahl)
         {  x=getfloat(hilf); dispose(hilf); }
         else sonst
         if((!parameter)||(parameter->knotentyp!=1))
         {  fehler(1,parameter);delete(parameter);return(-1L); }
         nextp;
         if(zahl)
         {  y=getfloat(hilf); dispose(hilf); }
         else sonst
         if(pruefe(x,y))
         { delete(parameter); return(-1L); }
         if(flag)
           AreaDraw(GWindow1->RPort,220+runden(x),107-(runden(y)>>1));
         else { flag=1; AreaMove(GWindow1->RPort,220+runden(x),107-(runden(y)>>1)); }
         i++;
      }
      if(i==99) { fehler(15,parameter); delete(parameter); }
      AreaEnd(GWindow1->RPort);
      return(leeres_atom);
   }
   else
   {  delete(parameter);return(-1L);
   }
  }else {delete(parameter); fehler(23,0L); return(-1L); }
}
struct paar *ellipsef(parameter)
struct paar *parameter;
{ if(GWindow1)
  {if(genug_parameter(parameter,5,5))
   {  struct atom *hilf;
      struct paar *merke;
      int i;
      float a[5];
      if(!GScreen)
        GScreen=AllocRaster(440,204);
      if(!GScreen)
      {  delete(parameter); fehler(8,0L); return(-1L); }
      GWindow1->RPort->TmpRas=(struct TmpRas *)
         InitTmpRas(&tmp,GScreen,RASSIZE(440,204));
      InitArea(&areainfo,areabuffer,100);
      GWindow1->RPort->AreaInfo=&areainfo;
      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]);
         if(pruefe(a[1],a[2])||
            pruefe(a[1]+a[3],a[2]+a[4])||
            pruefe(a[1]-a[3],a[2]-a[4]))
            return(-1L);
         AreaEllipse(GWindow1->RPort,220+runden(a[1]),107-(runden(a[2])>>1),
            runden(a[3]),runden(a[4])>>1);
         AreaEnd(GWindow1->RPort);
         return(leeres_atom);
      }
   }
   else {delete(parameter); return(-1L);}
  }else {delete(parameter); fehler(23,0L); return(-1L); }
}
/* rgb */
struct paar *rgb(parameter)
struct paar *parameter;
{  if(genug_parameter(parameter,4,4))
   {  struct atom *hilf;
      struct dezimal *hilf1,*hilf2;
      struct paar *merke;
      int  x,r,g,b;
      nextp;
      if(zahl)
      {  x=getint(hilf); dispose(hilf);
         if(x < 0) x=0;
      }
      else sonst
      nextp; if(zahl) { r=getint(hilf); dispose(hilf); } else sonst
      nextp; if(zahl) { g=getint(hilf); dispose(hilf); } else sonst
      nextp; if(zahl) { b=getint(hilf); dispose(hilf); } else sonst
      SetRGB4(&(Dialog->WScreen->ViewPort),x,r,g,b);
      return(leeres_atom);
   }
   else
   {  delete(parameter);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]);
         if(pruefe(a[1],a[2])||
            pruefe(a[1]+a[3],a[2]+a[4])||
            pruefe(a[1]-a[3],a[2]-a[4]))
            return(-1L);
         DrawEllipse(GWindow1->RPort,220+runden(a[1]),107-(runden(a[2])>>1),
            runden(a[3]),runden(a[4])>>1);
         return(leeres_atom);
      }
   }
   else {delete(parameter); return(-1L);}
  }else {delete(parameter); fehler(23,0L); return(-1L); }
}

/* 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]);
         if(pruefe(a[1],a[2]))
           return(-1L);
         if(!GScreen)
            GScreen=AllocRaster(440,204);
         if(GScreen)
         { GWindow1->RPort->TmpRas=(struct TmpRas *)
              InitTmpRas(&tmp,GScreen,RASSIZE(440,204));
           Flood(GWindow1->RPort,1,220+runden(a[1]),107-(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,10,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);
}
