/***************************************************************************
 * elements.c - CAMM v2.0 Periodic Table of the Elements module. This set  *
 * 11-8-88      of routines draws and gives information about the periodic *
 * Paul Miller  table of the elements. (Info provided by Sargent-Welch)    *
 ***************************************************************************/

#include "elements.h"
#include <libraries/dos.h>

struct Window *ewindow;
struct Screen *escreen;

struct TextFont *TextFont;
struct TextFont *ElementFont;
struct TextFont *CAMMFont;
struct TextAttr TextAttr = {(STRPTR)"CAMMtopaz.font", 8, 0, FPF_DISKFONT};
struct TextAttr ElementAttr = {(STRPTR)"element.font", 12, 0, FPF_DISKFONT};
struct TextAttr CAMMAttr = {(STRPTR)"CAMM.font", 5, 0, FPF_DISKFONT};

struct IntuiText TextText = {
   1,0,JAM1,0,0,&TextAttr, (UBYTE *)"", NULL
};
struct IntuiText ElementText = {
   1,0,JAM1,0,0,&ElementAttr, (UBYTE *)"", NULL
};
struct IntuiText CAMMText = {
   1,0,JAM1,0,0,&CAMMAttr, (UBYTE *)"", NULL
};

char *columntext[] = {"IA","IIA","IIA","IVA","VA","VIA","VIIA","VIIIA",
                      "IB","IIB","IIIB","IVB","VB","VIB","VIIB","VIII"};
char *rowtext[] = {"I","II","III","IV","V","VI","VII"};
USHORT table_x[] = {0,1,2,3,4,5,6,8,10,11,12,13,14,15,16,17};
USHORT table_y[] = {0,1,3,3,3,3,3,3,3,3,1,1,1,1,1,0};

USHORT info_x[]={126,197,150,126,126,205,174,157,205,230,253,
                 157,254,205,286,246};

int tabledata[] = {249,106, 249,103, 265,103,
                     -298,103, 315,103, 315,106, -1};
int CubicFCData[] = {0,0, 26,0, 38,12, 38,35, 12,35, 0,23, 0,0,
       12,12, 38,12, -12,12, 12,35, -25,23, 26,23, 26,24, 25,24, -1};
int CubicBCData[] = {0,0, 26,0, 26,23, 0,23, 0,0, 12,12, 12,35, 0,23,
       -12,12, 38,12, 38,35, 12,35, -26,23, 38,35, -26,0, 38,12,
       -38,35, 0,0, -26,0, 12,35, -38,12, 0,23, -12,12, 20,23, -1};
int CubicData[] = {0,0, 26,0, 38,12, 38,35, 12,35, 0,23, 0,0,
       12,12, 38,12, -12,12, 12,35, -1};
int HexData[] = {0,10, 19,0, 38,10, 38,31, 19,41, 0,31, 0,10, 38,31,
       -19,0, 19,41, -38,10, 0,31, -1};
int RhombData[] = {0,35, 5,12, 13,4, 8,27, 0,35, 25,31, 30,8, 5,12,
       -13,4, 38,0, 33,23, 8,27, -33,23, 25,31, -38,0, 30,8, -1};
int TetraData[] = {11,39, 11,5, 22,5, 22,39, 11,39, -11,5, 18,0, 29,0, 22,5,
       -29,0, 29,34, 22,39, -1};
int OrthoData[] = {0,41, 0,11, 27,11, 27,41, 0,41, -27,11, 38,0, 11,0, 0,11,
       -38,0, 38,30, 27,41, -1};
int MonoData[] = {0,20, 10,0, 28,0, 38,20, 28,40, 10,40, 0,20, -1};
int *structuredata[] = {&CubicFCData[0], &CubicBCData[0], &CubicData[0],
   &HexData[0], &RhombData[0], &TetraData[0], &OrthoData[0], &MonoData[0]};

char *structuretext[] = {"Cubic, FC", "Cubic, BC", "Cubic", "Hexagonal",
   "Rhombohedral","Tetragonal","Orthorhombic","Monoclinic", "Unknown"};

char *elem_type[] = {"SOLID","LIQUID","GAS","SYNTHETIC"};

