/**************************************************************/
/* $VER: SynthLib.c Revison 1.0                               */
/* This file is part of Synth Librarian v1.0                  */
/* ©1993-1994 Jean-Alexis MONTIGNIES                          */
/* This file must not be distributed modified or separatly    */
/* without my written permission                              */
/* See Synth_Librarian.guide for more details                 */
/**************************************************************/

/* Synth librarian main part */

#define __USE_SYSBASE
#include <exec/types.h>
#include <proto/exec.h>
#include <proto/gadtools.h>
#include <proto/intuition.h>
#include <proto/utility.h>
#include <libraries/gadtools.h>
#include <graphics/gfx.h>
#include <exec/ports.h>
#include <graphics/gfxbase.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <intuition/classes.h>
#include <intuition/classusr.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>
#include <proto/dos.h>
#include <libraries/locale.h>
#include <proto/locale.h>
#include <string.h>
#include <stdio.h>

struct LocaleBase *LocaleBase;

#define CATCOMP_NUMBERS
#define CATCOMP_BLOCK
#include "SynthLibLoc.h"

#include "SynthLib.h"
#include "SynthLibInt.h"

#define GT_STRING(G)    (((struct StringInfo *)(((struct Gadget *)(G)) -> SpecialInfo)) -> Buffer)

#define MAIN_FLAGS_CANTEND MAIN_FLAGS_COMTASK

STRPTR VersionString="$VER: Synth Librarian v1.0  ©1993-1994 Jean-Alexis MONTIGNIES";
struct DriverData *DD;
BPTR DSeg;
struct DriverData *(*DInit)(ULONG (*GetData)(ULONG));
struct DriverData *InitDriver (ULONG (*GetData)(ULONG));

struct LocaleInfo MLi;
struct MsgPort *MainPort=NULL,*ComTaskPort;
struct Process *TaskCom;
struct LibMessage *AMess,MyMess;

struct List DumpList={(struct Node*)&DumpList.lh_Tail,
                      0,(struct Node*)&DumpList.lh_Head,0,0};

typedef char String[256];
String Messages[2];

struct EasyStruct AboutES = {
    sizeof (struct EasyStruct),
    0,
    NULL,
    NULL,
    NULL
 };

ULONG Flags;
BOOL MainMessUsed;
BYTE MessageDisplayed;
ULONG SelectedNumber;
struct DumpNode *SelectedDump;
ULONG SelectedRequest;
struct Node *SelectedRequestNode;

STRPTR GetString(struct LocaleInfo *li, LONG stringNum,char *CatCompBlock);
void main(void);
int InitAll(void);
void CloseAll(void);
void EndComTask(void);
int SendMainMsg(UBYTE Code,APTR Data);
void StartComTask(void);
void HandleCom( void );
void AvailablesGadgets( void );
void NewMessage(char *Str,UBYTE Code);
void SelectDump(ULONG Number);
void SelectRequest(ULONG Number);
void AknowledgeMessage( void );
void AddDumpToList(struct DumpNode *Node);
void DropDump(struct DumpNode *ANode);
void LoadDriver(STRPTR Name);
ULONG GetData(ULONG Number);
BOOL CloseDriver(void);
BPTR GetDriverSeg(void);

STRPTR GetString(struct LocaleInfo *li, LONG stringNum,char *CatCompBlock)
{
LONG   *l;
UWORD  *w;
STRPTR  builtIn;

    l = (LONG *)CatCompBlock;

    while (*l != stringNum)
    {
        w = (UWORD *)((ULONG)l + 4);
        l = (LONG *)((ULONG)l + (ULONG)*w + 6);
    }
    builtIn = (STRPTR)((ULONG)l + 6);

    if (LocaleBase)
        return(GetCatalogStr(li->li_Catalog,stringNum,builtIn));

    return(builtIn);
}

