  //*************************************************************************//
// Filename:    ProcessComm.cpp
// Autor:       Christian Taulien of Strange Intelligence
// Purpose:     Implementation für die Behandlung und die Kommunikation
//              der Prozesse
// Creation:    29. März 1998
//*************************************************************************//

#include "global.h"
#include "ProcessComm.h"
#include "WindowList.h"

#include <string.h>
#include <stdio.h>

#include <dos/dostags.h>
#include <exec/types.h>
#include <rexx/errors.h>
#include <rexx/rxslib.h>
#include <utility/tagitem.h>

#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/rexxsyslib_protos.h>
#include <clib/utility_protos.h>

extern FLXWatchListC *glob_poWatches;

struct MsgPort *glob_poReciever = NULL;
struct MsgPort *glob_poStopper  = NULL;
struct Process *glob_poWorker   = NULL;
char  *glob_sPortName           = "GOLDED.1";
WindowListC *glob_poWindowList = NULL;


ULONG* SAVEDS SendRexxCommand(UBYTE *port, UBYTE *cmd, struct MsgPort *replyPort)
/*S*/
{
  TRACE("");
  Forbid();

  struct MsgPort *rexxport;
  if (rexxport = FindPort(port))
  {
    struct RexxMsg *rexxMsg, *answer;
    if (rexxMsg = CreateRexxMsg(replyPort, NULL, NULL))
    {
      if (rexxMsg->rm_Args[0] = CreateArgstring(cmd, strlen(cmd)))
      {
        static ULONG result;

        rexxMsg->rm_Action = RXCOMM | RXFF_RESULT;
        PutMsg(rexxport, &rexxMsg->rm_Node);

        if (replyPort)
        {
          do
          {
            WaitPort(replyPort);
            if (answer = (struct RexxMsg *)GetMsg(replyPort))
            {
              result = answer->rm_Result1;
            } // if
          } while (!answer);
        } // if

        Permit();
        TRACE("zurück vom msg verschicken.");

        if (replyPort)
        {
          if (answer->rm_Result1 == RC_OK)
          {
            if (answer->rm_Result2)
            {
              DeleteArgstring((UBYTE *)answer->rm_Result2);
            } // if
          } // if

          DeleteArgstring((UBYTE *)ARG0(answer));
          DeleteRexxMsg(answer);
        } // if
        return &result;
      } // if
    } // if
  } // if
  Permit();

return NULL;
}
/*E*/
void DispatchMessage(struct Message *arg_poMessage, BOOL arg_bAsync)
/*S*/
{
  TRACE("");
  // bis jetzt noch kein richtiger dispatcher
  // solange wir was zum verschicken haben, schicken wir das einfach los
  if (arg_poMessage && arg_poMessage->mn_Node.ln_Name)
  {
    // wenn kein Asyncronen-Command
    if (arg_bAsync || Strnicmp("QUIT", arg_poMessage->mn_Node.ln_Name, 4)==0)
    {
      TRACE(poMessage->mn_Node.ln_Name);
      SendRexxCommand(glob_sPortName, arg_poMessage->mn_Node.ln_Name, NULL);
      TRACE("Asyncronen Befehl an Golded geschickt");
    }
    else
    {
      struct MsgPort *msgPort;
      if (msgPort = CreateMsgPort())
      {
        TRACE(arg_poMessage->mn_Node.ln_Name);
        SendRexxCommand(glob_sPortName, arg_poMessage->mn_Node.ln_Name, msgPort);
        TRACE("Befehl an Golded geschickt");
        DeleteMsgPort(msgPort);
      } // if
    } // if
    delete arg_poMessage->mn_Node.ln_Name;
    delete arg_poMessage;
  } // if
}
/*E*/
void sendMsgToGoldED(char *arg_sCommand, char *arg_sParameter, BOOL arg_bAsync)
/*S*/
{
  if (!arg_sParameter)
  {
    arg_sParameter = "";
  } // if

  // allocate the mem for the command-string
  char *sCommand = new char [strlen(arg_sCommand)+strlen(arg_sParameter)+2];
  if (sCommand)
  {
    sprintf(sCommand, arg_sCommand, arg_sParameter);

    struct Message *poMessage = new struct Message;
    if (poMessage)
    {
      memset(poMessage, 0, sizeof(struct Message));
      poMessage->mn_Length = sizeof(struct Message);
      poMessage->mn_Node.ln_Name = sCommand;

      TRACE("msg weitergeleitet:");
      TRACE(sCommand);
      DispatchMessage(poMessage, arg_bAsync);
    }
    else
    {
      delete sCommand;
    } // if
  } // if
//  Delay(50);
}
/*E*/
void SAVEDS handleAPIRemoteCmdMsg(FelixMessage *arg_poFLXMsg)
/*S*/
{
  TRACE("");
  if (!arg_poFLXMsg || !arg_poFLXMsg->m_poTagList || arg_poFLXMsg->m_ulType!=FelixMessage::FLXMSG_REMOTECMD)
  {
    return;
  } // if

  switch (GetTagData(FLXTAG_REMOTECOMMAND, FLXWINDOWCMD_UNDEFINED, arg_poFLXMsg->m_poTagList))
  {
    case FLXREMOTECMD_RELOADFILE:
      TRACE("Datei soll nachgeladen werden");
      { // dummy scope
        char *sFileName = (char *)GetTagData(FLXTAG_FileName, 0, arg_poFLXMsg->m_poTagList);

        if (sFileName)
        {
          sendMsgToGoldED("WINDOW QUIET USE=\"%s\"", sFileName, TRUE);
          sendMsgToGoldED("OPEN AGAIN FORCE NAME \"%s\"", sFileName, TRUE);
          sendMsgToGoldED("GOTO CHANGE","", TRUE);
        } // if
      }
      break;
    default:
      TRACE("Unbekannte remotecmd-msg");
      break;
  } // switch
}
/*E*/
void SAVEDS handleAPIWindowMsg(FelixMessage *arg_poFLXMsg)
/*S*/
{
  TRACE("");
  if (!arg_poFLXMsg || !arg_poFLXMsg->m_poTagList || arg_poFLXMsg->m_ulType!=FelixMessage::FLXMSG_WINDOWLIST)
  {
    return;
  } // if

  switch (GetTagData(FLXTAG_WINDOWCOMMAND, FLXWINDOWCMD_UNDEFINED, arg_poFLXMsg->m_poTagList))
  {
    case FLXWINDOWCMD_OPEN:
      TRACE("Fenster soll geöffnet werden");
      { // dummy scope
        struct APIMessage *apiMsg = (struct APIMessage *) GetTagData(FLXTAG_APIMSG, 0, arg_poFLXMsg->m_poTagList);
        if (apiMsg)
        {
          // wenn es noch keine Fensterliste gibt
          if (!glob_poWindowList)
          {
            // eine anlegen
            glob_poWindowList = new WindowListC(glob_poWatches);
          } // if

          // wenn es jetze ein Fenster gibt
          if (glob_poWindowList)
          {
            static BOOL bStartedOnce = FALSE;
            BOOL bKeepPos = GetTagData(FLXTAG_KeepPos, FALSE, arg_poFLXMsg->m_poTagList);
            // wenn noch nicht gestartet
            if (!bStartedOnce || !bKeepPos)
            {
              ULONG ulX = GetTagData(FLXTAG_Left, -1, arg_poFLXMsg->m_poTagList);
              ULONG ulY = GetTagData(FLXTAG_Top, -1, arg_poFLXMsg->m_poTagList);
              glob_poWindowList->setWindowPosition(ulX, ulY, TRUE);
              bStartedOnce = TRUE;
            } // if

            ULONG ulEntries = GetTagData(FLXTAG_Entries, 20, arg_poFLXMsg->m_poTagList);
            glob_poWindowList->setMaxVisibleEntries(ulEntries);

            glob_poWindowList->openWindowList(apiMsg);
            glob_poWindowList->updateWindowList(apiMsg->api_Instance);
          } // if
        } // if
        else
        {
          TRACE("kein FLXTAG_APIMSG in der TagList");
        } // if
      } // dummy scope
      break;
    case FLXWINDOWCMD_CLOSE:
      if (glob_poWindowList)
      {
        delete glob_poWindowList;
        glob_poWindowList = NULL;
      }
      TRACE("Fenster soll geschlossen werden");
      break;
    case FLXWINDOWCMD_UPDATE:
      if (glob_poWindowList)
      {
        struct APIMessage *apiMsg = (struct APIMessage *) GetTagData(FLXTAG_APIMSG, 0, arg_poFLXMsg->m_poTagList);
        if (apiMsg)
        {
          glob_poWindowList->updateWindowList(apiMsg->api_Instance);
        } // if
      } // if
      break;
    default:
      TRACE("Unbekannte windowlist-msg");
      break;
  }

}
/*E*/
BOOL SAVEDS handleAPIMessage(struct Message *arg_poMessage)
/*S*/
{
  TRACE("Entry");

  if (!arg_poMessage)
  {
    TRACE("Falscher Parameter!");
    return FALSE;
  } // if

  char *sName = arg_poMessage->mn_Node.ln_Name;
  TRACE(sName);
  if (sName)
  {
    // Ist es die ende-Msg?
    if (0 == strcmp("ende", sName))
    {
      TRACE("Ende-Message erkannt");
      // wenn die WindowList noch offen ist
      if (glob_poWindowList)
      {
        delete glob_poWindowList;
        glob_poWindowList = NULL;
      } // if
      return TRUE;
    }
    // ist es eine message für die WindowList-verwaltung
    else if (0 == strcmp("windowlist", sName))
    {
      TRACE("WindowListMessage erhalten");
      FelixMessage *poFLXMsg = (FelixMessage *) arg_poMessage;
      handleAPIWindowMsg(poFLXMsg);
    }
    else if (0 == strcmp("remote", sName))
    {
      TRACE("An ein befehl soll verschickt werden")
      FelixMessage *poFLXMsg = (FelixMessage *) arg_poMessage;
      handleAPIRemoteCmdMsg(poFLXMsg);
    } // if
  } // if
  ReplyMsg(arg_poMessage);
return FALSE;
}
/*E*/
void BuildWaitMask(const struct MsgPort *arg_poMsgPort, ULONG &arg_rulMask)
/*S*/
{
  TRACE("");
  if (!arg_poMsgPort)
  {
    TRACE("Kein Msg-Port");
    return;
  } // if

  arg_rulMask |= (1L << (arg_poMsgPort->mp_SigBit));
}
/*E*/
void SAVEDS EntprellePort(struct MsgPort *arg_poPort)
/*S*/
{
  TRACE("");
  if (!arg_poPort)
  {
    return;
  }

  struct Message *poMessage;
  // solange wir messages kriegen
  while (poMessage = GetMsg(arg_poPort))
  {
    // Wenn die Message einen ReplyPort hat
    if (poMessage->mn_ReplyPort)
    {
      ReplyMsg(poMessage);
    } // if
  } // while
}
/*E*/