char *infotext[] = {"Atomic Weight:","Electron Configuration:",
   "Oxidation States:","Boiling Point:","Melting Point:",
   "Density at 300K (g/cm3):","Covalent Radius (A):","Atomic Radius (A):",
   "Atomic Volume (cm3/mol):","First Ionization Potential:",
   "Specific Heat Capacity (J/gK):","Electronegativity:",
   "Heat of Vaporization (kJ/mol):","Heat of Fusion (kJ/mol):",
   "Electrical Conductivity (106/Ocm):","Thermal Conductivity (W/cmK):"};

UWORD color_map[4] = {0x0020, 0x00A0, 0x007F, 0x0E44};
UWORD shadow_map[8] = {0x0333, 0x00A0, 0x000F, 0x0E00,
                       0x0000, 0x0000, 0x0000, 0x0000};

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct DiskfontBase *DiskfontBase;

extern struct Menu infomenu_strip[];

struct Element element[ELEMENTS];
struct Info info[ELEMENTS];

long Xoff = EOFF_X, Yoff = EOFF_Y;
BOOL shadow = FALSE;

void elements(), handle_infomenu(), draw_table(), outline(), PrintBText();
void superscript(), convert_superscript(), draw_text(), draw_box();
void draw_data(), draw_infotext(), draw_info(), open_libraries(), abort();
void highlight_box();

main(argc,argv)
int argc;
char *argv[];
{
   struct NewScreen ns;

   if (argc > 1)
      shadow = TRUE;

   open_libraries();
   if (!load_elements())
      abort("Cannot find `Elements.DAT' file.");
   if (!load_info())
      abort("Cannot find `Info.DAT' file.");

   setmem(&ns, sizeof(ns), 0L);

   ns.LeftEdge = 0;
   ns.TopEdge = 0;
   ns.Width = SCREEN_WIDTH;
   ns.Height = SCREEN_HEIGHT;
   ns.Depth = DEPTH;
   ns.DetailPen = 0;
   ns.BlockPen = 1;
   ns.ViewModes = HIRES | LACE;
   ns.Type = CUSTOMSCREEN;
   ns.DefaultTitle = (UBYTE *)SCREEN_TITLE;

   if (shadow)
      ns.Depth = SHADOWDEPTH;

   if (!(escreen = (struct Screen *)OpenScreen(&ns)))
      abort("Cannot open main screen.");

   if (!shadow)
      LoadRGB4(&escreen->ViewPort, color_map, 4L);
   else
      LoadRGB4(&escreen->ViewPort, shadow_map, 8L);

   elements(escreen);
}

void elements(screen)
struct Screen *screen;
{
   struct NewWindow nw;
   struct Window *w;
   struct IntuiMessage *message;
   ULONG class;
   USHORT code;
   int mx, my, info;

   setmem(&nw, sizeof(nw), 0L);

   nw.LeftEdge = 0;
   nw.TopEdge = EWIN_TOP;
   nw.Width = EWIN_WIDTH;
   nw.Height = EWIN_HEIGHT;
   nw.DetailPen = -1;
   nw.BlockPen = -1;
   nw.IDCMPFlags = MOUSEBUTTONS | MENUPICK;
   nw.Flags = WINDOWDEPTH | GIMMEZEROZERO | SMART_REFRESH | REPORTMOUSE |
              ACTIVATE;
   nw.Title = (UBYTE *)E_TITLE;
   nw.Screen = screen;
   nw.Type = CUSTOMSCREEN;

   if (!(ewindow = (struct Window *)OpenWindow(&nw)))
      abort("Cannot open elements window.");

   SetMenuStrip(ewindow, infomenu_strip);

   if (shadow)
      draw_table(ewindow, shadow);

   draw_table(ewindow, FALSE);

   while(1)
   {
      Wait(1L<<ewindow->UserPort->mp_SigBit);

      while(message = (struct IntuiMessage *)GetMsg(ewindow->UserPort))
      {
         class = message->Class;
         code = message->Code;
         mx = message->MouseX;
         my = message->MouseY;
         w = message->IDCMPWindow;
         ReplyMsg(message);
         switch (class)
         {
            case CLOSEWINDOW:
               close_window(w);
            case MOUSEBUTTONS:
               switch (code)
               {
                  case SELECTDOWN:
                     if (info = get_element(mx, my))
                        info_window(info-1);
                     break;
               }
               break;
            case MENUPICK:
               ClearMenuStrip(w);
               handle_infomenu(code);
               SetMenuStrip(w, infomenu_strip);
               break;
         }
      }
   }
}

