/*
***************************************************************************
*
* Datei:
*    RSysBroker.c
*
* Inhalt:
*    void InstallBroker(void);
*    void RemoveBroker(void);
*    struct Screen *FindFrontPubScr(struct Screen *activescr);
*    void HandleBrokerPort(void);
*
* Bemerkungen:
*    Broker-Verwaltungsroutinen unter Verwendung der Commodities-Library.
*
* Erstellungsdatum:
*    07-Jul-93    Rolf Böhme
*
* Änderungen:
*    07-Jul-93    Rolf Böhme    Erstellung
*
***************************************************************************
*/

#include "RSysDebug.h"
   /*
    * Die externen Funktionenreferenzen werden eingelesen.
    */
#include "RSysFunc.h"

   /*
    * Der Zeiger auf den Brokerport. An diesem liegen
    * die Nachrichten an, die vom Programm Exchange
    * abgesendet werden.
    */
struct MsgPort *broker_mp = NULL;
 
   /*
    * Die "Objekte", die die Eigenschaften der
    * Nachrichten, die an den Broker gesendet werden
    * sollen, festlegen.
    */
CxObj *broker,
     *filter[HOTKEYS],
     *sender,
     *translate;
 
   /*
    * Die Tastenkombinationen, mit denen RSys gesteuert
    * werden kann.
    */
char  hotkey[HOTKEYS][30];

   /*
    * In dieser Struktur werden alle Eigenschaften des
    * Brokers definiert. Insbesondere der Name, die
    * Version (systemabhängig), Eindeutigkeit des
    * verwendeten Broker-Namens und ob Show/Hide-
    * Nachrichten empfangen werden sollen.
    */
struct NewBroker newbroker =
{
   NB_VERSION,
   NAME,
   NAME " " VERSION " - " COPYRIGHT,
   "RSys Commodity Handler",
   NBU_UNIQUE,
   COF_SHOW_HIDE,
   0,
   0,
   0
};

   /*
    * Ein Zeiger auf den letzten PublicScreen, auf dem
    * das Hauptfenster von RSys geöffnet wurde.
    */
struct Screen *lastpubscreen = NULL;

   /*
    * Die Prozedur InstallHotKeys() bildet für alle zu
    * installierenden HotKeys einen Filter und bindet
    * diese dann in die Broker-Struktur ein.
    */
static void
InstallHotKeys(void)
{
   register int i;

   for (i = 0; i < HOTKEYS; i++)
   {
      filter[i] = HotKey((UBYTE *) & hotkey[i][0], broker_mp, (long)(i + 1));
         /*
          * Falls kein Filter erzeugt werden konnte, wird eine
          * Fehlermeldung ausgegeben und das Programm beendet.
          */
      if (NOT(filter[i]))
         ErrorHandle(BROKER_ERR, CREATE_FAIL, KILL);

      AttachCxObj(broker, filter[i]);
   }

   return;
}

   /*
    * InstallBroker() öffnet die commodities.library,
    * richtet einen MessagePort für die Nachrichten vom
    * Broker ein, initialisiert ein Broker-
    * Kontrollstruktur und startet den Broker.
    */
void
InstallBroker(void)
{
   DPOS;
      /*
       * Ein Kommunikations-Port wird erzeugt.
       */
   if (broker_mp = CreatePort((UBYTE *) "RSys-Broker-Port", 0L))
   {
      newbroker.nb_Port = broker_mp;
      newbroker.nb_Pri  = 0;

         /*
          * Falls der Broker erzeugt werden konnte, werden die
          * HotKeys installiert und der Broker gestartet.
          */
      if (broker = CxBroker(&newbroker, NULL))
         InstallHotKeys();
      else
         ErrorHandle(BROKER_ERR, CREATE_FAIL, KILL);

      ActivateCxObj(broker, TRUE);
   }
   else
         /*
          * Das Programm wird beendet, falls kein Messageport
          * eingerichtet werden konnte.
          */
      ErrorHandle(PORT_ERR, CREATE_FAIL, KILL);

   return;
}

   /*
    * RemoveBroker() entfernt alle mit dem Broker
    * verbundenen Datenstrukturen aus dem System und
    * schließt die commodities.library.
    */
void
RemoveBroker(void)
{
   DPOS;

   if (broker)
      DeleteCxObjAll(broker);

   if (broker_mp)
      DeletePort(broker_mp);

   return;
}

   /*
    * Die Funktion FindFrontPunbScr() ermittelt
    * bezüglich des aktuellen Screens, auf dem das
    * Hauptfenster geöffnet wurde, den nächsten Public
    * screen und gibt den Zeiger auf diesen zurück,
    * falls dieser ungleich dem aktuellen und zugleich
    * der vorderste Screen auf dem Bildschirm ist.
    */
