#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuitionbase.h>
#include <libraries/mathffp.h>
#include <libraries/arpbase.h>
#include <clib/req_protos.h>
#include <proto/intuition.h>
#include "messages.h"
#include "chem_defs.h"
#include "eingabe.h"

static int	 PropBlock = 0xFFFF, PropSchritte = 1;

static USHORT *AddBuffer=NULL;	       /* MemoryBuffer f. Gadget-Grafik */
static USHORT *EditBuffer=NULL;
static USHORT *UpBuffer=NULL;
static USHORT *DnBuffer=NULL;
static struct Window *Window2;

extern int atomanz, drehx, drehy, drehz, ref, geladene_Atome;
extern long conwin;
extern double mattheit, matthm1, abstand, vergr, zf, VERGRFAKTOR;
extern T_A a;
extern T_A alt;        /* enthaelt Original-Werte, nicht gedreht etc. */
extern VEKTOR l, b;
extern USHORT GadgetID;
extern BOOL reflexion;
extern char Dateiname[];
extern struct Atom *GAtom[];
extern struct Screen *FirstScreen;


void	  uebertragen(), anzeigen(), FlushStrGadget(), Prepare();
double	  atof();

extern char *AllocMem();
extern void SimpleRequest();

int	  Eingabe()
{
  register int i, j;
  int	    ende = 0, anfang = 1, nummer = atomanz + 1, pos, mx, my, rwert,
	    atomanz_alt, a_name;
  char	    dummy[81];
  T_A	    kopie;

  EingabeFenster.Screen = FirstScreen;
  if (!(Window2 = (struct Window *) OpenWindow(&EingabeFenster)))
    return 0;
  Print(Window2, Dateiname, 7, 0, -1, 20);      /* zentriert ! */
  Print(Window2, "Atom                         X      Y      Z    Radius",
	9, 0, 62, 127);
  Box(Window2, 1, 6, 4, 35, 608, 86);
  sprintf(dummy, "%s    %s               %s               %s             ",
	  MAGNF, TURN, LIGHT, REFLEX);
  Print(Window2, dummy, 13, 2, 4, 158);
  atomanz_alt = atomanz;	       /* Sichern, falls Abbr. gedrueckt wird */
  for (i = 1; i <= atomanz; i++)
  {
    a[i] = alt[i];		       /* Original-Werte zurückschreiben */
    kopie[i] = a[i];		       /* Sicherheitskopie des Molekuels
					  anlegen */
  }
  uebertragen();
  if (atomanz > 10)
  {
    PropBlock = (int) (0xFFFF / (float) (atomanz / 10.0));
    PropSchritte = (int) (0xFFFF / (atomanz - 10));
    ModifyProp(&Prop, Window2, NULL, AUTOKNOB | FREEVERT, 0, 0, 0, PropBlock);
  }
  while (!ende)
  {
    switch (Nachricht(Window2))
    {
      case CLOSEWINDOW:
	rwert = 0;
	ende++;
	break;
      case GADGETUP:
	switch (GadgetID)
	{
	  case 1:		       /* PropGadget */
	    if (atomanz > 9)
	    {
	      anfang = PropSInfo.VertPot / PropSchritte + 1;
	      if (anfang > atomanz - 9)
		anfang = atomanz - 9;
	      anzeigen(anfang);
	    }
	    break;
	  case 2:		       /* Pfeil nach oben */
	    if (anfang > 1)
	    {
	      anfang--;
	      anzeigen(anfang);
	      ModifyProp(&Prop, Window2, NULL, AUTOKNOB | FREEVERT,
		      0, PropSInfo.VertPot - PropSchritte, 0, PropBlock);
	    }
	    break;
	  case 3:		       /* Pfeil nach unten */
	    if (anfang < atomanz - 9)
	    {
	      anfang++;
	      anzeigen(anfang);
	      ModifyProp(&Prop, Window2, NULL, AUTOKNOB | FREEVERT,
		      0, PropSInfo.VertPot + PropSchritte, 0, PropBlock);
	    }
	    break;

	  case 4:		       /* Vergroesserung */
	    ActivateGadget(&DrehX, Window2, NULL);
	    break;
	  case 5:
	    ActivateGadget(&DrehY, Window2, NULL);
	    break;
	  case 6:
	    ActivateGadget(&DrehZ, Window2, NULL);
	    break;
	  case 7:
	    ActivateGadget(&LichtX, Window2, NULL);
	    break;
	  case 8:
	    ActivateGadget(&LichtY, Window2, NULL);
	    break;
	  case 9:
	    ActivateGadget(&LichtZ, Window2, NULL);
	    break;
	  case 10:
	    ActivateGadget(&Reflex, Window2, NULL);
	    break;
	  case 11:
	    break;
	  case 12:
	    strcpy(a[nummer].name, AtomSIBuff);
	    ActivateGadget(&PosX, Window2, NULL);
	    break;
	  case 13:
	    a[nummer].x = PosXSInfo.LongInt;
	    ActivateGadget(&PosY, Window2, NULL);
	    break;
	  case 14:
	    a[nummer].y = PosYSInfo.LongInt;
	    ActivateGadget(&PosZ, Window2, NULL);
	    break;
	  case 15:
	    a[nummer].z = PosZSInfo.LongInt;
	    ActivateGadget(&Radius, Window2, NULL);
	    break;
	  case 16:
	    a[nummer].r = RadiusSInfo.LongInt;
	    if (Neu.Flags & SELECTED)  /* nur wenn wirklich neues Atom */
	    {
	      atomanz++;
	      if (atomanz > 10)
	      {
		PropBlock = (int) (0xFFFF / (float) (atomanz / 10.0));
		PropSchritte = (int) (0xFFFF / (atomanz - 9));
		ModifyProp(&Prop, Window2, NULL, AUTOKNOB | FREEVERT,
			   0, anfang * PropSchritte, 0, PropBlock);
	      }
	      nummer++;
	    }
	    anzeigen(anfang);
	    FlushStrGadget(&AtomSInfo);
	    FlushStrGadget(&PosXSInfo);
	    FlushStrGadget(&PosYSInfo);
	    FlushStrGadget(&PosZSInfo);
	    FlushStrGadget(&RadiusSInfo);
	    RefreshGList(&Atom, Window2, NULL, 5);
	    if (Neu.Flags & SELECTED)
	    {
	      sprintf(dummy, "%3d", nummer);
	      Print(Window2, dummy, 1, 0, 8, 137);
	      ActivateGadget(&Atom, Window2, NULL);
	    }
	    break;
	  case 17:		       /* OK */
	    zf = atof(VergrSIBuff);
	    if (zf == 0.0)
	      SimpleRequest(MAGNF_FACTOR);
	    if (zf == 0.0)
	      break;
	    drehx = DrehXSInfo.LongInt;
	    drehy = DrehYSInfo.LongInt;
	    drehz = DrehZSInfo.LongInt;
	    l.x = atof(LichtXSIBuff);
	    l.y = atof(LichtYSIBuff);
	    l.z = atof(LichtZSIBuff);
	    ref = ReflexSInfo.LongInt;
	    for (i = 1; i <= atomanz; i++)
	      alt[i] = a[i];	       /* Original-Werte aufbewahren fuer
					  erneutes Editieren */
	    rwert = 1;
	    ende++;
	    break;
	  case 18:		       /* Abbruch */
	    atomanz = atomanz_alt;     /* "alte" Anzahl zurueckholen */
	    for (i = 1; i <= atomanz; i++)
	      a[i] = kopie[i];	       /* Sicherheitskopie zurueckholen */
	    rwert = 0;
	    ende++;
	    break;
	  case 19:		       /* Edit oder Anfügen ? */
	    if (Neu.Flags & SELECTED)
	    {
	      nummer = atomanz + 1;
	      sprintf(dummy, "%3d", nummer);
	      Print(Window2, dummy, 1, 0, 8, 137);
	      ActivateGadget(&Atom, Window2, NULL);
	    }
	    break;
	}
	break;
      case MOUSEBUTTONS:
	mx = Window2->MouseX;
	my = Window2->MouseY;
	pos = (my - 38) / 8;
	if (pos >= 0 && pos < 10 && mx < 618)
	{
	  if(Neu.Flags & SELECTED)    /* im Anfüge-Modus ? */
	    SimpleRequest(WRONG_MODE);
	  else
	  {
	    pos = pos + anfang;
	    if(pos<=atomanz)
	    {
	      strcpy(AtomSIBuff, a[pos].name);
	      sprintf(PosXSIBuff, "%d", a[pos].x);
	      sprintf(PosYSIBuff, "%d", a[pos].y);
	      sprintf(PosZSIBuff, "%d", a[pos].z);
	      sprintf(RadiusSIBuff, "%d", a[pos].r);
	      RefreshGList(&Atom, Window2, NULL, 5);
	      nummer = pos;		   /* Aktuelle Atom-Nummer aufs aus-
					      gewaehlte Atom setzen */
	      sprintf(dummy, "%3d", nummer);
	      Print(Window2, dummy, 1, 0, 8, 137);
	      a_name = 105;		   /* auf ??? setzen, falls nichts ge-
					      funden wird */
	      for (j = 1; j <= geladene_Atome; j++)
	      {
		if (strcmp(a[pos].name, GAtom[j]->Kurzz) == NULL)
		{
		  a_name = j;
		  break;
		}
	      }
	      sprintf(dummy, "%-20s", GAtom[a_name]->Name);
	      Print(Window2, dummy, 1, 0, 96, 136);
	    }
	  }
	}
	break;
    }
  }
  CloseWindowSafely(Window2, NULL);
  Window2 = NULL;
  return rwert;
}