void handle_infomenu(menu)
int menu;
{
   if (menu != MENUNULL)
   {
      switch (ITEMNUM(menu))
      {
         case 0:
            display_subpart();
            break;
         case 1:
            display_radioiso();
            break;
         case 2:
            display_ionichar();
            break;
         case 3:
            display_notes();
            break;
         case 4:
            display_info();
            break;
         case 5:
            close_all();
            abort("");
            break;
      }
   }
}

get_element(x, y)
int x, y;
{
   register int i;

   if (y <= EWIN_TOP)
      return(NULL);

   y -= EWIN_TOP;

   if (y > (EOFF_Y + 7 * BOX_H))
      y -= (.25 * BOX_H);

   x = (x - EOFF_X - 4) / BOX_W;
   y = (y - EOFF_Y) / BOX_H;

   for (i = 0; i < ELEMENTS; i++)
      if ((x == element[i].column) && (y == element[i].row))
      {
         highlight_box(i);
         return(i+1);
      }
   return(NULL);
}

void draw_table(window, shad)
struct Window *window;
BOOL shad;
{
   struct RastPort *rp = window->RPort;
   long x, y, i, num;
   char number[3];

   if (!shad)
   {
      SetAPen(rp, (long)BOX_COLOR);
      Xoff = EOFF_X;
      Yoff = EOFF_Y;
   }
   else
   {
      SetAPen(rp, (long)SHADOWBLACK);
      ElementText.FrontPen = SHADOWBLACK;
      Xoff = EOFF_SHADX;
      Yoff = EOFF_SHADY;
   }

   for (i = 0; i < ELEMENTS; i++)
   {
      num = element[i].number;
      x = Xoff + (element[i].column * BOX_W);
      y = Yoff + (element[i].row * BOX_H);

      if ((num>57 && num<72) || (num>89 && num<104))
         y += (.25 * BOX_H);

      draw_box(rp, x, y, BOX_W, BOX_H);

      sprintf(number, "%d", element[i].number);
      superscript(number);
      if (!shad)
         ElementText.FrontPen = BOX_COLOR;
      else
         ElementText.FrontPen = SHADOWBLACK;
      ElementText.IText = (UBYTE *)number;
      PrintIText(rp, &ElementText, (long)(x+ENUM_X), (long)(y+ENUM_Y));

      if (num > 103) x -= 6;

      if (!shad)
         ElementText.FrontPen = element[i].type;

      ElementText.IText = (UBYTE *)element[i].symbol;
      if (element[i].type == SYNTHETIC_E)
      {
         if (!shad)
            outline(rp, &ElementText, x+ESYM_X-2L, y+ESYM_Y-2L, BOX_COLOR);
         else
            outline(rp, &ElementText, x+ESYM_X-2L, y+ESYM_Y-2L, SHADOWBLACK);
      }
      else
         PrintIText(rp, &ElementText, (long)(x+ESYM_X), (long)(y+ESYM_Y));
   }
   Move(rp, (long)(Xoff+(12*BOX_W)-1), (long)(Yoff+(1*BOX_H)));
   Draw(rp, (long)(Xoff+(12*BOX_W)-1), (long)(Yoff+(2*BOX_H)-1));
   Draw(rp, (long)(Xoff+(13*BOX_W)-1), (long)(Yoff+(2*BOX_H)-1));
   Draw(rp, (long)(Xoff+(13*BOX_W)-1), (long)(Yoff+(3*BOX_H)-1));
   Draw(rp, (long)(Xoff+(14*BOX_W)-1), (long)(Yoff+(3*BOX_H)-1));
   Draw(rp, (long)(Xoff+(14*BOX_W)-1), (long)(Yoff+(4*BOX_H)-1));
   Draw(rp, (long)(Xoff+(15*BOX_W)-1), (long)(Yoff+(4*BOX_H)-1));
   Draw(rp, (long)(Xoff+(15*BOX_W)-1), (long)(Yoff+(5*BOX_H)-1));
   Draw(rp, (long)(Xoff+(16*BOX_W)-1), (long)(Yoff+(5*BOX_H)-1));
   Draw(rp, (long)(Xoff+(16*BOX_W)-1), (long)(Yoff+(6*BOX_H)-1));

   draw_text(window, shad);
}