struct Screen *
FindFrontPubScr(struct Screen *activescr)
{
   char  newnamebuffer[MAXPUBSCREENNAME + 1];
   UBYTE *test;
   struct Screen *NewScr;

   DPOS;
      /*
       * Der Name des aktuellen Screens, auf dem RSys
       * geöffnet wurde, wird gemerkt.
       */
   strncpy(newnamebuffer, (char *)namebuffer,MAXPUBSCREENNAME);

      /*
       * Der Zeiger des neuen Screens wird initialisiert
       * und der nächst Public screen ermittelt.
       */
   NewScr = NULL;
   test = NextPubScreen(activescr, namebuffer);

      /*
       * Solange der neue Screen nicht der vorderste
       * Screen und nicht der aktuelle ist, und der neue
       * Screen erfolgreich ermittelt werden konnte, wird
       * dieser neue getestet. Im Erfolgsfall wird ein
       * Zeiger auf diesen neuen Screen zurückgegeben.
       */
   while ((NewScr != IntuitionBase->FirstScreen) &&
          (NewScr != activescr) && test)
   {
      NewScr = LockPubScreen(namebuffer);

      if ((NewScr == IntuitionBase->FirstScreen) && (NewScr != activescr))
      {
         UnlockPubScreen(NULL, NewScr);
         return (NewScr);
      }

      UnlockPubScreen(NULL, NewScr);

      test = NextPubScreen(NewScr, namebuffer);
   }

      /*
       * Wenn das Unterprogramm bis hierher kommt, konnte
       * kein weiterer Public screen erkannt werden. Der
       * gemerkte Screen name wird zurückkopiert und der
       * Zeiger auf den aktiven Screen zurückgegeben.
       */
   strncpy((char *)namebuffer, newnamebuffer,MAXPUBSCREENNAME);

   return (activescr);
}

   /*
    * HandleBrokerPort() verarbeitet alle Nachrichten,
    * die am Broker port eintreffen.
    */
void
HandleBrokerPort(void)
{
   CxMsg *msg;
   ULONG msgid,
         msgtype;
   struct Screen *activescr;
      /*
       * Dieses Feld von Funktionenzeigern enthält alle
       * Funktionen, die entsprechend der MessageID
       * ausgeführt werden.
       */
   void  (*func[HOTKEYS - 1]) (void)=
   {CryptFile, FindFile, FormatDisk, HunkStruct,CRCSum,SaveWindows};

   DPOS;
      /*
       * Alle Messages, die am Brokerport anliegen, werden
       * bearbeitet.
       */
   while (msg = (CxMsg *) GetMsg(broker_mp))
   {
         /*
          * Aus der Message werden die notwendigen Daten
          * herauskopiert. Danach wird die Nachricht wieder
          * so schnell wie möglich beantwortet, damit der
          * Broker nicht wartet.
          */
      msgid = CxMsgID(msg);
      msgtype = CxMsgType(msg);

      ReplyMsg((struct Message *) msg);

         /*
          * Entsprechend dem Typ der Nachricht werden
          * verschiedene Aktionen ausgelöst.
          */
      switch (msgtype)
      {
            /*
             * Es handelt sich um einen Inputevent.
             */
         case CXM_IEVENT:
               /*
                * Ist die MessageID 1, soll das RSys-Hauptfenster
                * erscheinen.
                */
            if(msgid == 1)
            {
                  /*
                   * Falls das Hauptfenster bereits offen ist, wird der
                   * nächst Public screen gesucht und versucht, RSys auf
                   * diesem Screen zu öffnen. War das erfolgreich, wird
                   * das ListView des Hauptfensters aktualisiert.
                   */
               if (SysWnd)
               {
                  activescr = SysWnd->WScreen;

                  if (activescr != FindFrontPubScr(activescr))
                  {
                     CloseASysWindow(&SysWnd, &SysGList, &SysMenus);
                     CloseDownScreen();

                     OpenMainWindow();
                     RefreshList(LastID);
                  }
                  else
                     ErrorHandle(SCREEN_ERR, FIND_FAIL, NO_KILL);
               }
               else
               {
                     /*
                      * Ist das Hauptfenster noch nicht geöffnet, wird es
                      * mit der Standardprozedur geöffnet und das ListView
                      * aktualisiert.
                      */
                  OpenMainWindow();
                  RefreshList(LastID);
               }
            }
            else
            {
                  /*
                   * Ist die MessageID größer als 1, werden die
                   * entsprechenden Funktionen aus dem
                   * Funktionenzeigerfeld ausgeführt.  Ist das
                   * Hauptfenster noch nicht geöffnet worden, muß der
                   * Screen, auf dem das Fenster der jeweiligen
                   * Funktion geöffnet werden soll, mit SetupScreen()
                   * vorbereitet werden.
                   */
               if (NOT(SysWnd))
                  if (SetupScreen())
                     ErrorHandle(SCREEN_ERR, INFO_FAIL, NO_KILL);
 
               (*func[msgid - 2]) ();
 
               if (NOT(SysWnd))
                  CloseDownScreen();
            }
            break;
 
            /*
             * Es sit eine Nachricht vom Programm Exchange.
             */
         case CXM_COMMAND:
            switch (msgid)
            {
                  /*
                   * Der Broker von RSys soll ausgeschaltet werden.
                   */
               case CXCMD_DISABLE:
                  ActivateCxObj(broker, 0L);
                  break;
 
                  /*
                   * Der Broker von RSys soll eingeschaltet werden.
                   */
               case CXCMD_ENABLE:
                  ActivateCxObj(broker, 1L);
                  break;
 
                  /*
                   * Das Hauptfenster von RSys soll erscheinen.
                   */
               case CXCMD_APPEAR:
                  if (NOT(SysWnd))
                  {
                     OpenMainWindow();
                     RefreshList(LastID);
                  }
 
                  break;
 
                  /*
                   * Das Hauptfenster soll verschwinden und das AppIcon
                   * soll erscheinen.
                   */
               case CXCMD_DISAPPEAR:
                  if (SysWnd)
                     Iconify();
                  break;
 
                  /*
                   * RSys soll ohne Sicherheitsabfrage beendet werden.
                   */
               case CXCMD_KILL:
                  quit(FALSE);
                  break;
 
               case CXCMD_UNIQUE:
                     /*
                      * Ein Programm versucht einen Broker mit dem Namen
                      * RSys einzurichten. Es erscheint eine Fehlermeldung.
                      */
                  ErrorHandle(BROKER_ERR, DUPLICATE_FAIL, NO_KILL);
                  break;
            }
            break;
      }
   }
 
   return;
}