void	  uebertragen()
{
  char	    dummy[80];

  anzeigen(1);                         /* Start immer bei 1 */
  sprintf(dummy, "%3.1lf", zf);
  strncpy(VergrSIBuff, dummy, VergrSInfo.MaxChars);
  VergrSInfo.NumChars = strlen(VergrSIBuff);
  DrehXSInfo.LongInt = drehx;
  sprintf(DrehXSIBuff, "%d", drehx);
  DrehYSInfo.LongInt = drehy;
  sprintf(DrehYSIBuff, "%d", drehy);
  DrehZSInfo.LongInt = drehz;
  sprintf(DrehZSIBuff, "%d", drehz);
  sprintf(dummy, "%7.0f", l.x);
  strncpy(LichtXSIBuff, dummy, LichtXSInfo.MaxChars);
  LichtXSInfo.NumChars = strlen(LichtXSIBuff);
  sprintf(dummy, "%7.0f", l.y);
  strncpy(LichtYSIBuff, dummy, LichtYSInfo.MaxChars);
  LichtYSInfo.NumChars = strlen(LichtYSIBuff);
  sprintf(dummy, "%7.0f", l.z);
  strncpy(LichtZSIBuff, dummy, LichtZSInfo.MaxChars);
  LichtZSInfo.NumChars = strlen(LichtZSIBuff);
  ReflexSInfo.LongInt = ref;
  sprintf(ReflexSIBuff, "%d", ref);
  RefreshGList(&Vergr, Window2, NULL, 8);
}