void outline(rp, text, x, y, color)
struct RastPort *rp;
struct IntuiText *text;
long x, y, color;
{
   long xx, yy;

   text->FrontPen = color;
   for (yy = y-1; yy <= y+1; yy++)
      for (xx = x-1; xx <= x+1; xx++)
         PrintIText(rp, text, xx, yy);
   text->FrontPen = BACKGROUND;
   PrintIText(rp, text, x, y);
}

void superscript(text)
char text[];
{
   register USHORT i;

   for (i = 0; text[i] != '\0'; i++)
      text[i] += 0x50;
}

void convert_super(in, out)
char in[], out[];
{
   register USHORT i, n;

   for (i = 0, n = 0; in[i] != '\0'; i++)
   {
      if (in[i] == '+')
         out[n] = in[++i] + 0x50;
      else
         out[n] = in[i];
      n++;
   }
   out[n] = '\0';
}

void draw_text(w, shad)
struct Window *w;
BOOL shad;
{
   struct RastPort *rp = w->RPort;
   long i, x, y;

   if (!shad)
      CAMMText.FrontPen = BOX_COLOR;
   else
      CAMMText.FrontPen = SHADOWBLACK;

   CAMMText.IText = (UBYTE *)"GROUP";
   PrintIText(rp, &CAMMText, (long)(Xoff+3), (long)(Yoff-14));

   for (i = 0; i < 16; i++)
   {
      CAMMText.IText = (UBYTE *)columntext[i];
      x = Xoff+(table_x[i]*BOX_W)+2;
      x += (.5 * (BOX_W - IntuiTextLength(&CAMMText)));
      y = Yoff + (table_y[i]*BOX_H) - 7;
      PrintIText(rp, &CAMMText, x, y);
   }
   for (i = 0; i < 7; i++)
   {
      CAMMText.IText = (UBYTE *)rowtext[i];
      x = (Xoff - IntuiTextLength(&CAMMText))/2;
      y = Yoff+(i*BOX_H)+ROWNUM_Y;
      PrintIText(rp, &CAMMText, x, y);
   }

   draw_data(rp, &tabledata[0], Xoff, Yoff);
}

void draw_box(rp, x, y, width, height)
struct RastPort *rp;
long x, y, width, height;
{
   Move(rp, x, y);
   Draw(rp, x+width, y);
   Draw(rp, x+width, y+height);
   Draw(rp, x, y+height);
   Draw(rp, x, y);
}

void draw_data(rp, data, x, y)
struct RastPort *rp;
int data[];
long x, y;
{
   long i;

   Move(rp, (long)(data[0]+x), (long)(data[1]+y));

   for (i = 2; data[i] != -1; i += 2)
   {
      if (data[i] < 0)
         Move(rp, (long)((-data[i])+x), (long)(data[i+1]+y));
      else
         Draw(rp, (long)(data[i]+x), (long)(data[i+1]+y));
   }
}

info_window(num)
int num;
{
   struct Window *iwindow;
   LONG pro, neu;
   char title[80];

   pro = element[num].number;
   neu = (long)info[num].AWeight;
   if (neu < 0)
      neu = -neu;
   neu -= pro;
   sprintf(title,"%s: %s (P:%d N:%d E:%d)", element[num].symbol,
      element[num].name, pro, neu, pro);

   pro = Xoff + (element[num].column * BOX_W) - (.5 * IWIN_WIDTH);
   neu = Yoff + (element[num].row * BOX_H) - (.5 * IWIN_HEIGHT);
   if (pro < 0) pro = 0;
   if (pro > SCREEN_WIDTH-IWIN_WIDTH) pro = SCREEN_WIDTH-IWIN_WIDTH;
   if (neu < EWIN_TOP) neu = EWIN_TOP;
   if (neu > SCREEN_HEIGHT-IWIN_HEIGHT) neu = SCREEN_HEIGHT-IWIN_HEIGHT;

   iwindow = get_window(pro,neu,IWIN_WIDTH,IWIN_HEIGHT,title);
   if (iwindow == NULL)
      return(NULL);

   draw_infotext(iwindow);
   draw_info(iwindow, num);

   return(TRUE);
}

