/* Application.c */

#include "Constants.h"
#include "Locale.h"

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <libraries/commodities.h>
#include <libraries/asl.h>
#include <devices/scsidisk.h>
#include <devices/cd.h>
#include <graphics/rastport.h>
#include <pragma/screennotify_lib.h>
#include "AsmLib/CD-ROM.h"
#include "Structures/Application.h"

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/commodities_protos.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/icon_protos.h>
#include <clib/wb_protos.h>
#include <string.h>
#include "ACDPlay_protos.h"

extern char        *ls[ANZ_MSG];
extern char             PROG_NAME[];
extern char        *PROG_FULLNAME;

struct Application *CreateApplication(char *progname)
{
        struct Application *app = NULL;

        /* Speicher für Applicationstruktur besorgen */
        if (app = GetVecA(sizeof(struct Application), MEMF_PUBLIC | MEMF_CLEAR))
        {
                app->progname = progname;
                app->orgprwin = ((struct Process *)FindTask(NULL))->pr_WindowPtr;

                if (app->cdstr = GetVecA(sizeof(struct CDStruct), MEMF_PUBLIC | MEMF_CLEAR))
                {
                        app->edit_pos = -1;

                        if (app->arexx_mp = OpenARexxPortA())
                        {
                                ReadArguments(app);
                                ReadConfig(app, "ENV:acdplay.cfg");
                                app->arexxdir = GetDirContents("PROGDIR:ARexx");

                                if (OpenCDStruct(app->cdstr))
                                {
                                        if (app->scroller = GetVecA(sizeof(struct Scroll), MEMF_CLEAR | MEMF_PUBLIC))
                                        {
                                                int i;

                                                app->appwin[WINDOW_PUBSCREEN].minwidth = MINWIDTH_LISTVIEWWIN;
                                                app->magicwbmode = (app->flag_tool & FLAG_TOOL_MWB) ? TRUE : FALSE;

                                                /* ASL-Requester-Werte eintragen */
                                                for (i = 0; i < ANZ_ASL; i++)
                                                {
                                                        app->appasl[i].leftedge = 100;
                                                        app->appasl[i].topedge  = 50;
                                                        app->appasl[i].width    = 200;
                                                        app->appasl[i].height   = 200;
                                                        app->appasl[i].noicons  = TRUE;
                                                }
                                                /* spezifische ASL-Werte */
                                                app->appasl[ASL_AREXX].titletext                = ls[MSG_ASL_AREXX_HAIL];
                                                strcpy(app->appasl[ASL_AREXX].dirname, "ARexx/");

                                                UpdateCDTitles(app);    /* CD-Titel setzen */
                                                if (CreateCommodity(app))
                                                        return (app);
                                                else
                                                        ShowMsgA(ls[MSG_ERROR_TITLE], ls[MSG_NO_CX], NULL);
                                        }
                                }
                        }
                }
        }

        DeleteCxObjAll(app->broker);
        DeleteMsgPort(app->broker_mp);
        FreeVec(app->scroller);
        FreeList(app->arexxdir);
        CloseARexxPortA(app->arexx_mp);
        FreeCDStruct(app->cdstr);
        FreeVec(app);
        return (NULL);
}

void DeleteApplication(struct Application *app)
{
        CloseApplication(app);
        FreeAppIcon(app);

        /* ScreenNotify-Port, falls vorhanden, entfernen */
        if (app->scrnotify_mp)
        {
                /* Solange versuchen den Screennotifyclient zu schließen, bis es klappt */
                if (app->snhandle_wbench)
                        while (!RemWorkbenchClient(app->snhandle_wbench))
                                Delay(10);

                Forbid();
                FlushMessagesA(app->scrnotify_mp);
                DeleteMsgPort(app->scrnotify_mp);
                Permit();
        }

        /* Muß leider hier plaziert werden, da die Listen in CreateApplication() */
        /* erstellt wurden: */
        FreeList(app->cdstr->cdtitles);
        FreeList(app->cdstr->progtitles);
        FreeList(app->arexxdir);

        /* Commodities: Broker löschen, MsgPort leeren und freigeben */
        DeleteCxObjAll(app->broker);
        Forbid();                                                       /* Sicher ist sicher :-) */
        FlushMessagesA(app->broker_mp);
        DeleteMsgPort(app->broker_mp);
        Permit();

        FreeVec(app->scroller);

        FreeCDStruct(app->cdstr);
        CloseARexxPortA(app->arexx_mp);
        FreeVec(app);
}

