/*
 * ClusterIO                                       © 1988 by Unicorn Systems
 * ---------
 * Sternhaufensimulation, Eingabe/Ausgabefunktionen
 * Aztec C 3.6, Kickstart 1.2, Workbench 1.2,
 * 
 * Datum:   Autor:      Aenderung:                                   Version:
 * --------------------------------------------------------------------------
 * 1.8.88   Roger       Programm erstellt                            1.00
 *
 */

/*=========================   INCLUDES/DEFINES   ===========================*/

#include <exec/exec.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/display.h>
#include <stdio.h>
#include <clusterDEF.h>
#include <clusterIO.h>


/*==========================   MODULFUNKTIONEN   ===========================*/

void closeIO(), waitkey(), clear(), normalfarben(), pixel(), cleanup();
int openIO(), getkey(), getword(), opendwin(), universum();
void dclear(), dprint(), closedwin();


/*============================   FUNKTIONEN   ==============================*/

/*
 * Oeffnet das Datenfenster. Die Grösse dieses Fensters ist durch die Makros
 * ZEILEN und SPALTEN definiert.
 */

int opendwin()
{
   newdwin.Width = (dwidth = SPALTEN * 8 + 8);
   newdwin.Height = (dheight = ZEILEN * 8 +17);
   newdwin.Screen = scr;
   if (! guru)
      newdwin.TopEdge = 1;
   if (dwin = OpenWindow(&newdwin)) {
      dflag = 1;
      dwinrp = dwin->RPort;
      dwinvp = ViewPortAddress(dwin);
      SetDrMd(dwinrp, JAM1);
      clX = dwin->Width - dwin->BorderLeft - dwin->BorderRight;
      clY = dwin->Height - dwin->BorderBottom - 1;
      return(WAHR);
   }
   else
      return(FALSCH);
}


/*
 * Gibt im Datenfenster den globalen Zeichenvektor 'wort' an der Position
 * 'zeile' und 'spalte' aus.
 */

void dprint(zeile, spalte)
register int zeile;
register int spalte;
{
   SetAPen(dwinrp, 7L);
   Move(dwinrp, (long) spalte * 8L + 5L, (long) zeile * 8L + 19L);
   Text(dwinrp, wort, (long) strlen(wort));
}


/*
 * Oeffnet alle Libraries sowie den Screen und das Hauptfenster, in dem 
 * die Simulation stattfindet. Wenn das Programm auf einem PAL-Amiga läuft,
 * wird ein Screen von 256 Pixeln höhe geöffnet, bei einem NTSC-Amiga 
 * sollte die Höhe 200 Pixel sein (noch nicht getestet).
 */

int openIO()
{
   fd = 0;
   if ((IntuitionBase = OpenLibrary("intuition.library", REV)) == NULL)
      return(FALSCH);
   if ((GfxBase = OpenLibrary("graphics.library", REV)) == NULL)
      return(FALSCH);
   if ((ExecBase = OpenLibrary("exec.library", REV)) == NULL)
      return(FALSCH);
   /* Hier wird der erste Screen in der verketteten Liste bestimmt: */
   scr = IntuitionBase->FirstScreen;
   /* Suchen nach dem Workbench-Screen (Screentitel = Workbench): */
   while (strncmp((char *) scr->Title, "Workbench", 9) != 0)
      if (! (scr = scr->NextScreen))
         return(FALSCH);               /* Workbenchscreen nicht gefunden */
   if (scr->Height == 256 || scr->Height == 512)
      height = 256;                    /* Wenn PAL-Amiga */
   else
      height = 200;                    /* Wenn NTSC-Amiga */
   newscr.Height = height;
   if (guru)
      newwin.Height = height;
   else {
      newwin.Height = height - 1;
      newwin.TopEdge = 1;
   }
   if (scr = OpenScreen(&newscr)) {
      newwin.Screen = scr;
      scrrp = &scr->RastPort;
      scrvp = &scr->ViewPort;
      if (win = OpenWindow(&newwin)) {
         ShowTitle(scr, 0L);
         winrp = win->RPort;
         winvp = ViewPortAddress(win);
         normalfarben();
         SetDrMd(winrp, JAM1);
         SetAPen(winrp, 13L);
         return(WAHR);
      } 
   }
   else {
      CloseScreen(scr);
      return(FALSCH);
   }
}


/*
 * Schliesst Eingabe- und Ausgabekanäle, gibt Speicher zurück. 
 */

void closeIO()
{
   if (win) {
      while (message = GetMsg(win->UserPort))
         ReplyMsg(message);
      CloseWindow(win);
   }
   closedwin();
   if (scr)
      CloseScreen(scr);
   if (IntuitionBase)
      CloseLibrary(IntuitionBase);
   if (GfxBase)
      CloseLibrary(GfxBase);
   if (ExecBase)
      CloseLibrary(ExecBase);
   cleanup();
}


/*
 * Schliesst das Datenfenster. Kann mehrmals aufgerufen werden.
 */
 
void closedwin()
{
   if (dflag) {
      CloseWindow(dwin);
      dflag = 0;
   }
}


/*
 * Gibt den allozierten Speicher zurück.
 */

void cleanup()
{
   register int i;
   for (i = 0; i < 3; ++i) {
      if (acc[i])
         free(acc[i]);
      if (vel[i])
         free(vel[i]);
      if (pos[i])
         free(pos[i]);
   }
   if (col)
      free(col);
   if (mas)
      free(mas);
   if (fd)                    /* Kann offen sein nach 'universum()' */
      fclose(fd);
}