void SAVEDS FelixTask(void)
/*S*/
{
  TRACE("Entry");
  struct Message *poMessage = NULL;
  if (glob_poReciever = CreateMsgPort())
  {
    // wenn der Empfänger-Port vorhanden ist
    if (glob_poReciever)
    {
      BOOL done = FALSE;
      while(!done)
      {
        TRACE("Thread-msg-schleife");
        ULONG ulSigMask = NULL;
        BuildWaitMask(glob_poReciever, ulSigMask);
        // wenn auch ein fenster existiert
        if (glob_poWindowList && glob_poWindowList->getWindow())
        {
          BuildWaitMask(glob_poWindowList->getWindow()->UserPort, ulSigMask);
        } // if
        TRACE("go waiting...");
        Wait(ulSigMask);
        TRACE("waking up...");

        while (!done && (poMessage = GetMsg(glob_poReciever)))
        {
          TRACE("getmsg()-schleife für api");
          done = handleAPIMessage(poMessage);
          TRACE("zurück von handleapimsg()");
          // ! diese Messages müssen nicht beantwortet werden !
        } // while

        if (!done && glob_poWindowList)
        {                             
          TRACE("Versuche handleWindowList");
          BOOL bClose = glob_poWindowList->handleWindowList();
          if (bClose)
          {
            delete glob_poWindowList;
            glob_poWindowList = NULL;
          } // if
        } // if
      } // while

      // Aufräumen
      EntprellePort(glob_poReciever);
      DeleteMsgPort(glob_poReciever);
      glob_poReciever = NULL;
    } // if

    // Message jetzt zurückschicken
    glob_poWorker = NULL;
    TRACE("Steige jetzt wieder aus");
    if (poMessage)
    {
      PutMsg(glob_poStopper, poMessage);
    }
    else
    {
      TRACE("exit ohne message!!!");
    } // if
  } // if
}
/*E*/
void SendeNachricht(char *arg_sName, UBYTE arg_uyMsgType, ULONG arg_eTags ...)
/*S*/
{ 
  TRACE("Entry");
  SendeNachrichtA(arg_sName, arg_uyMsgType, (struct TagItem *) &arg_eTags);
}
/*E*/
void SendeNachrichtA(char *arg_sName, UBYTE arg_uyMsgType, struct TagItem *arg_poTagList)
/*S*/
{
  TRACE("Entry");
  struct MsgPort *poPort;
  // Wenn Stopper-Port vorhanden
  if (poPort = CreateMsgPort())
  {
    // Wenn Reciever-Port vorhanden
    if (glob_poReciever && glob_poWorker)
    {
      struct FelixMessage oMessage;
      memset(&oMessage, 0, sizeof(struct FelixMessage));
      oMessage.mn_Length = sizeof(struct FelixMessage);
      oMessage.mn_Node.ln_Name = arg_sName;
      oMessage.m_ulType        = arg_uyMsgType;
      oMessage.m_poTagList     = arg_poTagList;
      oMessage.mn_ReplyPort    = poPort;

      TRACE("schicke Nachricht");
      PutMsg(glob_poReciever, &oMessage);
      TRACE("Nachricht abgeschickt");
      WaitPort(poPort);
      TRACE("Zurück von warte auf reply");
    } // if
    DeleteMsgPort(poPort);
  } // if
}
/*E*/
void BeendeProzess(void)
/*S*/
{
  TRACE("");
  // Wenn Stopper-Port vorhanden
  if (glob_poStopper = CreateMsgPort())
  {
    // Wenn Reciever-Port vorhanden
    if (glob_poReciever)
    {
      // Wenn der Prozess auch vorhanden
      if (glob_poWorker)
      {
        struct Message oMessage;
        memset(&oMessage, 0, sizeof(struct Message));
        oMessage.mn_Length = sizeof(struct Message);
        oMessage.mn_Node.ln_Name = "ende";

        PutMsg(glob_poReciever, &oMessage);
        TRACE("Ende-Message abgeschickt");
        WaitPort(glob_poStopper);
      } // if
    } // if
    EntprellePort(glob_poStopper);
    DeleteMsgPort(glob_poStopper);
    glob_poStopper = NULL;
  } // if
}
/*E*/
void StarteProzess(void)
/*S*/
{
  TRACE("");
  glob_poWorker = CreateNewProcTags(NP_Entry, FelixTask,
                                    NP_Priority, FindTask(NULL)->tc_Node.ln_Pri + 5,
                                    NP_Name, "Felix-Task (GoldED-API)",
                                    TAG_DONE);
}
/*E*/