void draw_infotext(window)
struct Window *window;
{
   struct RastPort *rp = window->RPort;
   register USHORT i;

   TextText.FrontPen = GREENTEXT;

   for (i = 0; i < INFOTEXT; i++)
   {
      TextText.IText = (UBYTE *)infotext[i];
      PrintIText(rp, &TextText, (long)INFOTEXTX, (long)(((i+1)*10)+3));
   }
   TextText.IText = (UBYTE *)"Stable Form:";
   PrintIText(rp, &TextText, 214L, 13L);
   TextText.IText = (UBYTE *)"Crystal";
   PrintIText(rp, &TextText, 312L, 63L);
   TextText.IText = (UBYTE *)"Structure:";
   PrintIText(rp, &TextText, 304L, 73L);
}

void draw_info(window, num)
struct Window *window;
int num;
{
   struct RastPort *rp = window->RPort;
   register USHORT i;
   char info_t[INFOTEXT][25];
   char floattext[25], modtext[25];

   TextText.FrontPen = REDTEXT;
   TextText.IText = (UBYTE *)elem_type[element[num].type-1];
   PrintIText(rp, &TextText, 318L, 13L);

   if (info[num].OxiStates[0] == '*')
      info[num].OxiStates[0] = 0xB1;

   TextText.IText = (UBYTE *)structuretext[info[num].Structure];
   i = 343 - (.5 * IntuiTextLength(&TextText));
   PrintIText(rp, &TextText, (long)i, 83L);

   if (info[num].Structure < 8)
      draw_data(rp, structuredata[info[num].Structure], 324L, 93L);

   sprintf(info_t[0], "%f", info[num].AWeight);
   convert_super(info[num].Config, info_t[1]);
   sprintf(info_t[2], "%s", info[num].OxiStates);
   sprintf(info_t[5], "%f", info[num].Density);
   sprintf(info_t[6], "%f", info[num].CRadius);
   sprintf(info_t[7], "%f", info[num].ARadius);
   sprintf(info_t[8], "%f", info[num].AVolume);
   sprintf(info_t[9], "%f", info[num].IonPot);
   sprintf(info_t[10], "%f", info[num].SpecHeat);
   sprintf(info_t[11], "%f", info[num].Electroneg);
   sprintf(info_t[12], "%f", info[num].HeatVap);
   sprintf(info_t[13], "%f", info[num].HeatFus);
   convert_super(info[num].ElecCond, info_t[14]);
   sprintf(info_t[15], "%f", info[num].ThermalCond);

   shfloat(info_t[0]);
   for (i = 5; i < 14; i++)
      shfloat(info_t[i]);
   shfloat(info_t[15]);

   if (info[num].AWeight < 0)
   {
      info_t[0][0] = '(';
      info_t[0][4] = ')';
      info_t[0][5] = '\0';
   }
   if (info[num].BoilingP == 0.0)
      sprintf(info_t[3], "-");
   else
   {
      sprintf(floattext, "%.3f", info[num].BoilingP);
      sprintf(modtext, "%.3f", (info[num].BoilingP-273.0));
      shfloat(floattext);
      shfloat(modtext);
      sprintf(info_t[3], "%s°K (%s°C)", floattext,modtext);
   }
   if (info[num].MeltingP == 0.0)
      sprintf(info_t[4], "-");
   else
   {
      sprintf(floattext, "%.3f", info[num].MeltingP);
      sprintf(modtext, "%.3f", (info[num].MeltingP-273.0));
      shfloat(floattext);
      shfloat(modtext);
      sprintf(info_t[4], "%s°K (%s°C)", floattext,modtext);
   }
   for (i = 1; info_t[14][i] != '\0'; i++)
      if (info_t[14][i] == '-')
         info_t[14][i] = 0x8E;

   for (i = 0; i < INFOTEXT; i++)
   {
      if (i == 2)
      {
         PrintBText(rp, info_t[i], (long)info_x[i], (long)(((i+1)*10)+3));
         continue;
      }
      TextText.IText = (UBYTE *)info_t[i];
      PrintIText(rp, &TextText, (long)info_x[i], (long)(((i+1)*10)+3));
   }
}

