//*************************************************************************//
// Filename:    funcs.c
// Autor:       Christian Taulien of Strange Intelligence
// Purpose:     Functions for Felix.api
// Creation:    18. März 1998
//*************************************************************************//
extern struct Window;
extern struct Message;

#include "funcs.h"
#include "flxclasses.h"
#include "ProcessComm.h"
#include "freshlocale.h"
#include "WindowList.h"

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

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <utility/utility.h>
#include <resources/battclock.h>

#include <clib/battclock_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>
#include <clib/utility_protos.h>

#define MYAPICLASSES  ( API_CLASS_COMMAND \
                      | API_CLASS_SYSTEM \
                      | API_CLASS_KEY    \
                      | API_CLASS_IO     \
                      | API_CLASS_SCREEN)

enum
{
  ARG_XPOS, ARG_YPOS, ARG_ENTRIES, ARG_KEEPPOS, ARG_OFF,
  ARG_COUNT
};

UBYTE *apiCommands[] =
{
  "FELIX",
  "WINDOWLIST X/N Y/N ENTRIES/N KEEPPOSITION/S OFF/S",
  "CHECKACCESSES",
  "GETUSERNAME",
  NULL
};

const struct APIClient  glob_oAPIClient =
{
  API_INTERFACE_VERSION,      // api_APIVersion
  VERSION,                    // api_Version
  "Felix API",                // api_Name
  "Felix API - Überprüft Dateizugriffe und bietet Fensterlistenfunktion", // api_Info
  apiCommands,                // api_Commands
  0,                          // api_Serial
  MYAPICLASSES,               // api_Classes
  NULL                        // api_Area
};

char *glob_sReturnBuffer = NULL;

extern FLXWatchListC *glob_poWatches;
extern WindowListC *glob_poWindowList;
struct Library *BattClockBase;

// libraryentries
//**********************************************************************************************************
struct SAVEDS APIClient *APIMountClient(register __a0 struct APIMessage *apiMsg, register __a1 char *args)
/*S*/
{
  TRACE("Entry");

  glob_poWatches->addWatch(apiMsg->api_Instance);

  SendeNachricht("windowlist",
    FelixMessage::FLXMSG_WINDOWLIST,
    FLXTAG_WINDOWCOMMAND, FLXWINDOWCMD_UPDATE,
    FLXTAG_APIMSG, apiMsg,
    TAG_DONE);

return &glob_oAPIClient;
} // APIMountClient()
/*E*/
//***********************************************************************************************************
void SAVEDS APICloseClient(register __a0 struct APIClient *handle, register __a1 struct APIMessage *apiMsg)
/*S*/
{
  // no ressources to be freed yet
  TRACE("Entry");
  FLXNodeC *pNode = glob_poWatches->findWatch(apiMsg->api_Instance);
  if (pNode)
  {
    delete pNode;
  } // if

  if (glob_poWatches->getSize()==0)
  {
    SendeNachricht("windowlist",
      FelixMessage::FLXMSG_WINDOWLIST,
      FLXTAG_WINDOWCOMMAND, FLXWINDOWCMD_CLOSE,
      FLXTAG_APIMSG, apiMsg,
      TAG_DONE);
  }
  else
  {
    SendeNachricht("windowlist",
      FelixMessage::FLXMSG_WINDOWLIST,
      FLXTAG_WINDOWCOMMAND, FLXWINDOWCMD_UPDATE,
      FLXTAG_APIMSG, apiMsg,
      TAG_DONE);
  } // if

} // APICloseClient()
/*E*/
//***********************************************************************************************************
void SAVEDS APIBriefClient(register __a0 struct APIClient *handle, register __a1 struct APIMessage *apiMsg)
/*S*/
{
  struct APIMessage *msg;

  // handle host's command notify
  TRACE("Entry");

  // for every message
  for (msg = apiMsg; msg!=0; msg = msg->api_Next)
  {
    // Dietmar told us to check this out
    if (msg->api_State == API_STATE_NOTIFY)
    {
      // je nach klasse unterscheiden
      switch (msg->api_Class)
      {
        case API_CLASS_COMMAND:
          TRACE("API_CLASS_COMMAND");
          if (msg->api_Class == API_CLASS_COMMAND)
          {
            // Wenn wir einen ARexx-Befehl ausführen sollen müssen
            if (msg->api_Action == API_ACTION_COMMAND)
            {
              DispatchCommandClassMessage(handle, msg);
            }
            else
            {
              msg->api_Error = API_ERROR_UNKNOWN;
            } // if
          } // if
          break;
        case API_CLASS_SCREEN:
          TRACE("API_CLASS_SCREEN");
          DispatchScreenClassMessage(handle, msg);
          break;
        case API_CLASS_SYSTEM:
          TRACE("API_CLASS_SYSTEM");
          DispatchSystemClassMessage(handle, msg);
          break;
        case API_CLASS_IO:
          TRACE("API_CLASS_IO");
          DispatchIOClassMessage(handle, msg);
          break;
        case API_CLASS_KEY:
          TRACE("API_CLASS_KEY");
          DispatchKeyClassMessage(handle, msg);
          break;
        default:
          msg->api_Error = API_ERROR_UNKNOWN;
          break;
      } // switch
    } // if
  } // for
} // APIBriefClient()
/*E*/
//****************************************************************************************************
void SAVEDS APIFree(register __a0 struct APIClient *handle, register __a1 struct APIOrder *apiOrder)
/*S*/
{
    TRACE("Entry");
    // no ressources to be freed
} // APIFree()
/*E*/