int InitAll()
 {int ReturnCode=0;
  if (LocaleBase=MLi.li_LocaleBase=OpenLibrary("locale.library",0L))
    MLi.li_Catalog=OpenCatalog(NULL,"SynthLib/SynthLib.catalog",OC_BuiltInLanguage,"english",TAG_DONE);

  if (!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L)))
    ReturnCode=MG_INIT_GRAPHICS;

  if (!ReturnCode)
    if (!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",37L)))
      ReturnCode=MG_INIT_INTUITION;

  if (!ReturnCode)
    if (!(GadToolsBase=OpenLibrary("gadtools.library",0L)))
      ReturnCode=MG_INIT_GADTOOLS;

  if (!ReturnCode)
    if (!(UtilityBase=OpenLibrary("utility.library",0L)))
      ReturnCode=MG_INIT_UTILITY;

  if (!ReturnCode)
    if (FileOpInit())
      ReturnCode=MG_INIT_ASL;

  if (!ReturnCode)
    if (SetupScreen())
      ReturnCode=MG_INIT_SCREEN;

  if (!ReturnCode)
    if (OpenLibWindow())
      ReturnCode=MG_INIT_WINDOW;
     else
     {
      MessageDisplayed=-1;
      SelectedNumber=~0;
      SelectedDump=NULL;
      SelectedRequest=~0;
      SelectedRequestNode=0;
     }

  if (!ReturnCode)
    if (!(MainPort=CreatePort(0,0)))
      ReturnCode=MG_INIT_PORT;
     else
     {
      MyMess.LMess.mn_ReplyPort=MainPort;
      MainMessUsed=FALSE;
     }

  Flags=0;

  return(ReturnCode);
 }

void CloseAll()
 {
  if (DD)
   {GT_SetGadgetAttrs(LibGadgets[GD_TypeList],LibWnd,NULL,GTLV_Labels,NULL,TAG_DONE);
    DD->Close();
#ifndef DEBUG_SL
    UnLoadSeg(DSeg);
#endif
   }
  LibNew();
  CloseLibWindow();
  CloseDownScreen();

  FileOpClose();

  if (UtilityBase)
    CloseLibrary(UtilityBase);

  if (GadToolsBase)
    CloseLibrary(GadToolsBase);

  if (IntuitionBase)
    CloseLibrary((struct Library *)IntuitionBase);

  if (GfxBase)
    CloseLibrary((struct Library *)GfxBase);

  if (MainPort)
    DeletePort(MainPort);

  if (MLi.li_LocaleBase)
   {
    CloseCatalog(MLi.li_Catalog);
    CloseLibrary(MLi.li_LocaleBase);
   }
 }

void NewMessage(char *Str,UBYTE Code)
 {if (Str && (Code>=0) && (Code<=1))
   {stccpy(Messages[Code],Str,255);
    if (MessageDisplayed<=Code)
     {MessageDisplayed=Code;
      GT_SetGadgetAttrs(LibGadgets[GD_Info],LibWnd,NULL,GTTX_Text,Messages[Code],TAG_DONE);
     }
   }
 }

void AknowledgeMessage()
 {if (MessageDisplayed>=1)
   {MessageDisplayed--;
    GT_SetGadgetAttrs(LibGadgets[GD_Info],LibWnd,NULL,GTTX_Text,Messages[MessageDisplayed],TAG_DONE);
   }
 }

int LibCloseWindow(void)
 {Flags|=MAIN_FLAGS_END;
  EndComTask();
  return(0);
 }

int DataNodesClicked()
 {SelectDump(LibMsg.Code);
  return(0);
 }

int NodeNameClicked()
 {if (SelectedNumber!=~0)
   {GT_SetGadgetAttrs(LibGadgets[GD_DataNodes],LibWnd,NULL,GTLV_Labels,~0,TAG_DONE);
    stccpy(SelectedDump->Name,GT_STRING(LibMsg.IAddress),32);
    GT_SetGadgetAttrs(LibGadgets[GD_DataNodes],LibWnd,NULL,GTLV_Labels,&DumpList,TAG_DONE);
    SelectDump(~0);
   }
  return(0);
 }

