
/* main.c  contains init- and close routines and main message-loop */

#include <exec/io.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <devices/inputevent.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <libraries/gadtools.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>

struct Requester *BlockInput();
UBYTE CXPos();
void CleanExit();

struct IntuitionBase *IntuitionBase;
struct Library *GadToolsBase, *AslBase;
struct Device *ConsoleDevice;
struct Window *Window;
struct RastPort *RPort;
struct Image_plus *Images;
struct Requester *OBlock;
APTR My_VisualInfo;
struct Menu *My_MenuStrip;
UBYTE *BB, *RB;
struct IOStdReq ConReq;
int drive, lastdrive;
ULONG CurBlock;
UBYTE CursorX, CursorY, OldCursorX, OldCursorY, RealCursorY;

extern struct NewMenu My_NewMenu[];

struct Image_plus
{
   UWORD  Im_Data[40];
   struct Image  Im_Im;
};

struct Image_plus Up_arrow =
{
   0x0000, 0x0000, 0x0000, 0x1000, 0x0060, 0x1000, 0x00f0, 0x1000,
   0x01f8, 0x1000, 0x03fc, 0x1000, 0x07fe, 0x1000, 0x0fff, 0x1000,
   0x0000, 0x1000, 0xffff, 0xf000,
   0xffff, 0xf000, 0x8000, 0x0000, 0x8000, 0x0000, 0x8000, 0x0000,
   0x8000, 0x0000, 0x8000, 0x0000, 0x8000, 0x0000, 0x8000, 0x0000,
   0x8000, 0x0000, 0x0000, 0x0000,
   0, 0, 20, 10, 2, NULL, 3, 0, NULL
};

struct Image_plus Down_arrow =
{
   0x0000, 0x0000, 0x0000, 0x1000, 0x0fff, 0x1000, 0x07fe, 0x1000,
   0x03fc, 0x1000, 0x01f8, 0x1000, 0x00f0, 0x1000, 0x0060, 0x1000,
   0x0000, 0x1000, 0xffff, 0xf000,
   0xffff, 0xf000, 0x8000, 0x0000, 0x8000, 0x0000, 0x8000, 0x0000,
   0x8000, 0x0000, 0x8000, 0x0000, 0x8000, 0x0000, 0x8000, 0x0000,
   0x8000, 0x0000, 0x0000, 0x0000,
   0, 0, 20, 10, 2, NULL, 3, 0, NULL
};

struct TextAttr  Style =
{  (UBYTE *)"topaz.font", TOPAZ_EIGHTY, FS_NORMAL, FPF_ROMFONT };

struct IntuiText
Cursor     = {  1, 0, INVERSVID | COMPLEMENT, 0, 0, &Style, (UBYTE *)" ", NULL  },
DriveText  = {  1, 0, JAM2, 50, 18, &Style, (UBYTE *)"Drive Unit", NULL  },
DF0Text    = {  1, 0, JAM2, 6, 3, &Style, (UBYTE *)"DF0:", &DriveText  },
DF1Text    = {  1, 0, JAM2, 6, 3, &Style, (UBYTE *)"DF1:", NULL  },
DF2Text    = {  1, 0, JAM2, 6, 3, &Style, (UBYTE *)"DF2:", NULL  },
DF3Text    = {  1, 0, JAM2, 6, 3, &Style, (UBYTE *)"DF3:", NULL  },
TrackText  = {  1, 0, JAM2, 9, 18, &Style, (UBYTE *)"Track", NULL  },
SectorText = {  1, 0, JAM2, 5, 18, &Style, (UBYTE *)"Sector", NULL  },
BlockText  = {  1, 0, JAM2, 9, 18, &Style, (UBYTE *)"Block", NULL  },
TestText2  = {  2, 3, JAM2, 440, 0, &Style, (UBYTE *)"0123456789ABCDEF", NULL  },
TestText   = {  1, 0, JAM2, 0, 0, &Style, (UBYTE *)
   "000: 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF", &TestText2  };