// Functions not present as library-entries
//*********************************************************************************************
void SAVEDS DispatchCommandClassMessage(struct APIClient *apiClient, struct APIMessage *apiMsg)
/*S*/
// Dispatch incoming command: examine command string (command part is uppercase
// already), look for handler function related to command, parse arguments (if
// command supports arguments), call handler.
{
  struct RDArgs *rdArgs, *args;

  TRACE("Entry");

  if (rdArgs = (struct RDArgs*) AllocDosObject(DOS_RDARGS, NULL))
  {
    // table of supported commands, handlers & schablone strings

    static struct parser
    {
       char *command;
       LONG (*handler)(ULONG *, struct APIMessage *);
       char *schablone;
    }  parser[] =
    {
      { "FELIX", CommandAbout, NULL },
      { "WINDOWLIST", CommandWindowList, "X/N,Y/N,ENTRIES/N,KEEPPOSITION/S,OFF/S"},
      { "CHECKACCESSES", CommandCheckAccesses, NULL },
      { "GETUSERNAME", CommandGetUserName, NULL },
      {  NULL, NULL, NULL }
    };

    ULONG n;
    UBYTE buffer[100];
    ULONG argArray[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };

    // make LF-terminated copy of command string (required by dos/readArgs):

    strncpy(buffer, apiMsg->api_Command, sizeof(buffer));
    strcat (buffer, "\12");

    for (n = 0; parser[n].command; ++n)
    {
      if (memcmp(buffer, parser[n].command, strlen(parser[n].command)) == 0)
      {
        UBYTE *arguments = buffer + strlen(parser[n].command);

        // tell host that message has been consumed by us:

        apiMsg->api_State = API_STATE_CONSUMED;

        rdArgs->RDA_Source.CS_Buffer = arguments;
        rdArgs->RDA_Source.CS_Length = strlen(arguments);
        rdArgs->RDA_Source.CS_CurChr = 0;
        rdArgs->RDA_DAList           = NULL;
        rdArgs->RDA_Buffer           = NULL;

        if (parser[n].schablone)
        {
          if (args = ReadArgs(parser[n].schablone, (LONG *) argArray, rdArgs))
          {
            apiMsg->api_RC = (*parser[n].handler)(argArray, apiMsg);
            FreeArgs(args);
          }
          else
          {
            static UBYTE errorText[80 + 1];

            apiMsg->api_RC           = RC_WARN;
            apiMsg->api_CommandError = errorText;

            Fault(IoErr(), "IoErr()", errorText, 80);
          } // if
        }
        else
        {
          apiMsg->api_RC = (*parser[n].handler)(argArray, apiMsg);
        } // if
      } // if
    } // for
    FreeDosObject(DOS_RDARGS, rdArgs);
  } //if

  SendeNachricht("windowlist",
    FelixMessage::FLXMSG_WINDOWLIST,
    FLXTAG_WINDOWCOMMAND, FLXWINDOWCMD_UPDATE,
    FLXTAG_APIMSG, apiMsg,
    TAG_DONE);
} // DispatchCommandClassMessage
/*E*/
//********************************************************************************************
void SAVEDS DispatchSystemClassMessage(struct APIClient *apiClient, struct APIMessage *apiMsg)
/*S*/
{
  TRACE("Entry");
  //
  switch (apiMsg->api_Action)
  {
    case API_ACTION_WELCOME:
      TRACE("WELCOME");
      break;
    case API_ACTION_EXIT:
        TRACE("EXIT");
      break;
    default:
      TRACE("UNKNOWN");
      break;
  }
} // DispatchSystemClassMessage()
/*E*/
//********************************************************************************************
void SAVEDS DispatchScreenClassMessage(struct APIClient *apiClient, struct APIMessage *apiMsg)
/*S*/
{
  TRACE("Entry");
  //
  switch (apiMsg->api_Action)
  {
    case API_ACTION_HIDE:
      TRACE("HIDE");
      break;
    case API_ACTION_SHOW:
      TRACE("SHOW");
      break;
    default:
      TRACE("UNKNOWN");
      break;
  }
} // DispatchScreenClassMessage()
/*E*/
//*****************************************************************************************
void SAVEDS DispatchKeyClassMessage(struct APIClient *apiClient, struct APIMessage *apiMsg)
/*S*/
{
  TRACE("Entry");

  static struct APIInstance *oldInstance = NULL;
  if (oldInstance != apiMsg->api_Instance)
  {
    SendeNachricht("windowlist",
      FelixMessage::FLXMSG_WINDOWLIST,
      FLXTAG_WINDOWCOMMAND, FLXWINDOWCMD_UPDATE,
      FLXTAG_APIMSG, apiMsg,
      TAG_DONE);
    oldInstance = apiMsg->api_Instance;
  } // if

  switch (apiMsg->api_Action)
  {
    case API_ACTION_VANILLAKEY:
      TRACE("VANILLAKEY");
      glob_poWatches->checkAccess();
      break;
    case API_ACTION_RAWKEY:
      TRACE("RAWKEY");
      glob_poWatches->checkAccess();
      break;
    default:
      TRACE("UNKNOWN");
      break;
  } // switch

  SendeNachricht("windowlist",
    FelixMessage::FLXMSG_WINDOWLIST,
    FLXTAG_WINDOWCOMMAND, FLXWINDOWCMD_TEXTMODIFY,
    FLXTAG_APIMSG, apiMsg,
    TAG_DONE);

} // DispatchKeyClassMessage()
/*E*/
//*****************************************************************************************
void SAVEDS DispatchIOClassMessage(struct APIClient *apiClient, struct APIMessage *apiMsg)
/*S*/
{
  TRACE("Entry");
  //
  switch (apiMsg->api_Action)
  {
    case API_ACTION_SAVE:
      TRACE("SAVE");
      {
        FLXNodeC *pNode = glob_poWatches->findWatch(apiMsg->api_Instance);
        if (pNode)
        {
          // Den Watch löschen. Nach dem Speichern wird der Watch
          // automatisch wieder erzeugt, irgendwie, aber so ist's nun mal.
          // Es ist jetzt 05:13:56 und ich bin schon fast ein bischen müde.
          delete pNode;
        } // if
        return;
      }
      break;
    case API_ACTION_CREATED:
      TRACE("CREATED");
      {
        glob_poWatches->checkAccess();
        glob_poWatches->addWatch(apiMsg->api_Instance);

        SendeNachricht("windowlist",
          FelixMessage::FLXMSG_WINDOWLIST,
          FLXTAG_WINDOWCOMMAND, FLXWINDOWCMD_CREATED,
          FLXTAG_APIMSG, apiMsg,
          TAG_DONE);
      }
      break;
    case API_ACTION_READ:
      TRACE("READ");
      {
        FLXNodeC *pNode = glob_poWatches->findWatch(apiMsg->api_Instance);
        if (pNode)
        {
          pNode->setModified(FALSE);
        } // if
      }
      break;
    default:
      TRACE("UNKNOWN");
      break;
  } // switch

/*
  SendeNachricht("windowlist",
    FelixMessage::FLXMSG_WINDOWLIST,
    FLXTAG_WINDOWCOMMAND, FLXWINDOWCMD_UPDATE,
    FLXTAG_APIMSG, apiMsg,
    TAG_DONE);
*/
} // DispatchSystemClassMessage()
/*E*/