int AboutLib()
 {AboutES.es_TextFormat=GetString(&MLi,MG_INFO_ABOUT,MainCatBlock);
  AboutES.es_GadgetFormat=GetString(&MLi,MG_INFO_OK,MainCatBlock);
  EasyRequest( LibWnd, &AboutES, NULL );
  return(0);
 }

int AboutDriver(void)
 {if (DD && DD->About)
   {AboutES.es_TextFormat=DD->About();
    AboutES.es_GadgetFormat=GetString(&MLi,MG_INFO_OK,MainCatBlock);
    EasyRequest( LibWnd, &AboutES, NULL );
   }
  return(0);
 }

int RemoveLib()
 {if (SelectedDump)
   {struct DumpNode *RNode;

    RNode=SelectedDump;
    SelectDump(~0);
    GT_SetGadgetAttrs(LibGadgets[GD_DataNodes],LibWnd,NULL,GTLV_Labels,~0,TAG_DONE);
    DropDump(RNode);
    GT_SetGadgetAttrs(LibGadgets[GD_DataNodes],LibWnd,NULL,GTLV_Labels,&DumpList,TAG_DONE);
   }
  return(0);
 }

int SENDClicked()
 {if (SelectedNumber!=~0)
    if(!SendMainMsg(MSGCODE_SEND,(APTR)SelectedDump))
     {
      SelectedDump->Flags|=NODE_FLAGS_BUSY;
      Flags|=MAIN_FLAGS_SEND;

      AvailablesGadgets();
     }
  return(0);
 }

int AbortClicked()
 {SendMainMsg(MSGCODE_ABORT,0);
  return(0);
 }

int TypeListClicked()
 {SelectRequest(LibMsg.Code);
  return(0);
 }

int RequestClicked()
 {if (SelectedRequest!=~0)
    if(!SendMainMsg(MSGCODE_REQUEST,(APTR)SelectedRequestNode))
     {
      Flags|=MAIN_FLAGS_REQUEST;

      AvailablesGadgets();
     }
  return(0);
 }

void DropDump(struct DumpNode *ANode)
 {if (!(ANode->Flags & NODE_FLAGS_BUSY))
   {
    Remove((struct Node *)ANode);
    FreeMem(ANode->Dump,ANode->DumpLength);
    if (ANode->Data)
      FreeMem(ANode->Data,ANode->DataLength);

    FreeMem(ANode,sizeof(struct DumpNode));
   }
   else
    NewMessage(GetString(&MLi,MG_ERROR_INUSE,MainCatBlock),1);
 }

int LibNew()
 {struct DumpNode *Node1,*Node2;

  SelectDump(~0);

  GT_SetGadgetAttrs(LibGadgets[GD_DataNodes],LibWnd,NULL,GTLV_Labels,~0,TAG_DONE);
  Node1=(struct DumpNode *)DumpList.lh_Head;

  while (Node2=(struct DumpNode *)Node1->DNode.ln_Succ)
   {DropDump(Node1);
    Node1=Node2;
   }

  GT_SetGadgetAttrs(LibGadgets[GD_DataNodes],LibWnd,NULL,GTLV_Labels,&DumpList,TAG_DONE);

  Flags&=~MAIN_FLAGS_NAMED;
  return(0);
 }

void AddDumpToList(struct DumpNode *Node)
 {Node->DNode.ln_Name=(char *)&(Node->Name);
  Node->Flags&=~NODE_FLAGS_BUSY;

  if (!(Node->Name[0]))
    strcpy(Node->Name,"Unnamed");

  if (!(Node->Type[0]))
    strcpy(Node->Type,"Unknown");

  SelectDump(~0);
  GT_SetGadgetAttrs(LibGadgets[GD_DataNodes],LibWnd,NULL,GTLV_Labels,~0,TAG_DONE);

  AddTail(&DumpList,(struct Node *)Node);

  GT_SetGadgetAttrs(LibGadgets[GD_DataNodes],LibWnd,NULL,GTLV_Labels,&DumpList,TAG_DONE);

  AvailablesGadgets();
 }