void	  anzeigen(anfang)
int	  anfang;
{
  register int i, j;
  int	    y = 0, nummer;
  char	    dummy[80];

  for (i = anfang; i <= anfang + 9; i++)
  {
    nummer = 105;
    for (j = 1; j <= geladene_Atome; j++)
    {
      if (strcmp(a[i].name, GAtom[j]->Kurzz) == 0)
      {
	nummer = j;
	break;
      }
    }
    sprintf(dummy, "%3d)   %3s %-20s %6d %6d %6d  %4d                ",
      i, a[i].name, GAtom[nummer]->Name, a[i].x, a[i].y, a[i].z, a[i].r);
    Print(Window2, dummy, 3, 5, 8, 44 + y * 8);
    y++;
  }
}

void	  FlushStrGadget(StrInfo)
struct StringInfo *StrInfo;
{
  strcpy(StrInfo->Buffer, "");
  StrInfo->NumChars = 0;
  StrInfo->BufferPos = 0;
}

void	  Prepare()                    /* Werte vorbereiten zum Zeichnen */
{
  int	    n;

  atomedrehen('x', (double) drehx);
  atomedrehen('y', (double) drehy);
  atomedrehen('z', (double) drehz);
  vergr = VERGRFAKTOR;
  vergr *= zf;
  abstand = BILDSCHIRMABSTAND / zf;
  b.x = 0.0;
  b.y = -abstand;
  b.z = 0.0;
  for (n = 1; n <= atomanz; n++)       /*Vergroeßerung der Kalotten*/
    a[n].r = round(ATOMVERGRFAKT * a[n].r);
  reflexion = TRUE;
  if (ref < 1)
    reflexion = FALSE;
  else
  {
    if (ref > 100)
      ref = 100;
    mattheit = (double) ref / 100.0;
    matthm1 = 1.0 / mattheit - 1.0;
  }
  atomeordnen();
  atomezentrieren();
}