WORD
Boxpairs[]     = { 573, 1, 573, 131, 0, 131},
Boxpairsa[]    = { 0, 130, 0, 0, 573, 0 },
StrPairs[]     = { 44, 1, 44, 19, 0, 19 },
StrPairsa[]    = { 0, 18, 0, 0, 44, 0 },
DrivesPairs[]  = { 99, 1, 99, 11, 0, 11 },
DrivesPairsa[] = { 0, 10, 0, 0, 99, 0 },
TitlePairs[]   = { 51, 1, 51, 11, 0, 11 },
TitlePairsa[]  = { 0, 10, 0, 0, 51, 0 },
FourPairs[]    = { 44, 1, 44, 13, 0, 13 },
FourPairsa[]   = { 0, 12, 0, 0, 44, 0 };

struct Border
BoxBordera     = { 0, 0, 1, 0, JAM1, 3, Boxpairsa, NULL },
BoxBorder      = { 0, 0, 2, 0, JAM1, 3, Boxpairs, &BoxBordera },
StrBordera     = { -3, -6, 2, 0, JAM1, 3, StrPairsa, NULL },
StrBorder      = { -3, -6, 1 ,0, JAM1, 3, StrPairs, &StrBordera },
DrivesBordera  = { 0, 0, 1, 0, JAM1, 3, DrivesPairsa, NULL },
DrivesBorder   = { 0, 0, 2, 0, JAM1, 3, DrivesPairs, &DrivesBordera },
TitleBordera   = { 0, 0, 1, 0, JAM1, 3, TitlePairsa, NULL },
TitleBorder    = { 0, 0, 2, 0, JAM1, 3, TitlePairs, &TitleBordera },
FourBordera    = { 0, 0, 2, 0, JAM1, 3, FourPairsa, NULL },
FourBorder     = { 0, 0, 1, 0, JAM1, 3, FourPairs, &FourBordera },
FourBorderInva = { 0, 0, 1, 0, JAM1, 3, FourPairsa, NULL },
FourBorderInv  = { 0, 0, 2, 0, JAM1, 3, FourPairs, &FourBorderInva };

UBYTE TrackBuffer[4], SectorBuffer[3], BlockBuffer[5];

struct PropInfo  Schuif_info =
{  PROPNEWLOOK | FREEVERT | AUTOKNOB, 0, 0, 0, 0x8000, 0, 0, 0, 0, 0, 0   };

struct StringInfo
Track_info  = { TrackBuffer, NULL, 0, 4, 0, 0, 0, 0, 0, 0, NULL, 0, NULL },
Sector_info = { SectorBuffer, NULL, 0, 3, 0, 0, 0, 0, 0, 0, NULL, 0, NULL },
Block_info  = { BlockBuffer, NULL, 0, 5, 0, 0, 0, 0, 0, 0, NULL, 0, NULL };

/* Gadget ID's */
#define g_DF0    1
#define g_DF1    2
#define g_DF2    3
#define g_DF3    4
#define g_Track  5
#define g_Sector 6
#define g_Block  7
#define g_Schuif 8
#define g_TrUp   9
#define g_TrDown 10
#define g_SeUp   11
#define g_SeDown 12
#define g_BlUp   13
#define g_BlDown 14
#define g_Box    15

/* Raw-codes for cursor keys */
#define c_links  79
#define c_rechts 78
#define c_op     76
#define c_neer   77
#define c_min    76
#define c_max    79

struct Gadget
BoxGadget = {
   NULL, 63, 18, 528, 128, GFLG_GADGHNONE, GACT_IMMEDIATE, GTYP_BOOLGADGET,
   NULL, NULL, NULL, NULL, NULL, g_Box, NULL },
SchuifGadget = {
   &BoxGadget, 600, 16, 20, 132, GFLG_GADGHCOMP,
   GACT_RELVERIFY, GTYP_PROPGADGET,
   &Up_arrow.Im_Im, NULL, NULL, NULL, &Schuif_info, g_Schuif, NULL },