void PrintBText(rp, text, x, y)
struct RastPort *rp;
char *text;
long x, y;
{
   register USHORT i;
   char letter[2];

   for (i = 0; text[i] != '\0'; i++)
   {
      if (text[i] == 'B')
      {
         sprintf(letter,"%c",text[++i]);
         TextText.IText = (UBYTE *)letter;
         PrintIText(rp, &TextText, x, y);
         PrintIText(rp, &TextText, x+1, y);
      }
      else
      {
         sprintf(letter,"%c",text[i]);
         TextText.IText = (UBYTE *)letter;
         PrintIText(rp, &TextText, x, y);
      }
      x += 8;
   }
}

shfloat(text)
char *text;
{
   register USHORT i;
   USHORT decimal = NULL;

   if (text[0] == '0' && text[1] == '\0')
   {
      text[0] = '-';
      return(NULL);
   }
   for (i = 0; text[i] != '\0'; i++)
   {
      if (text[i] == '.')
         decimal = 1;
   }
   if (!decimal)
      return(NULL);

   while (--i > 0)
   {
      if ((text[i] != '0') || (text[i-1] == '.'))
         break;
      text[i] = '\0';
   }
   if (text[0] == '0' && text[3] == '\0')
   {
      text[0] = '-';
      text[1] = '\0';
   }
}

load_info()
{
   register LONG fd;
   register USHORT i;

   fd = (LONG)Open(INFO_FILE, MODE_OLDFILE);
   if (!fd)
      return(NULL);

   for (i = 0; i < ELEMENTS; i++)
   {
      Read(fd, &info[i].Structure, 2L);
      Read(fd, &info[i].AWeight, 4L);
      Read(fd, &info[i].Config, 25L);
      Read(fd, &info[i].OxiStates, 11L);
      Read(fd, &info[i].BoilingP, 4L);
      Read(fd, &info[i].MeltingP, 4L);
      Read(fd, &info[i].Density, 4L);
      Read(fd, &info[i].CRadius, 4L);
      Read(fd, &info[i].ARadius, 4L);
      Read(fd, &info[i].AVolume, 4L);
      Read(fd, &info[i].IonPot, 4L);
      Read(fd, &info[i].SpecHeat, 4L);
      Read(fd, &info[i].Electroneg, 4L);
      Read(fd, &info[i].HeatVap, 4L);
      Read(fd, &info[i].HeatFus, 4L);
      Read(fd, &info[i].ElecCond, 13L);
      Read(fd, &info[i].ThermalCond, 4L);
   }
   Close(fd);
   return(TRUE);
}

void open_libraries()
{
   if ((DiskfontBase = (struct DiskfontBase *)
      OpenLibrary("diskfont.library",0L)) == NULL)
      abort("Couldn't open diskfont.library!");
   if ((IntuitionBase = (struct IntuitionBase *)
      OpenLibrary("intuition.library",0L)) == NULL)
      abort("Could't open intuition.library!");
   if ((GfxBase = (struct GfxBase *)
      OpenLibrary("graphics.library",0L)) == NULL)
      abort("Couldn't open graphics.library!");

   if ((TextFont = (struct TextFont *)OpenDiskFont(&TextAttr)) == NULL)
      abort("Couldn't find CAMMtopaz.font.");
   if ((ElementFont = (struct TextFont *)OpenDiskFont(&ElementAttr)) == NULL)
      abort("Couldn't find element.font.");
   if ((CAMMFont = (struct TextFont *)OpenDiskFont(&CAMMAttr)) == NULL)
      abort("Couldn't find CAMM.font.");
}

void abort(txt)
char *txt;
{
   puts(txt);
   if (infomenu_strip) ClearMenuStrip(ewindow);
   if (ewindow) CloseWindow(ewindow);
   if (escreen) CloseScreen(escreen);
   if (TextFont) CloseFont(TextFont);
   if (CAMMFont) CloseFont(CAMMFont);
   if (ElementFont) CloseFont(ElementFont);
   if (GfxBase) CloseLibrary(GfxBase);
   if (IntuitionBase) CloseLibrary(IntuitionBase);
   if (DiskfontBase) CloseLibrary(DiskfontBase);
   exit(NULL);
}