void PrepareEGadgets()
{
  if(TypeOfMem(Add_data) & MEMF_FAST)
  {
    AddBuffer=(USHORT *)AllocMem(sizeof(Add_data),MEMF_CHIP|MEMF_PUBLIC);
    if(AddBuffer==NULL)
      WrConWin(conwin,NO_GADGET_MEM);
    else
    {
      movmem(Add_data,AddBuffer,sizeof(Add_data));
      NeuImage2.ImageData=AddBuffer;
    }
  }
  if(TypeOfMem(Edit_data) & MEMF_FAST)
  {
    EditBuffer=(USHORT *)AllocMem(sizeof(Edit_data),MEMF_CHIP|MEMF_PUBLIC);
    if(EditBuffer==NULL)
      WrConWin(conwin,NO_GADGET_MEM);
    else
    {
      movmem(Edit_data,EditBuffer,sizeof(Edit_data));
      NeuImage1.ImageData=EditBuffer;
    }
  }
  if(TypeOfMem(Dn_data) & MEMF_FAST)
  {
    DnBuffer=(USHORT *)AllocMem(sizeof(Dn_data),MEMF_CHIP|MEMF_PUBLIC);
    if(DnBuffer==NULL)
      WrConWin(conwin,NO_GADGET_MEM);
    else
    {
      movmem(Dn_data,DnBuffer,sizeof(Dn_data));
      DnImage.ImageData=DnBuffer;
    }
  }
  if(TypeOfMem(Up_data) & MEMF_FAST)
  {
    UpBuffer=(USHORT *)AllocMem(sizeof(Up_data),MEMF_CHIP|MEMF_PUBLIC);
    if(UpBuffer==NULL)
      WrConWin(conwin,NO_GADGET_MEM);
    else
    {
      movmem(Up_data,UpBuffer,sizeof(Up_data));
      UpImage.ImageData=UpBuffer;
    }
  }
}

void FreeEGadgets()
{
  if(AddBuffer)
    FreeMem(AddBuffer,sizeof(Add_data));
  if(EditBuffer)
    FreeMem(EditBuffer,sizeof(Edit_data));
  if(DnBuffer)
    FreeMem(DnBuffer,sizeof(Dn_data));
  if(UpBuffer)
    FreeMem(UpBuffer,sizeof(Up_data));
}