/*
 * Löscht das Hauptfenster, in dem die Simulation stattfindet.
 */

void clear()
{
   SetAPen(winrp, 0L);
   RectFill(winrp, 0L, 0L, (long) WIDTH, (long) height);
}


/*
 * Löscht das Datenfenster (muss geöffnet sein).
 */

void dclear()
{
   SetAPen(dwinrp, 0L);
   RectFill(dwinrp, (long) (dwin->BorderLeft + 1), \
            (long) (dwin->BorderTop + 1), (long) clX, (long) clY);
}


/*
 * Wartet auf einen Tastendruck. 
 */

void waitkey()
{
   for (;;) {
      class = 0;
      Wait(1L<<win->UserPort->mp_SigBit);
      while (message = GetMsg(win->UserPort)) {
         class = message->Class;
         code = message->Code;
         qual = message->Qualifier;
         ReplyMsg(message);
      }
      if (class == VANILLAKEY)
         break;
   }
}


/*
 * Gibt als Wert 1 zurück, wenn eine Taste gedrückt wurde. Wenn ein Event
 * eingetreten ist, werden alle weiteren Events ausgelesen. (Kein Puffer!)
 */

int getkey()
{
   message = (void *) 0;
   class = 0;
   while (message = GetMsg(win->UserPort)) {
      class = message->Class;
      code = message->Code;
      qual = message->Qualifier;
      ReplyMsg(message);
   }
   if (class == VANILLAKEY)
      return(WAHR);
   return(FALSCH);
}


/*
 * Setzt den Punkt x, y mit der Farbe f. Die Koordinaten haben den Null-
 * punkt in der Mitte des Bildschirms. Die Vorzeichen der Koordinaten:
 *
 *                           |+Y
 *                           |
 *                    -X ----0---- +X
 *                           |
 *                           |-Y
 */

void pixel(x, y, f)
register int x, y, f;
{
   SetAPen(winrp, (long) f);
   WritePixel(winrp, x + WIDTH / 2L, height - (y + height / 2L));
}


/*
 * Liest die Daten eines Sternhaufens mit dem Namen 's' ein. Wenn alles 
 * verstanden wurde, ist der Wert = WAHR, sonst FALSCH. Format der Daten:
 * 1. Anzahl Sterne, 2. Koordinaten x, y und z des ersten Sterns,
 * 3. Geschwindigkeit x, y, z - Achse des ersten Sterns, 4. Masse des
 * ersten Sterns, 5. Farbe von 0 bis 15 des ersten Sterns.
 */

int universum(s)
char *s;
{
   register int c, i, j;
   double zahl;
   if (! (fd = fopen(s, "r")))
      return(FALSCH);                     /* File nicht lesbar. */
   if (getword() == EOF)
      return(FALSCH);
   if ((stars = atoi(wort)) == 0)
      return(FALSCH);
   for (j = 0; j < 3; ++j) {
      if (acc[j] = (double *) malloc(sizeof(double) * stars))
         if (vel[j] = (double *) malloc(sizeof(double) * stars))
            if (pos[j] = (double *) malloc(sizeof(double) * stars))
               continue;
      cleanup();
      return(FALSCH);
   }
   if (! (col = (int *) malloc(sizeof(int) * stars))) {
      cleanup();
      return(FALSCH);
   }
   if (! (mas = (double *) malloc(sizeof(double) * stars))) {
      cleanup();
      return(FALSCH);
   }
   for (i = 0; i < stars; ++i) {
      for (j = 0; j < 3; ++j)             /* Koordinaten */
         if (getword() != EOF)
            pos[j][i] = atof(wort);
         else {
            cleanup();
            return(FALSCH);
         }
      for (j = 0; j < 3; ++j)             /* Geschwindigkeit */
         if (getword() != EOF)
            vel[j][i] = atof(wort);
         else {
            cleanup();
            return(FALSCH);
         }
      if (getword() != EOF) {             /* Masse */
         mas[i] = atof(wort);
         if (getword() != EOF) {          /* Farbe */
            col[i] = atoi(wort);
            if (col[i] >= 0 && col[i] < COLORS)
               continue;
         }
      }
      cleanup();
      return(FALSCH);
   }
   for (i = 0; i < stars; ++i)
      for (j = 0; j < 3; ++j)
         acc[j][i] = 0.0;                 /* Beschleunigungen auf Null */
   fclose(fd);
   return(WAHR);
}


/*
 * Liest das nächste Wort in den Stringvektor 'wort' ein. Wenn kein Wort
 * mehr vorhanden ist (EOF), ist die Rückgabe 'EOF', sonst 'NULL' 
 */

int getword()
{
   register int c, i = 0;
   while ((c = getc(fd)) != EOF)
      if (c != ' ' && c != '\n' && c != '\t' && c != '\f')
         wort[i++] = c;
      else
         if (i > 0)
            break;
   if (i > 0) {
      wort[i] = STREND;
      return(NULL);
   }
   return(EOF);
}


/*
 * Setzt die Farben auf Werte der 'colortable'. 
 */

void normalfarben()
{
   register int i;
   for (i = 0; i < COLORS; ++i) 
      SetRGB4(scrvp, (long) i, (long) colortable[i][0], \
                               (long) colortable[i][1], \
                               (long) colortable[i][2]);
}