BlDownGadget = {
   &SchuifGadget, 494, 167, 20, 10, GFLG_GADGHCOMP | GFLG_GADGIMAGE,
   GACT_RELVERIFY, GTYP_BOOLGADGET, NULL, NULL, NULL, NULL, NULL, g_BlDown,
   NULL },
BlUpGadget = {
   &BlDownGadget, 494, 157, 20, 10, GFLG_GADGHCOMP | GFLG_GADGIMAGE,
   GACT_RELVERIFY, GTYP_BOOLGADGET, NULL, NULL, NULL, NULL, NULL, g_BlUp,
   NULL },
SeDownGadget = {
   &BlUpGadget, 394, 167, 20, 10, GFLG_GADGHCOMP | GFLG_GADGIMAGE,
   GACT_RELVERIFY, GTYP_BOOLGADGET, NULL, NULL, NULL, NULL, NULL, g_SeDown,
   NULL },
SeUpGadget = {
   &SeDownGadget, 394, 157, 20, 10, GFLG_GADGHCOMP | GFLG_GADGIMAGE,
   GACT_RELVERIFY, GTYP_BOOLGADGET, NULL, NULL, NULL, NULL, NULL, g_SeUp,
   NULL },
TrDownGadget = {
   &SeUpGadget, 294, 167, 20, 10, GFLG_GADGHCOMP | GFLG_GADGIMAGE,
   GACT_RELVERIFY, GTYP_BOOLGADGET, NULL, NULL, NULL, NULL, NULL, g_TrDown,
   NULL },
TrUpGadget = {
   &TrDownGadget, 294, 157, 20, 10, GFLG_GADGHCOMP | GFLG_GADGIMAGE,
   GACT_RELVERIFY, GTYP_BOOLGADGET, NULL, NULL, NULL, NULL, NULL, g_TrUp,
   NULL },
BlockGadget = {
   &TrUpGadget, 452, 163, 43, 13, GFLG_GADGHCOMP,
   GACT_RELVERIFY | GACT_STRINGCENTER | GACT_LONGINT, GTYP_STRGADGET,
   (APTR)&StrBorder, NULL, &BlockText, NULL, &Block_info, g_Block, NULL },
SectorGadget = {
   &BlockGadget, 352, 163, 43, 13, GFLG_GADGHCOMP,
   GACT_RELVERIFY | GACT_STRINGCENTER | GACT_LONGINT, GTYP_STRGADGET,
   (APTR)&StrBorder, NULL, &SectorText, NULL, &Sector_info, g_Sector, NULL },
TrackGadget = {
   &SectorGadget, 252, 163, 43, 13, GFLG_GADGHCOMP,
   GACT_RELVERIFY | GACT_STRINGCENTER | GACT_LONGINT, GTYP_STRGADGET,
   (APTR)&StrBorder, NULL, &TrackText, NULL, &Track_info, g_Track, NULL },
DF3Gadget = {
   &TrackGadget, 163, 160, 45, 14, GFLG_GADGHNONE, GACT_IMMEDIATE,
   GTYP_BOOLGADGET, (APTR)&FourBorder, NULL, &DF3Text, NULL, NULL, g_DF3,
   NULL },
DF2Gadget = {
   &DF3Gadget, 118, 160, 45, 14, GFLG_GADGHNONE, GACT_IMMEDIATE,
   GTYP_BOOLGADGET, (APTR)&FourBorder, NULL, &DF2Text, NULL, NULL, g_DF2,
   NULL },
DF1Gadget = {
   &DF2Gadget, 73, 160, 45, 14, GFLG_GADGHNONE, GACT_IMMEDIATE,
   GTYP_BOOLGADGET, (APTR)&FourBorder, NULL, &DF1Text, NULL, NULL, g_DF1,
   NULL },
DF0Gadget = {
   &DF1Gadget, 28, 160, 45, 14, GFLG_GADGHNONE, GACT_IMMEDIATE,
   GTYP_BOOLGADGET, (APTR)&FourBorderInv, NULL, &DF0Text, NULL, NULL, g_DF0,
   NULL };