void SelectDump(ULONG Number)
 {
  SelectedNumber=Number;
  if (SelectedNumber==~0)
   {
    SelectedDump=0;
    GT_SetGadgetAttrs(LibGadgets[GD_DUMP_TYPE],LibWnd,NULL,GTTX_Text,NULL,TAG_DONE);
    GT_SetGadgetAttrs(LibGadgets[GD_DUMP_LENGTH],LibWnd,NULL,GTNM_Number,0,TAG_DONE);
   }
   else
   {SelectedDump=(struct DumpNode *)DumpList.lh_Head;

    while((SelectedDump->DNode.ln_Succ) && Number--)
      SelectedDump=(struct DumpNode *)SelectedDump->DNode.ln_Succ;

    if (SelectedDump->DNode.ln_Succ)
     {
      GT_SetGadgetAttrs(LibGadgets[GD_DUMP_TYPE],LibWnd,NULL,GTTX_Text,SelectedDump->Type,TAG_DONE);
      GT_SetGadgetAttrs(LibGadgets[GD_DUMP_LENGTH],LibWnd,NULL,GTNM_Number,(ULONG)SelectedDump->DumpLength,TAG_DONE);
     }
     else
     {SelectedNumber=~0;
      SelectedDump=NULL;
     }
   }
  AvailablesGadgets();
 }

void SelectRequest(ULONG Number)
 {
  if (DD)
    if (DD->TypeList)
     {SelectedRequest=Number;
      if (SelectedRequest==~0)
        SelectedRequestNode=0;
       else
       {SelectedRequestNode=DD->TypeList->lh_Head;

        while((SelectedRequestNode->ln_Succ) && Number--)
          SelectedRequestNode=SelectedRequestNode->ln_Succ;

        if (!SelectedRequestNode->ln_Succ)
         {SelectedRequest=~0;
          SelectedRequestNode=NULL;
         }
       }
     }
     else
     {SelectedRequestNode=0;
      SelectedRequest=~0;
     }
   else
   {SelectedRequestNode=0;
    SelectedRequest=~0;
   }

  AvailablesGadgets();
 }

int SERIALClicked( void )
 {if (!(Flags & (MAIN_FLAGS_CLOSETASK | MAIN_FLAGS_END)))
   {if (Flags & MAIN_FLAGS_COMTASK)
      EndComTask();
     else
      StartComTask();
   }

  return (0);
 }


int NewDriver(void)
 {if (!(Flags & MAIN_FLAGS_CHANGE_DRIVER))
    if (CloseDriver())
      LoadDriver(NULL);
     else
      Flags|=MAIN_FLAGS_CHANGE_DRIVER;

  return(0);
 }

BOOL CloseDriver(void)
 {BOOL ReturnCode;

  if (DD)
    if (Flags & MAIN_FLAGS_DRIVER)
     {
      SendMainMsg(MSGCODE_QUIT_DRIVER,0);
      ReturnCode=FALSE;
     }
     else
     {
      SelectRequest(~0);
      GT_SetGadgetAttrs(LibGadgets[GD_TypeList],LibWnd,NULL,GTLV_Labels,0,TAG_DONE);
      DD->Close();
      DD=NULL;
      ReturnCode=TRUE;
     }
   else
    ReturnCode=TRUE;

  return(ReturnCode);
 }

void EndComTask(void)
{
 if (Flags & MAIN_FLAGS_COMTASK)
  {Flags|=MAIN_FLAGS_CLOSETASK;
   SendMainMsg(MSGCODE_EXIT,0);
   AvailablesGadgets();
  }
}

