/* -----------------------------------------------------------------------------

  GEDApp v0.94 - GoldED AppIcon handler, ©1993/94 Dietmar Eilert
                 Gestionnaire d'AppIcône GoldED, ©1993/94 Dietmar Eilert
  DICE:

  dcc main.c appIconA.a -// -proto -mRR -mi -pr -2.0 -o ram:GEDApp

  ------------------------------------------------------------------------------
*/

/// "includes"

#include <amiga20/exec/exec.h>
#include <string.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <amiga20/intuition/intuition.h>
#include <amiga20/dos/dos.h>
#include <amiga20/dos/dosextens.h>
#include <amiga20/dos/rdargs.h>
#include <amiga20/dos/dostags.h>
#include <amiga20/workbench/startup.h>
#include <amiga20/workbench/workbench.h>
#include <amiga20/rexx/errors.h>
#include <amiga20/rexx/rxslib.h>

#include <amiga20/clib/alib_protos.h>
#include <amiga20/clib/dos_protos.h>
#include <amiga20/clib/exec_protos.h>
#include <amiga20/clib/icon_protos.h>
#include <amiga20/clib/intuition_protos.h>
#include <amiga20/clib/utility_protos.h>
#include <amiga20/clib/rexxsyslib_protos.h>
#include <amiga20/clib/wb_protos.h>

#ifdef PRAGMAS

#include "Pragmas/exec.h"
#include "Pragmas/disk.h"
#include "Pragmas/diskfont.h"
#include "Pragmas/dynamic.h"
#include "Pragmas/gadtools.h"
#include "Pragmas/keymap.h"
#include "Pragmas/graphics.h"
#include "Pragmas/icon.h"
#include "Pragmas/input.h"
#include "Pragmas/intuition.h"
#include "Pragmas/layers.h"
#include "Pragmas/locale.h"
#include "Pragmas/misc.h"
#include "Pragmas/timer.h"
#include "Pragmas/wb.h"
#include "Pragmas/xpkmaster.h"
#include "Pragmas/amigaguide.h"
#include "Pragmas/reqtools.h"

#endif

#define Prototype        extern
#define MAX_LEN          150

///
/// "prototypes"

Prototype void   main(ULONG, char **);
Prototype int    wbmain(struct WBStartup *);
Prototype void   MainLoop(void);
Prototype char  *MakeFileName(char *, char *);
Prototype char  *CompletePath(char *);
Prototype char  *StartGED(void);
Prototype struct RexxMsg *SendRexxCommand(char *, char *, struct MsgPort *);
Prototype void   FreeRexxCommand (struct RexxMsg *);
Prototype ULONG  WaitForAnswer(struct MsgPort *);
Prototype char  *LookForGED(void);
Prototype void   ReadWBCmd(ULONG, struct WBArg *);

extern struct Library *IconBase;
extern struct Library *DOSBase;
extern struct Library *SysBase;
extern struct Library *IntuitionBase;
extern struct Library *WorkbenchBase;

///
/// "entry points"

void
main(argc, argv)

ULONG argc;
char *argv[];
{
    MainLoop();
}

int
wbmain(struct WBStartup *wbs)
{
    MainLoop();
}


///
/// "main loop"

/* --------------------------------- MainLoop ----------------------------------

 Open AppIcon, handle incoming messages

 Ouvrir l'AppIcône, gérer les messages reçus

*/

void
MainLoop()
{
    const char *version = "$VER: GEDApp 0.92 (24.3.94)";

    struct DiskObject *appDiskObject;

    if (!(appDiskObject = GetDiskObject("envarc:GoldED/AppIcon")))
        appDiskObject = GetDefDiskObject(WBTOOL);

    if (appDiskObject) {

        struct MsgPort     *msgPort;
        struct AppMessage  *amsg;
        struct AppIcon     *appIcon;

        if (msgPort = CreateMsgPort()) {

            if (appIcon = AddAppIconA(0, NULL, "GED", msgPort, NULL, appDiskObject, TAG_END)) {

                BOOL terminated = FALSE;

                while (!terminated) {

                    WaitPort(msgPort);

                    while (amsg = (struct AppMessage *)GetMsg(msgPort)) {

                        if (amsg->am_NumArgs)
                            ReadWBCmd(amsg->am_NumArgs, amsg->am_ArgList);
                        else
                            terminated = TRUE;

                        ReplyMsg((struct Message *)amsg);
                    }
                }
            }
            else {

                puts("Couldn't allocate AppIcon. Workbench closed ?!");
                puts("Impossible d'allouer l'AppIcon. Le Workbench est fermé ?!");
            }

            RemoveAppIcon(appIcon);

            DeleteMsgPort(msgPort);
        }
        else {

            puts("Couldn't create message port ?!");
            puts("Impossible de créer le port message ?!");
        }

        FreeDiskObject(appDiskObject);
    }
    else {

        puts("Impossible d'allouer DiskObject ?!");
        puts("Couldn't allocate DiskObject ?!");
    }

    exit(0);
}


///
/// "misc"

/* ------------------------------- MakeFileName --------------------------------

 Build fully qualified path from file/path names; return pointer to static copy.

 Générer le chemin d'accès complet à partir des icônes; retourne un pointeur
 pour une copie statique.

*/