struct Gadget *DriveGadgets[] =
{  &DF0Gadget, &DF1Gadget, &DF2Gadget, &DF3Gadget };

long main()
{
   struct IntuiMessage *message;
   UWORD  code, GadgetNr;
   struct InputEvent IE;
   UBYTE IEString[20];
   int drive2, td_err;
   ULONG L;
   BOOL loop = TRUE;

   Open_All();
   td_err = ReadBlocks(drive, (WORD) Block_info.LongInt, 1, BB);
   if (td_err) ProcessTDError(td_err);
   CursorX = 0;
   CursorY = 0;
   UpDateSB();
   UnBlockInput(OBlock, Window);

   while(loop)
   {
      if (!(message = (struct IntuiMessage *) GetMsg(Window->UserPort)))
      {
         Wait(1L << Window->UserPort->mp_SigBit);
         continue;
      }
      code = message->Code;
      if (message->Class & (IDCMP_GADGETUP | IDCMP_GADGETDOWN))
         GadgetNr = ((struct Gadget *) message->IAddress)->GadgetID;
      switch(message->Class)
      {
         case IDCMP_MENUPICK:
            loop = DoMenu(MENUNUM(code), ITEMNUM(code), SUBNUM(code));
            break;

         case IDCMP_RAWKEY:
            if ((code >= c_min) && (code <= c_max))
            {
               switch(message->Code)
               {
                  case c_op:
                     if (RealCursorY > 0)
                     {
                        RealCursorY--;
                        if (CursorY == 0)
                        {
                           L = (ULONG) RealCursorY * 65536 / 16;
                           NewModifyProp(&SchuifGadget, Window, NULL,
                              Schuif_info.Flags, 0, (UWORD) L, 0,
                              Schuif_info.VertBody, 1);
                           UpDateSB();
                        }
                        else
                        {
                           CursorY--;
                           UpDateCursor();
                        }
                     }
                     break;

                  case c_neer:
                     Cursor_Neer();
                     break;

                  case c_links:
                     if (CursorX > 0)
                     {
                        CursorX--;
                        UpDateCursor();
                     }
                     break;

                  case c_rechts:
                     if (CursorX < 47)
                     {
                        CursorX++;
                        UpDateCursor();
                     }
                     break;
               }
            }
            else if (code == 0x41)
            {
               if (CursorX > 0)
               {
                  CursorX--;
                  UpDateCursor();
               }
            }
            else if ((code == 0x44) && (RealCursorY != 31))
            {
               if (CursorX >= 32)
               {
                  CursorX = 32;
                  Cursor_Neer();
               }
               else
               {
                  CursorX = 0;
                  Cursor_Neer();
               }
            }

            else  /* Convert Rawkey to ASCII */
            {
               IE.ie_NextEvent = NULL;
               IE.ie_Class = IECLASS_RAWKEY;
               IE.ie_Code = code;
               IE.ie_Qualifier = message->Qualifier;
               if (RawKeyConvert(&IE, IEString, 20L, NULL) == 1)
                  Process_VKey(IEString[0]);
            }
            break;

         case IDCMP_GADGETDOWN:
            if (GadgetNr == g_Box)
            {
               Process_MPos((message->MouseX-63)/8, (message->MouseY-18)/8);
            }
            else if ((GadgetNr >= g_DF0) && (GadgetNr <= g_DF3))
            {
               drive2 = GadgetNr - g_DF0;
               if (drive2 != drive)
               {
                  DriveGadgets[drive2]->GadgetRender = &FourBorderInv;
                  DriveGadgets[drive]->GadgetRender = &FourBorder;
                  RefreshGList(DriveGadgets[drive2], Window, NULL, 1);
                  RefreshGList(DriveGadgets[drive], Window, NULL, 1);
                  drive = drive2;
                  CheckBlock();
               }
            }
            break;

         case IDCMP_GADGETUP:
            switch(GadgetNr)
            {
               case g_Track:
                  if (Track_info.LongInt > 159L) Track_info.LongInt = 159L;
                  if (Track_info.LongInt < 0L) Track_info.LongInt = 0L;
                  sprintf(TrackBuffer, "%d\x00", Track_info.LongInt);
                  RefreshGList(&TrackGadget, Window, NULL, 1);
                  UpDateBlockG();
                  CheckBlock();
                  break;

               case g_Sector:
                  if (Sector_info.LongInt > 10L) Sector_info.LongInt = 10L;
                  if (Sector_info.LongInt < 0L) Sector_info.LongInt = 0L;
                  sprintf(SectorBuffer, "%d\x00", Sector_info.LongInt);
                  RefreshGList(&SectorGadget, Window, NULL, 1);
                  UpDateBlockG();
                  CheckBlock();
                  break;

               case g_Block:
                  if (Block_info.LongInt > 1759L) Block_info.LongInt = 1759L;
                  if (Block_info.LongInt < 0L) Block_info.LongInt = 0L;
                  sprintf(BlockBuffer, "%d\x00", Block_info.LongInt);
                  RefreshGList(&BlockGadget, Window, NULL, 1);
                  UpDateTrSeG();
                  CheckBlock();
                  break;

               case g_Schuif:
                  UpDateSB();
                  break;

               case g_TrUp:
                  if (Track_info.LongInt < 159L)
                  {
                     sprintf(TrackBuffer, "%d\x00", ++Track_info.LongInt);
                     RefreshGList(&TrackGadget, Window, NULL, 1);
                     UpDateBlockG();
                     CheckBlock();
                  }
                  break;

               case g_TrDown:
                  if (Track_info.LongInt > 0L)
                  {
                     sprintf(TrackBuffer, "%d\x00", --Track_info.LongInt);
                     RefreshGList(&TrackGadget, Window, NULL, 1);
                     UpDateBlockG();
                     CheckBlock();
                  }
                  break;

               case g_SeUp:
                  if (Sector_info.LongInt < 21L)
                  {
                     sprintf(SectorBuffer, "%d\x00", ++Sector_info.LongInt);
                     RefreshGList(&SectorGadget, Window, NULL, 1);
                     UpDateBlockG();
                     CheckBlock();
                  }
                  break;

               case g_SeDown:
                  if (Sector_info.LongInt > 0L)
                  {
                     sprintf(SectorBuffer, "%d\x00", --Sector_info.LongInt);
                     RefreshGList(&SectorGadget, Window, NULL, 1);
                     UpDateBlockG();
                     CheckBlock();
                  }
                  break;

               case g_BlUp:
                  if (Block_info.LongInt < 1759L)
                  {
                     sprintf(BlockBuffer, "%d\x00", ++Block_info.LongInt);
                     RefreshGList(&BlockGadget, Window, NULL, 1);
                     UpDateTrSeG();
                     CheckBlock();
                  }
                  break;

               case g_BlDown:
                  if (Block_info.LongInt > 0L)
                  {
                     sprintf(BlockBuffer, "%d\x00", --Block_info.LongInt);
                     RefreshGList(&BlockGadget, Window, NULL, 1);
                     UpDateTrSeG();
                     CheckBlock();
                  }
                  break;
            }
            break;
      }
      ReplyMsg((struct Message *)message);
   }
   Close_All();
   return(0L);
}