BOOL OpenApplication(struct Application *app)
{
        BOOL success = TRUE;

        if (!app->screen)
        {
                success = FALSE;

                app->screen = LockPubScreen(app->pubscreenname);        /* Es wird zuerst versucht, */
                if (!app->screen)                                                                       /* den gewünschten PubScreen */
                        app->screen = LockPubScreen(NULL);                              /* zu locken. */
                if (!app->screen)                                                                       /* Bei Scheitern wird es mit dem */
                {                                                                                                       /* DefaultPubScreen versucht, */
                        ShowMsgA(ls[MSG_ERROR_TITLE], ls[MSG_NO_PUBSCREEN], NULL);      /* wenn das nicht klappt, */
                        return (success);                                                               /* steigt ACDPlay aus */
                }

                ScreenToFront(app->screen);

                if (app->screen->Flags & WBENCHSCREEN)
                        app->Flags |= APPF_WORKBENCH;
                else
                        app->Flags &= ~APPF_WORKBENCH;

                if (app->visualinfo = GetVisualInfo(app->screen, TAG_END))
                {
                        WORD win;
                        app->font = app->screen->Font;

                        success = TRUE;

                        if (!MakeMenus(app)) return (FALSE);

                        /* Message-Port erstellen, der als shared-IDCMP-Port benutzt wird */
                        if (app->idcmp = CreateMsgPort())
                        {
                                for (win = ANZ_WINDOWS - 1; win >= 0; win--)
                                        if (app->appwin[win].winopen)
                                                if (!(OpenAppWin(app, win))) success = FALSE;
                        }

                        /* Damit die Application nicht mehr durch OpenWorkBench() geöffnet werden kann */
                        app->Flags &= ~APPF_SNCLOSED;
                }
                else ShowMsgA(ls[MSG_ERROR_TITLE], ls[MSG_NO_VISUALINFO], app->screen->Title);
        }
        else
        {
                ScreenToFront(app->screen);             /* Screen wird *immer* nach vorne geholt */
                WindowToFront(app->appwin[WINDOW_MAIN].window);
                ActivateWindow(app->appwin[WINDOW_MAIN].window);
        }

        return(success);
}

void CloseApplication(Application *app)
{
        if (app->screen)
        {
                WORD win;

                for (win = ANZ_WINDOWS-1; win >= 0; win--)
                        if (app->appwin[win].winopen) CloseAppWin(app, win, FALSE);

                /* DeleteMsgPort(), FreeMenus() und FreeVisualInfo() testen
                   selbstständig auf NULL-Pointer */

                DeleteMsgPort(app->idcmp);
                app->idcmp = NULL;

                FreeMenus(app->menustrip);
                app->menustrip = NULL;

                FreeVisualInfo(app->visualinfo);
                app->visualinfo = NULL;

                if (app->screen) {
                        UnlockPubScreen(NULL, app->screen);
                        app->screen = NULL;
                }
        }
}

BOOL OpenCDStruct(struct CDStruct *cd)
{
        BOOL success = FALSE;

        if (cd->cdx = CDOpenDeviceA(cd->device, cd->unit, cd->lun))
        {
                /* Wenn geöffnetes Gerät kein CD-ROM-Laufwerk ist */
                if (cd->cdx->cdx_DeviceType != DEVTYPE_CDROM)
                {
                        struct EasyStruct req={ sizeof(struct EasyStruct),      /* es_StructSize */
                                                                        0,                                                      /* es_Flags */
                                                                        ls[MSG_WARNING_TITLE],          /* es_Title */
                                                                        ls[MSG_BAD_SCSIDEVICE],         /* es_TextFormat */
                                                                        ls[MSG_YESNO_REQ] };            /* es_GadFormat */

                        if (!EasyRequestArgs(NULL, &req, NULL, &(ULONG)cd->unit))
                                return (success);
                }

                cd->num_track   = cd->cdx->cdx_TOCData->TrackNum;
                cd->cur_track   = cd->cdx->cdx_CurrentTrack;
                cd->active              = cd->cdx->cdx_Active;
                cd->cdnameptr   = cd->cdname;
                cd->artistptr   = cd->artistname;

                cd->fileformat  = FORMAT_CDR;
                cd->freq                = FREQ_44100;

                success = TRUE;
        }

        return (success);
}