//*******************************************************************
LONG SAVEDS CommandAbout(ULONG  *argArray, struct APIMessage *apiMsg)
/*S*/
{
  static struct EasyStruct about =
  {
    sizeof(struct EasyStruct),
    0,
    0,  // titel
    0,  // text
    0   // gadgets
  };
  about.es_Title = glob_poCatalog->getString(T_INFOTITLE);
  about.es_TextFormat = glob_poCatalog->getString(T_INFOTEXT);
  about.es_GadgetFormat = glob_poCatalog->getString(T_INFOWEITER);
  // note: apiMsg->api_Instance->api_Window may be NULL
  TRACE("Entry");

  EasyRequestArgs((struct Window *) (apiMsg->api_Instance->api_Window), &about, NULL, NULL);

  return(RC_OK);
} // CommandAbout()
/*E*/
//************************************************************************
LONG SAVEDS CommandWindowList(ULONG  *arg_aulArray, struct APIMessage *apiMsg)
/*S*/
{
  TRACE("Entry");
  ULONG ulX = -1;
  ULONG ulY = -1;
  ULONG ulEntries = 20;
  BOOL  bKeepPosition = FALSE;
  Tag oCommand = FLXWINDOWCMD_OPEN;

  if (arg_aulArray[ARG_KEEPPOS])
  {
    bKeepPosition = TRUE;
  } // if

  // wenn x angegeben wurde
  if (arg_aulArray[ARG_XPOS])
  {
    ulX = *((ULONG *) arg_aulArray[ARG_XPOS]);
  } // if

  // wenn y angegeben wurde
  if (arg_aulArray[ARG_YPOS])
  {
    ulY = *((ULONG *) arg_aulArray[ARG_YPOS]);
  } // if

  // wenn anzahl der einträge angegeben
  if (arg_aulArray[ARG_ENTRIES])
  {
    ulEntries = *((ULONG *) arg_aulArray[ARG_ENTRIES]);
  } // if

  // wenn schließen gewünscht
  if (arg_aulArray[ARG_OFF])
  {
    oCommand = FLXWINDOWCMD_CLOSE;
  } // if

  // wenn anzahl der einträge angegeben

    SendeNachricht("windowlist",
      FelixMessage::FLXMSG_WINDOWLIST,
      FLXTAG_WINDOWCOMMAND, oCommand,
      FLXTAG_Left, ulX,
      FLXTAG_Top, ulY,
      FLXTAG_Entries, ulEntries,
      FLXTAG_KeepPos, bKeepPosition,
      FLXTAG_APIMSG, apiMsg,
      TAG_DONE);

return(RC_OK);
} // CommandAbout()
/*E*/
//***************************************************************************
LONG SAVEDS CommandCheckAccesses(ULONG  *argArray, struct APIMessage *apiMsg)
/*S*/
{
  TRACE("Über ARexx gesteuerter Access-Check")
  glob_poWatches->checkAccess();
  return(RC_OK);
} // CommandAbout()
/*E*/
LONG SAVEDS CommandGetUserName(ULONG  *argArray, struct APIMessage *apiMsg)
/*S*/
{
  TRACE("Ermitteln des Usernamens")

  int count=GetVar("USER", glob_sReturnBuffer, 999, LV_VAR | GVF_GLOBAL_ONLY);
  if (-1 == count)        // if ao error occured
  {
    strcpy(glob_sReturnBuffer, "unknown");
  } // if

  apiMsg->api_CommandResult = glob_sReturnBuffer;

return RC_OK;
} // CommandAbout()
/*E*/