Open_All()
{
   struct IOStdReq IO;
   int i;
   BOOL menuok = FALSE;
   ULONG MTC;

   IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 0L);
   if (IntuitionBase->LibNode.lib_Version < 37)
      CleanExit(NULL, "This program requires Kickstart 2.0 or higher");
   if (IntuitionBase->LibNode.lib_Version >= 39) MTC = 1;
   else MTC = 2;
   GadToolsBase = (struct Library *) OpenLibrary("gadtools.library", 37);
   if (!GadToolsBase) CleanExit(NULL, "Could not open gadtools.library");

   CurBlock = 880L;
   Block_info.LongInt = CurBlock;
   sprintf(BlockBuffer, "%d\x00", Block_info.LongInt);

   drive = -1;
   for (i = 0; i < 4; i++)
   {
      if (OpenDevice("trackdisk.device", i, &IO, 0))
         DriveGadgets[i]->Flags |= GFLG_DISABLED;
      else
      {
         CloseDevice(&IO);
         if (drive < 0) drive = i;
      }
   }
   if (drive < 0) CleanExit(NULL, "No diskdrives found");
   lastdrive = drive;

   if (OpenDevice("console.device", -1L, &ConReq, 0L))
      CleanExit(NULL, "Error opening console.device");
   ConsoleDevice = ConReq.io_Device;

   Images = (struct Image_plus *) AllocMem(2*sizeof(struct Image_plus), MEMF_CHIP);
   if (!Images) CleanExit(NULL, "Insufficient chip memory");
   Images[0] = Up_arrow;
   Images[1] = Down_arrow;
   Images[0].Im_Im.ImageData = &Images[0].Im_Data[0];
   Images[1].Im_Im.ImageData = &Images[1].Im_Data[0];
   TrUpGadget.GadgetRender = &Images[0].Im_Im;
   TrDownGadget.GadgetRender = &Images[1].Im_Im;
   SeUpGadget.GadgetRender = &Images[0].Im_Im;
   SeDownGadget.GadgetRender = &Images[1].Im_Im;
   BlUpGadget.GadgetRender = &Images[0].Im_Im;
   BlDownGadget.GadgetRender = &Images[1].Im_Im;

   Window = OpenWindowTags(NULL,
      WA_Title,     "TrackEd",
      WA_Flags,      0x00200000, /* OS3.0 white menus */
      WA_Gadgets, &DF0Gadget,   WA_AutoAdjust,    TRUE,
      WA_Top,           0,      WA_Left,             0,
      WA_Width,       640,      WA_Height,         200,
      WA_DragBar,    TRUE,      WA_DepthGadget,   TRUE,
      WA_Activate,   TRUE,      WA_SmartRefresh,  TRUE,
      WA_IDCMP, IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_MENUPICK |
      IDCMP_RAWKEY,
      TAG_END);

   if (!Window) CleanExit(NULL, "Unable to open window");
   OBlock = BlockInput(Window);
   RPort = Window->RPort;
   UpDateTrSeG();
   DrawBorder(RPort, &BoxBorder, 20L, 16L);
   DrawBorder(RPort, &TitleBorder, 255L, 179L);
   DrawBorder(RPort, &TitleBorder, 355L, 179L);
   DrawBorder(RPort, &TitleBorder, 455L, 179L);
   DrawBorder(RPort, &DrivesBorder, 68L, 176L);
   BB = (UBYTE *) AllocMem(2*512L, MEMF_CHIP | MEMF_CLEAR);
   if (!BB) CleanExit(Window, "Insufficient chip memory");
   RB = &BB[512];
   if (My_VisualInfo = GetVisualInfo(Window->WScreen, TAG_END))
   {
      if (My_MenuStrip = CreateMenus(My_NewMenu, GTMN_FrontPen, MTC, TAG_END))
      {
         if (LayoutMenus(My_MenuStrip, My_VisualInfo, TAG_END))
         {
            if (SetMenuStrip(Window, My_MenuStrip)) menuok = TRUE;
         }
      }
   }
   if (!menuok) CleanExit(Window, "Could not create menu");
}

void CleanExit(window, string)
struct Window *window;
UBYTE *string;
{
   ShowText(window, string, "Exit");
   Close_All();
   exit(10);
}

Close_All()
{
   if (ConsoleDevice) CloseDevice(&ConReq);
   if (Window)
   {
      ClearMenuStrip(Window);
      FreeMenus(My_MenuStrip);
      FreeVisualInfo(My_VisualInfo);
      CloseWindow(Window);
   }
   if (BB) FreeMem(BB, 2*512L);
   if (Images) FreeMem(Images, 2*sizeof(struct Image_plus));
   if (GadToolsBase) CloseLibrary(GadToolsBase);
   if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
}