void FreeCDStruct(CDStruct *cd)
{
        if (cd->cdx)
                CDCloseDeviceA(cd->cdx);

        FreeVec(cd);
}

void CreateAppIcon(struct Application *app)
{
        if (!app->diskobj)
                if (app->diskobj = GetDiskObject(app->progname))
                {
                        /* Das muß wohl so sein */
                        app->diskobj->do_Type = NULL;

                        if (app->appicon_mp = CreateMsgPort())
                                app->appicon = AddAppIcon(0L, 0L, PROG_NAME, app->appicon_mp, NULL, app->diskobj, TAG_DONE);
                }
}

void FreeAppIcon(struct Application *app)
{
        BOOL success = FALSE;

        if (app->appicon)
        {
                RemoveAppIcon(app->appicon);
                app->appicon = NULL;
        }

        FlushMessagesA(app->appicon_mp);
        DeleteMsgPort(app->appicon_mp);
        app->appicon_mp = NULL;

        if (app->diskobj)
        {
                FreeDiskObject(app->diskobj);
                app->diskobj = NULL;
        }
}

BOOL CreateCommodity(struct Application *app)
{
        /* Erstellen des Commodities */
        if (app->broker_mp = CreateMsgPort())
        {
                struct NewBroker newbroker = {
                                NB_VERSION,                                     /* nb_Version - Version of the NewBroker structure */
                                PROG_NAME,                                      /* nb_Name - Name of the commodity */
                                PROG_FULLNAME,                          /* nb_Title */
                                ls[PROG_DESCR],                         /* nb_Decr - Description */
                                NBU_UNIQUE,                                     /* nb_Unique */
                                COF_SHOW_HIDE,                          /* nb_Flags */
                                app->cx_priority,                       /* nb_Pri - Priority */
                                app->broker_mp,                         /* nb_Port - MsgPort CX talks to */
                                0 };                                            /* nb_ReservedChannel */

                if (app->broker = CxBroker(&newbroker, NULL))
                {
                        if (app->filter_popkey = CxFilter(app->cx_popkey))
                        {
                                AttachCxObj(app->broker, app->filter_popkey);
                                if (app->sender_popkey = CxSender(app->broker_mp, EVENT_HOTKEYPRESSED))
                                {
                                        AttachCxObj(app->filter_popkey, app->sender_popkey);
                                        if (app->translate_popkey = CxTranslate(NULL))
                                        {
                                                AttachCxObj(app->filter_popkey, app->translate_popkey);

                                                if (app->filter_timer = CxFilter("timer -caps -alt -control -lcommand -rcommand -numericpad -rbutton -leftbutton -midbutton"))
                                                {
                                                        AttachCxObj(app->broker, app->filter_timer);
                                                        if (app->sender_timer = CxSender(app->broker_mp, EVENT_TIMER))
                                                        {
                                                                AttachCxObj(app->filter_timer, app->sender_timer);
                                                                ActivateCxObj(app->broker, 1L);

                                                                if (ScreenNotifyBase)
                                                                {
                                                                        if (app->scrnotify_mp = CreateMsgPort())
                                                                                app->snhandle_wbench = AddWorkbenchClient(app->scrnotify_mp, 1);
                                                                        else
                                                                                ShowMsgA(ls[MSG_ERROR_TITLE], ls[MSG_NO_MSGPORT], NULL);
                                                                }

                                                                return (TRUE);
                                                        }
                                                }
                                        }
                                }
                        }
                }
                DeleteMsgPort(app->broker_mp);
        }
        else ShowMsgA(ls[MSG_ERROR_TITLE], ls[MSG_NO_MSGPORT], NULL);

        return (FALSE);
}