int SendMainMsg(UBYTE Code,APTR Data)
{if (MainMessUsed)
   return(1);
  else
  {MainMessUsed=TRUE;
   MyMess.Code=Code;
   MyMess.Data=Data;
   PutMsg(ComTaskPort,(struct Message *)&MyMess);
   return(0);
  }
}

void LoadDriver(STRPTR Name)
 {
  Flags&=~MAIN_FLAGS_CHANGE_DRIVER;

#ifndef DEBUG_SL
  if (Name)
    DSeg=LoadSeg(Name);
   else
    DSeg=GetDriverSeg();
#endif

#ifndef DEBUG_SL
  if (DSeg)
   {DInit=(DSeg+1)<<2;
#else
  if (TRUE)
   {DInit=InitDriver;
#endif
    DD=DInit(GetData);
    GT_SetGadgetAttrs(LibGadgets[GD_TypeList],LibWnd,NULL,GTLV_Labels,DD->TypeList,TAG_DONE);
#ifndef DEBUG_SL
    if (!DD)
      UnLoadSeg(DSeg);
#endif
    if (Flags & MAIN_FLAGS_COMTASK)
     {
      SendMainMsg(MSGCODE_NEW_DRIVER,(UBYTE *)DD->Driver);
      Flags|=MAIN_FLAGS_CHANGE_DRIVER;
     }
   }
   else
    DD=NULL;
 }

__saveds ULONG GetData(ULONG Number)
{ULONG ReturnCode;

  switch(Number)
   {case GTD_DosBase:
      ReturnCode=(ULONG)DOSBase;

      break;

    case GTD_ExecBase:
      ReturnCode=(ULONG)SysBase;

      break;

    case GTD_LocaleBase:
      ReturnCode=(ULONG)LocaleBase;

      break;

    case GTD_IntuitionBase:
      ReturnCode=(ULONG)IntuitionBase;

      break;

    default:
      ReturnCode=0;

   }
  return(ReturnCode);
 }

void StartComTask(void)
 {
  TaskCom=CreateNewProcTags(NP_Entry,ComTask,NP_StackSize,4096,
                               NP_Name,"SynthLib MIDI Task");

  if (TaskCom)
   {
    Wait(1<<(MainPort->mp_SigBit));
    AMess=(struct LibMessage *)GetMsg(MainPort);
    NewMessage(AMess->Data,AMess->Code);

    if (AMess->Code==MSGCODE_INFO)
     {ComTaskPort=AMess->LMess.mn_ReplyPort;
      Flags|=MAIN_FLAGS_COMTASK;
      if (DD)
        SendMainMsg(MSGCODE_NEW_DRIVER,(UBYTE *)DD->Driver);
     }
     else
      Flags|=MAIN_FLAGS_CLOSETASK;

    ReplyMsg((struct Message *)AMess);

    AvailablesGadgets();
   }
 }

void HandleCom( void )
 {while(AMess=(struct LibMessage *)GetMsg(MainPort))

    if(AMess->LMess.mn_ReplyPort==MainPort)

     {MainMessUsed=FALSE;
      if (AMess->Code & MSGCODE_IGNORED)
        switch(AMess->Code & ~MSGCODE_IGNORED)
         {case MSGCODE_SEND:
            ((struct DumpNode *)AMess->Data)->Flags&=~NODE_FLAGS_BUSY;
            Flags&=~MAIN_FLAGS_SEND;
            AvailablesGadgets();

            break;

          case MSGCODE_REQUEST:

            Flags&=~MAIN_FLAGS_REQUEST;

            break;

          case MSGCODE_NEW_DRIVER:

            Flags&=~MAIN_FLAGS_CHANGE_DRIVER;

            break;
         }
       else
        switch(AMess->Code)
         {case MSGCODE_NEW_DRIVER:

            Flags|=MAIN_FLAGS_DRIVER;
            Flags&=~MAIN_FLAGS_CHANGE_DRIVER;
         }
     }
     else
     {
      switch (AMess->Code)
       {case MSGCODE_REQ_RESULT:

          Flags&=~MAIN_FLAGS_REQUEST;
          if (AMess->Data)
            AddDumpToList((struct DumpNode *)AMess->Data);
           else
            AvailablesGadgets();

          break;

        case MSGCODE_BYE:
          Signal((struct Task *)TaskCom,SIGBREAKF_CTRL_C);
          Flags&=~(MAIN_FLAGS_COMTASK | MAIN_FLAGS_CLOSETASK | MAIN_FLAGS_DRIVER | MAIN_FLAGS_CHANGE_DRIVER);
          AvailablesGadgets();
          NewMessage(AMess->Data,0);

          break;

        case MSGCODE_DRIVER_QUITED:
          Flags&=~MAIN_FLAGS_DRIVER;
          AvailablesGadgets();
          CloseDriver();
          if (Flags & MAIN_FLAGS_CHANGE_DRIVER)
           {
            LoadDriver(NULL);
           }

          break;

        case MSGCODE_DATA:

          AddDumpToList((struct DumpNode *)AMess->Data);

          break;

        case MSGCODE_SEND_FINISHED:

          ((struct DumpNode *)AMess->Data)->Flags&=~NODE_FLAGS_BUSY;
          Flags&=~MAIN_FLAGS_SEND;

          AvailablesGadgets();

          break;

        case MSGCODE_INFO:
        case MSGCODE_ERROR:

          NewMessage(AMess->Data,AMess->Code);

          break;
       }
      ReplyMsg((struct Message *)AMess);
     }
 }

void AvailablesGadgets( void )
 {BOOL Cond1;
  /*if ((Flags & FLAGS_MAIN_COMTASK) && !(Flags & FLAGS_CLOSETASK))*/
  GT_SetGadgetAttrs(LibGadgets[GD_SERIAL],LibWnd,NULL,GTCB_Checked,((Flags&MAIN_FLAGS_COMTASK)!=0),TAG_DONE);
  GT_SetGadgetAttrs(LibGadgets[GD_SERIAL],LibWnd,NULL,GA_Disabled,((Flags & MAIN_FLAGS_CLOSETASK)!=0),TAG_DONE);
  Cond1=((Flags & MAIN_FLAGS_COMTASK) && (Flags & MAIN_FLAGS_DRIVER) && !(Flags & (MAIN_FLAGS_CLOSETASK | MAIN_FLAGS_SEND | MAIN_FLAGS_REQUEST)));
  GT_SetGadgetAttrs(LibGadgets[GD_SEND],LibWnd,NULL,GA_Disabled,(!Cond1 || (SelectedNumber==~0)),TAG_DONE);
  GT_SetGadgetAttrs(LibGadgets[GD_Request],LibWnd,NULL,GA_Disabled,(!Cond1 || (SelectedRequest==~0)),TAG_DONE);
 }

void main( void )
 {int Error;
  ULONG WaitCom,WaitIntui,WaitAll,WichSignal;

  Error=InitAll();

  if (!Error)
   {
    StartComTask();

    WaitIntui=1<<(LibWnd->UserPort->mp_SigBit);
    WaitCom=1<<(MainPort->mp_SigBit);
    WaitAll=WaitCom | WaitIntui;

    HandleLibIDCMP();
    HandleCom();

      while ((Flags & MAIN_FLAGS_CANTEND) || !(Flags & MAIN_FLAGS_END))
       {WichSignal=Wait(WaitAll);
        if (WichSignal & WaitIntui)
          HandleLibIDCMP();
        if (WichSignal & WaitCom)
          HandleCom();
       }
   }
   else
     printf("%s\n",GetString(&MLi,Error,MainCatBlock));
  CloseAll();
 }
