/*
 * Cluster                                         © 1988 by Unicorn Systems
 * -------
 * Sternhaufensimulation, systemunabhängige Funktionen und Hauptprogramm.
 * 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 <math.h>
#include <stdio.h>
#include <clusterDEF.h>
#include <cluster.h>


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

void main(), cluster(), ItsAllOverNowBabyBlue(), SisterMorphine(), range();
int MeAndBobbyMcGee();


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

void main(argc, argv)
int argc;
char *argv[];
{
   register int i;
   register char *name = 0;
   if (argc < 2)
      ItsAllOverNowBabyBlue(argv[0]);
   for (i = 1; i < argc; ++i)
      if (**++argv == '-') {
         switch (*++*argv) {
            case 't':
               delta = atof(*++argv);
               ++i;
               break;
            case 'd':
               nahe = atof(*++argv);
               ++i;
               break;
            case 's':
               skal = atof(*++argv);
               sflag = 1;
               ++i;
               break;
            case 'g':
               guru = 0;
               break;
            case 'z':
               zyklen = atol(*++argv);
               if (zyklen > 0L)
                  zykflag = 1;
               ++i;
               break;
            default:
               ItsAllOverNowBabyBlue(argv[0]);
               break;
         };
      }
      else
         if (! name)
            name = *argv;
         else
            ItsAllOverNowBabyBlue(argv[0]);
   if (openIO())
      if (universum(name)) {
         range();
         cluster();
         if (! zykflag)
            waitkey();
      }
      else
         printf("Fehler in der Sterndatei.\n");
   else
      printf("Fehler beim öffnen des Screens / der Libraries\n");
   closeIO();
}


/*
 * Verfolgt die Bahnen der Sterne und berechnet neue Positionen.
 */

void cluster()
{
   register int i, j, k;
   double s, sq, as, sk = 0;
   dnormal = delta;
   dklein = delta / 10.0;
   clear();
   for (;;) {
      if (getkey())
         if (MeAndBobbyMcGee())
            return();
      if (zykflag)
         if (! --zyklen)
            return();
      sk = BIG_VAL;
      for (i = 0; i < stars; ++i) {
         for (k = 0; k < 3; ++k)
            acc[k][i] = 0.0;
         for (j = 0; j < stars; ++j)
            if (j != i) {
               sq = 0.0;
               for (k = 0; k < 3; ++k)
                  sq += (ds[k] = pos[k][i] - pos[k][j]) * ds[k];
               if (sq != 0.0) {
                  if ((s = sqrt(sq)) < sk)
                     sk = s;
                  as = mas[i] * mas[j] * GKONST / (sq * s * (mas[i] + mas[j]));
                  for (k = 0; k < 3; ++k)
                     acc[k][i] += as * ds[k];
               }
            }
         for (k = 0; k < 3; ++k)
            vel[k][i] -= acc[k][i] * delta;        /* Warum '-=' ??? */
         for (k = 0; k < 3; ++k)
            pos[k][i] += vel[k][i] * delta;
      }
      alter += delta;
      SisterMorphine();
      if (sk < nahe)
         delta = dklein;
      else
         delta = dnormal;
   }
}


/*
 * Tastenabfrage während der Simulation. d = Ein Datenfenster öffnen oder
 * in das bestehende die aktuellen Simulationsdaten ausgeben. c = löschen
 * des Datenfensters, aber die Simulation weiterführen. q = verlassen des
 * Programmes. Wenn 'q' gewählt wurde, muss vor dem entgültigen abbrechen
 * der Simulation noch eine weitere (beliebige) Taste gedrückt werden. Auf
 * diese Weise kann das Schlussbild des Sternhaufens nochmals betrachtet
 * werden. 
 */
 
int MeAndBobbyMcGee()
{
   register int z = 0;
   switch (code) {
      case 'd':               /* Datenfenster öffnen */
         if (! dflag)
            if (! opendwin())
               return(1);
         dclear();
         sprintf(wort, "Alter: %.4e Jahre", alter);
         dprint(z++, 0);
         sprintf(wort, "Zyklus: %.4e Jahre", dnormal);
         dprint(z++, 0);
         sprintf(wort, "Skalierung: %.4e", skal);
         dprint(z++, 0);
         sprintf(wort, "Objekte: %d", stars);
         dprint(z++, 0);
         sprintf(wort, "© 1988 Unicorn Systems");
         dprint(ZEILEN - 1, 0);
         return(0);
         break;
      case 'q':               /* Programm abbrechen */
         closedwin();
         return(1);
         break;
      case 'c':               /* Datenfenster löschen */
         closedwin();
         return(0);
         break;
      default:
         return(0);
         break;
   };
}


/* 
 * Zeigt alle Sterne in der neuen Position an. Die grösse des Angezeigten
 * Ausschnittes des Sternhaufens hängt vom Skalierungsfaktor 'skal' ab.
 * 'skalx' und 'skaly' sind der Auflösung entsprechende abwandlungen von
 * 'skal' (so werden Verzerrungen bei NTSC-Amigas mit 200 Punkten anstelle
 * von 256 Punkten ausgeschlossen).
 */

void SisterMorphine()
{
   register int i, j;
   for (i = 0; i < stars; ++i)
      pixel((int) (pos[0][i] * skalx), (int) (pos[1][i] * skaly), col[i]);
}


/*
 * Vergleicht alle Sternpositionen und sucht die grössten Werte für
 * x, y und z-Koordinaten heraus. Durch diese Werte wird der allgemeine
 * Skalierungsfaktor bestimmt, der in der Funktion 'pixel' verwendet wird.
 * Der Mittelpunkt des Sternhaufens (0/0/0) liegt immer in der Mitte des
 * Bildschirmes. Skalierungsfaktor: 'skal'. Diese Funktion verändert
 * 'skal' nur, wenn beim Starten der Simulation kein Skalierungsfaktor 
 * eingegeben wurde (sflag).
 */

void range()
{
   register int i, j;
   double max = 0.0, min = 0.0;
   if (! sflag) {
      for (i = 0; i < stars; ++i)
         for (j = 0; j < 2; ++j)             /* Nur x und y - Koordinaten */
            if (pos[j][i] > max)
               max = pos[j][i];
            else
               if (pos[j][i] < min)
                  min = pos[j][i];
      min = fabs(min);
      skal = (double) height / (((max > min) ? max : min) * 4.0);
   }
   skaly = skal;
   skalx = (WIDTH / height) * skal;
}


/*
 * Gibt kurze Gebrauchsanweisung aus und verlässt das Programm durch
 * 'exit()'. 
 */

void ItsAllOverNowBabyBlue(prg)
char *prg;
{
   printf("Gebrauch: %s <Name> -z <cc> -t <nn> -d <dd> -s <kk> -g\n", prg);
   printf("Name = Datei mit den Sterndaten.\n");
   printf("-g = Guru-Sicherung: Der Screen kann verschoben werden.\n");
   printf("cc = Anzahl der Zyklen. Wenn nicht vorhanden: Tastendruck\n");
   printf("nn = Zeitintervall, normalwert = 1 Jahr\n");
   printf("dd = Grenze von nah/fern, normalwert = 1 AE\n");
   printf("kk = Skalierungsfaktor, normalwert: Automatisch\n");
   exit(0);
}