load_elements()
{
   register LONG fd;
   USHORT num, col, row;
   char symbol[4], name[13], type[7];
   register USHORT i;

   fd = (LONG)Open(ELEMENTS_FILE, MODE_OLDFILE);
   if (!fd)
      abort("Cannot find elements file.");

   for (i = 0; i < ELEMENTS; i++)
   {
      Read(fd, &num, 2L);
      Read(fd, &col, 2L);
      Read(fd, &row, 2L);
      Read(fd, &symbol, 4L);
      Read(fd, &name, 13L);
      Read(fd, &type, 7L);

      element[i].number = num;
      element[i].column = col-1;
      element[i].row = row-1;
      switch(type[1])
      {
         case 'O':
            element[i].type = SOLID_E;
            break;
         case 'I':
            element[i].type = LIQUID_E;
            break;
         case 'A':
            element[i].type = GAS_E;
            break;
         case 'Y':
            element[i].type = SYNTHETIC_E;
            break;
      }
      strcpy(element[i].symbol, symbol);
      strcpy(element[i].name, name);
   }
   Close(fd);

   *(infotext[5]+21) += 0x50;
   *(infotext[6]+17) = 0xC2;
   *(infotext[7]+15) = 0xC2;
   *(infotext[8]+17) += 0x50;
   *(infotext[14]+27) += 0x50;
   *(infotext[14]+29) = 0x95;

   return(TRUE);
}

struct Window *get_window(left,top,width,height,title)
int left, top, width, height;
UBYTE *title;
{
   struct NewWindow nw;
   struct Window *window;
   UBYTE *text;

   if (left+width > SCREEN_WIDTH)
      left = SCREEN_WIDTH-width-1;
   if (top+height > SCREEN_HEIGHT)
      top = SCREEN_HEIGHT-height-1;

   if (left < 0) left = 0;
   if (top < 0) top = EWIN_TOP;

   text = (UBYTE *)AllocMem(80L, MEMF_PUBLIC|MEMF_CLEAR);
   if (!text) return(NULL);
   strcpy(text, title);

   setmem(&nw, sizeof(nw), 0L);
   nw.TopEdge = top;
   nw.LeftEdge = left;
   nw.Width = width;
   nw.Height = height;
   nw.DetailPen = -1;
   nw.BlockPen = -1;
   nw.IDCMPFlags = NULL;
   nw.Flags = WINDOWDEPTH|WINDOWDRAG|WINDOWCLOSE|SMART_REFRESH|ACTIVATE;
   nw.Title = text;
   nw.Screen = escreen;
   nw.Type = CUSTOMSCREEN;

   window = (struct Window *)OpenWindow(&nw);
   if (window == NULL)
   {
      if (text) FreeMem(text, 80);
      return(NULL);
   }

   window->UserPort = ewindow->UserPort;
   ModifyIDCMP(window, CLOSEWINDOW | MENUPICK);

   SetMenuStrip(window, infomenu_strip);
   window->UserData = text;

   return(window);
}

close_window(window)
struct Window *window;
{
   struct IntuiMessage *message;

   if (window == NULL)
      return(NULL);

   while (message = (struct IntuiMessage *)GetMsg(window->UserPort))
   {
      if (message->IDCMPWindow == window)
         Remove(&message->ExecMessage.mn_Node);
      ReplyMsg(message);
   }
   if (window->MenuStrip)
      ClearMenuStrip(window);
   window->UserPort = NULL;
   ModifyIDCMP(window, NULL);

   if (window->UserData)
   {
      FreeMem(window->UserData, 80L);
      window->Title = NULL;
      window->UserData = NULL;
   }
   CloseWindow(window);

   return(TRUE);
}

close_all()
{
   struct Window *window = ewindow;

   while (window = ewindow->NextWindow)
   {
      ewindow->NextWindow = window->NextWindow;
      close_window(window);
   }
   ewindow->NextWindow = NULL;
   return(NULL);
}

void highlight_box(num)
int num;
{
   register int x, y;
   struct RastPort *rp = ewindow->RPort;

   x = EOFF_X + (element[num].column * BOX_W);
   y = EOFF_Y + (element[num].row * BOX_H);

   if (y > (Yoff + 6*BOX_H))
      y += .25 * BOX_H;

   SetAPen(rp, GREENTEXT);
   SetDrMd(rp, COMPLEMENT);
   RectFill(rp, x, y, x+BOX_W, y+BOX_H);
   Delay(2);
   RectFill(rp, x, y, x+BOX_W, y+BOX_H);
   SetDrMd(rp, JAM1);
}