char *
MakeFileName(path, file)

char *path, *file;
{
    static char buffer[MAX_LEN + 1];

    strcpy(buffer, "\42");

    strcat(buffer, path);

    CompletePath(buffer);

    strcat(buffer, file);

    strcat(buffer, "\42");

    return(buffer);
}

/* ------------------------------ CompletePath -----------------------------------

 Add '/' to path if missing so far

 Ajouter un '/' au chemin si nécessaire

*/

char *
CompletePath(char *path)
{
    UWORD len;

    if (len = strlen(path))
        if ((path[len - 1] != ':') && (path[len - 1] != '/'))
            strcat(path, "/");

    return(path);
}

/* ---------------------------------- ReadWBCmd --------------------------------

 Parse AppIcon message

 Analyser le message AppIcon

*/

void
ReadWBCmd(numArgs, argList)

ULONG  numArgs;
struct WBArg  *argList;
{
    char *host;
    BOOL loadGED = !(host = LookForGED());

    if (loadGED)
        host = StartGED();

    if (host) {

        struct MsgPort *replyPort;

        if (replyPort = CreateMsgPort()) {

            if (SendRexxCommand(host, "LOCK CURRENT", replyPort)) {

                if (WaitForAnswer(replyPort) == RC_OK) {

                    UWORD count;
                    char  path[MAX_LEN + 1], *command;

                    for (count = 0; numArgs--; count++) {

                        NameFromLock(argList[count].wa_Lock, path, MAX_LEN);

                        command = MakeFileName(path, argList[count].wa_Name);

                        strins(command, "OPEN SMART QUIET ");

                        if (SendRexxCommand(host, command, replyPort))
                            WaitForAnswer(replyPort);
                    }
                }

                if (SendRexxCommand(host, "UNLOCK", replyPort))
                    WaitForAnswer(replyPort);
            }

            DeleteMsgPort(replyPort);
        }
    }
}


/* ----------------------------------- LookForGED ----------------------------

 Look for running GoldED task (check GOLDED.1 to GOLDED.9)

 Rechercher la tâche GoldED (vérifier GOLDED.1 à GOLDED.9)

*/

char *
LookForGED()
{
    static char host[] = "GOLDED.1";
    UWORD  try;

    for (try = '1'; try <= '9'; try++) {

        host[7] = try;

        if (FindPort(host))
            return(host);
    } 

    return(NULL);
}

/* ------------------------------------- StartGED -----------------------------

 Launch a new GoldED task. Return pointer to host name (or NULL).

 Démarrer une nouvelle tâche GoldED. Retourne un pointeur sur le nom de l'hôte
 (ou NULL).

*/

char *
StartGED()
{
    static char *host = "GOLDED.1";

    if (!SystemTags("GoldED:GoldED", SYS_Asynch, TRUE, SYS_Input, NULL, SYS_Output, NULL, TAG_DONE))

        UWORD try;

        for (try = 50; try; try--, Delay(10))
            if (FindPort(host))
                return(host);

    return(FALSE);
}

///
/// "ARexx"

/* -------------------------------------- WaitForAnswer -----------------------

  Wait for answer on previously sent message. Free message afterwards. Primary
  return code is returned.

  Attendre une réponse du message envoyé précédemment. Libérer ensuite le
  message. Le code de retour primaire est retourné.

*/

ULONG
WaitForAnswer(port)

struct MsgPort *port;
{
    struct RexxMsg *rexxMsg;
    ULONG  result;

    do {
        
        WaitPort(port);

        if (rexxMsg = (struct RexxMsg *)GetMsg(port))
            result = rexxMsg->rm_Result1;

    } while (!rexxMsg);

    FreeRexxCommand(rexxMsg);

    return(result);
}

/* ------------------------------------- FreeRexxCommand ----------------------

 Free ARexx message

 Libérer le message ARexx

*/

void
FreeRexxCommand(rexxmessage)

struct RexxMsg *rexxmessage;
{
    if (rexxmessage->rm_Result1 == RC_OK) 
        if (rexxmessage->rm_Result2)
            DeleteArgstring((char *)rexxmessage->rm_Result2);

    DeleteArgstring((char *)ARG0(rexxmessage));

    DeleteRexxMsg(rexxmessage);
}

/* ---------------------------------- SendRexxCommand -------------------------

 Send ARexx message

 Envoyer le message ARexx

*/

struct RexxMsg *
SendRexxCommand(port, cmd, replyPort)

char   *cmd,   *port;
struct MsgPort *replyPort;
{
    struct MsgPort *rexxport;
    struct RexxMsg *rexx_command_message = NULL;

    Forbid();

    if (rexxport = FindPort(port)) {

        if (rexx_command_message = CreateRexxMsg(replyPort, NULL, NULL)) {

            if (rexx_command_message->rm_Args[0] = CreateArgstring(cmd, strlen(cmd))) {

                rexx_command_message->rm_Action = RXCOMM | RXFF_RESULT;

                PutMsg(rexxport, &rexx_command_message->rm_Node);
            }
        }
    }

    Permit();

    return(rexx_command_message);
}

///
