#include    "global.h"
#include    "locale.h"

#define CONFIG_TEMPLATE (APTR)"TYPE/K/A,ACTION/K/A,QUOTES/S"
#define CT_TYPE         0
#define CT_ACTION       1
#define CT_QUOTES       2
#define CT_LENGTH       3

#define NO_LISTSELECT       1
#define NO_ACTIONTRIGGER    2
#define NO_QUOTETRIGGER     3
#define NO_SAVEACTION       4
#define NO_LOADACTION       5
#define NO_ABOUT            6
#define NO_SAVEACTIONA      7

#define LE_QUOTES           1

Object  *app,       /*  Application object  */
        *win,       /*  Application window  */
        *ob_lv,     /*  Type listview       */
        *ob_st,     /*  Type string         */
        *ob_ast,    /*  Action string       */
        *ob_qu,     /*  Action quote tick   */
        *ob_save,   /*  Save button         */
        *ob_load,   /*  Load button         */
        *ob_add,    /*  Add button          */
        *ob_edit,   /*  Edit filetype       */
        *ob_loadt,  /*  Load filetype       */
        *ob_savet;  /*  Save filetype       */

struct NewMenu NM_Edit[] =
{
    NM_TITLE, NULL, NULL, 0, 0L, NULL,
        NM_ITEM, NULL, NULL, 0, 0l, (APTR)NO_ABOUT,
        NM_ITEM, NM_BARLABEL, NULL, 0, 0l, NULL, 
        NM_ITEM, NULL, NULL, 0, 0l, (APTR)NO_LOADACTION,
        NM_ITEM, NM_BARLABEL, NULL, 0, 0l, NULL, 
        NM_ITEM, NULL, NULL, 0, 0l, (APTR)NO_SAVEACTIONA,
        NM_ITEM, NULL, NULL, 0, 0l, (APTR)NO_SAVEACTION,
        NM_ITEM, NM_BARLABEL, NULL, 0, 0l, NULL, 
        NM_ITEM, NULL, NULL, 0, 0l, (APTR)MUIV_Application_ReturnID_Quit,
    NM_END, NULL, NULL, 0, 0L, NULL
};

struct Library *IntuitionBase, *MUIMasterBase, *WhatIsBase, *LocaleBase;

int winopen;
struct lv_ListEntry {
    char le_FileType[10];
    UWORD le_Flags;
    char *le_FileAction;
};
struct lv_ListEntry *SelectEntry, *NewEntry;
LONG ConfigLine[CT_LENGTH];
char ActionBuffer[256];
BOOL ActionQuotes;
char ACTIONFILE[256];
char *centries[] = { "Don't use quotes", "Use quotes", NULL};
char empty[] = "";

extern ULONG HookEntry(struct Hook *, Object *, APTR);
struct Hook lv_Construct, lv_Destruct, lv_Display, lv_Compare;
struct FileRequester *request;
char FileName[256];
struct TagItem ftag[5] = {
    ASL_Hail,   NULL, 
    ASL_File,   NULL,
    ASL_Dir,    NULL,
    NULL,       FILF_SAVE,
    TAG_DONE,   NULL
};


BOOL FileRequest(BOOL save, char *filen, char *dirn) {

    static char dir[256] = "\0";
    BOOL result;

    ftag[0].ti_Data = (ULONG)((save) ?  GetString(msgSelectFileSave) :  GetString(msgSelectFileLoad));
    ftag[1].ti_Data = (ULONG)filen;
    ftag[2].ti_Data = (ULONG)dirn;
    ftag[3].ti_Tag  = (save) ? ASL_FuncFlags : TAG_IGNORE;

    if (!request) request = (struct FileRequester *)MUI_AllocAslRequest(ASL_FileRequest,ftag);

    if (request == NULL)
        return(FALSE);

    result = MUI_AslRequest(request,NULL);

    if (result == FALSE) 
        return(FALSE);

    strcpy(dir,(char *)(request->rf_Dir));
    strncpy(FileName,(char *)(request->rf_Dir),256);
    AddPart((STRPTR)FileName,(STRPTR)request->rf_File,256);

    return(TRUE);
}


void CloseAll(STRPTR printme) {
    if (printme)
        printf("%s/n",(char *)printme);
    if (IntuitionBase)      CloseLibrary(IntuitionBase);
    if (MUIMasterBase)      CloseLibrary(MUIMasterBase);
    if (WhatIsBase)         CloseLibrary(WhatIsBase);
}


void OpenAll(void) {
    if (!(IntuitionBase = OpenLibrary((APTR)"intuition.library",37L)))
        CloseAll(GetString(msgYouNeed20));
    if (!(MUIMasterBase = OpenLibrary((APTR)"muimaster.library",0L)))
        CloseAll(GetString(msgYouNeedMUI));
    if (!(WhatIsBase    = OpenLibrary((APTR)"whatis.library",0l)))
        CloseAll(GetString(msgCantOpenWhatIs));
    LocaleBase = OpenLibrary((APTR)"locale.library",0l);
}


BOOL Scan(char *type, APTR buf, ULONG bufsize, BOOL *quotes) {
    BPTR fh=NULL;
    APTR cs;
    int line=0;
    int c=0;
    UBYTE *cur;
    BOOL res=TRUE;
    struct RDArgs *myargs=NULL,*ap;

    fh=Open((APTR) ACTIONFILE,MODE_OLDFILE);
    if (!fh) return(FALSE);
    cs= AllocVec(512,MEMF_CLEAR|MEMF_ANY);
    if (!cs) {
        if (fh) Close(fh);
        fh=NULL;
        return FALSE;
    }
    myargs=(struct RDArgs *)AllocDosObject(DOS_RDARGS,TAG_DONE);
    if (!myargs) {
        if (fh) Close(fh);
        fh = NULL;
        FreeVec(cs);
        return FALSE;
    }
    do {
        line++;
        cur=(UBYTE *)FGets(fh,(STRPTR)cs,512);
        if (!cur) {
            res=FALSE;
            break;
        }
        c=0;
        c=strlen(cur);
        if (*cur==';') continue;
        if (*cur=='\n') continue;
        if (cur[c-1]!='\n') {
            MUI_Request(app, win, 0, (char *)GetString(msgFAEditMsg), (char *)GetString(msgOK),
              (char *)GetString(msgMissingNEWLINE));
            res=FALSE;
            break;
        }
        myargs->RDA_Flags |= RDAF_NOPROMPT;
        myargs->RDA_Source.CS_Buffer = cs;
        myargs->RDA_Source.CS_Length = c;
        myargs->RDA_Source.CS_CurChr = 0L;
        ap=ReadArgs(CONFIG_TEMPLATE,ConfigLine,myargs);
        if (!ap) {
            res=FALSE;
            Fault(IoErr(),NULL, cs, 512);
            MUI_Request(app, win, 0, (char *)GetString(msgFAEditMsg), (char *)GetString(msgOK),
              (char *)GetString(msgParseError), line, (char *)cs);
            break;
        }
        if (stricmp(type,(char *)ConfigLine[CT_TYPE])==0) {
            strncpy((char *)buf,(char *)ConfigLine[CT_ACTION],bufsize);
            res=TRUE;
            if (bufsize<strlen((char *)ConfigLine[CT_ACTION])) res=FALSE;
            *quotes = ConfigLine[CT_QUOTES];
            break;
        }
        FreeArgs(ap);
    } while (1);
    if (fh) Close(fh);
    fh = NULL;
    if (cs) FreeVec(cs);
    if (myargs) FreeDosObject(DOS_RDARGS,myargs);
    return res;
}

ULONG   ConstructLV(struct Hook *hook, struct lv_ListEntry *entry, APTR pool) {
    geta4();
    return((ULONG)entry);
}


ULONG   DestructLV(struct Hook *hook, struct lv_ListEntry *entry, APTR pool) {
    geta4();
    FreeVec(entry->le_FileAction);
    FreeVec(entry);
    return(0);
}


ULONG   DisplayLV(struct Hook *hook, struct lv_ListEntry *entry, char **array) {
    geta4();
    *array = entry->le_FileType;
    return(0);
}


ULONG   CompareLV(struct Hook *hook, struct lv_ListEntry *e1, struct lv_ListEntry *e2) {
    geta4();
    return(stricmp(e1->le_FileType, e2->le_FileType));
}


void BuildList() {
    struct lv_ListEntry *le;
    FileType ft;
    char *IDString;
    int stl;

    ft = FirstType();

    set(ob_lv, MUIA_List_Quiet, TRUE);

    while (ft) {
        IDString = GetIDString(ft);
        if (Scan(IDString, (APTR)ActionBuffer, 255, &ActionQuotes)) {
            stl = strlen(ActionBuffer);
        } else {
            stl = 0;
            ActionQuotes = TRUE;
            strcpy(ActionBuffer,"");
        }
        le = AllocVec(sizeof(struct lv_ListEntry), MEMF_ANY);
        le->le_FileAction = AllocVec(stl, MEMF_ANY);
        strcpy(le->le_FileType,IDString);
        le->le_Flags = LE_QUOTES * (ActionQuotes == TRUE);
        strcpy(le->le_FileAction,ActionBuffer);
        DoMethod(ob_lv, MUIM_List_Insert, &le, 1, MUIV_List_Insert_Sorted);
        ft = NextType(ft);
    }

    set(ob_lv, MUIA_List_Quiet, FALSE);
}


BOOL WriteActionList(char *file) {

    struct lv_ListEntry *entry;
    BPTR fh;
    int i;
    char buffer[256];
    char error[256];
    LONG returnedLength, err;

    fh = Open((STRPTR)file, MODE_NEWFILE);
    if (fh) {
        for(i=0;;i++) {

            DoMethod(ob_lv, MUIM_List_GetEntry, i, &entry);
            if (!entry) break;

            if (strcmp(entry->le_FileAction,"") != 0) {
                sprintf(buffer, "TYPE \"%s\"\t ACTION \"%s\" %s\n",
                        entry->le_FileType, 
                        entry->le_FileAction, 
                        (entry->le_Flags & LE_QUOTES) ? "QUOTES" : " ");
                returnedLength =  Write(fh, buffer, strlen(buffer));
                if (err = IoErr()) {
                    Fault(err, NULL, (STRPTR)error, 256);
                    sprintf(buffer, GetString(msgUnableToWrite), file, error);
                    MUI_Request(app, win, 0, (char *)GetString(msgFAEditMsg), (char *)GetString(msgOK) , buffer);
                    break;
                }
            }
        }
        Close(fh);
    } else {
        err = IoErr();
        Fault(err, NULL, (STRPTR)error, 256);
        sprintf(buffer, GetString(msgUnableToWrite), file, error);
        MUI_Request(app, win, 0, (char *)GetString(msgFAEditMsg), (char *)GetString(msgOK), buffer);
    }
}


void SaveActionList() {

    char *file;
    char buffer[256];
    char path[256];
    char error[256];
    BPTR fh;
    LONG err;

    strcpy(path,ACTIONFILE);
    file = (char *)FilePart((STRPTR)path);
    strcpy(buffer,file);
    *file = '\0';

    if (FileRequest(TRUE, buffer, path)) {
        if (strcmp((char *)FilePart((STRPTR)FileName),"") == 0) {
            MUI_Request(app, win, 0, (char *)GetString(msgFAEditMsg) , (char *)GetString(msgOK), (char *)GetString(msgInvalidFilename));
        } else {
            fh = Lock((STRPTR)FileName, ACCESS_WRITE);
            if (fh) {
                UnLock(fh);
                sprintf(buffer, (char *)GetString(msgOverwrite), FileName);
                if (MUI_Request(app, win, 0, (char *)GetString(msgFAEditMsg), (char *)GetString(msgOkCancel), buffer)) {
                    WriteActionList(FileName);
                    strcpy(ACTIONFILE, FileName);                
                }
            } else {
                err = IoErr();
                if (err == ERROR_OBJECT_NOT_FOUND) {
                    WriteActionList(FileName);
                    strcpy(ACTIONFILE, FileName);                
                } else {
                    Fault(err, NULL, (STRPTR)error, 256);
                    sprintf(buffer, (char *)GetString(msgUnableToWrite), FileName, error);
                    MUI_Request(app, win, 0, (char *)GetString(msgFAEditMsg), (char *)GetString(msgOK), buffer);
                }
            }
        }
    }
}


void LoadActionList() {

    char *file;
    char buffer[256];
    char path[256];
    char error[256];
    BPTR fh;
    LONG err;

    strcpy(path,ACTIONFILE);
    file = (char *)FilePart((STRPTR)path);
    strcpy(buffer,file);
    *file = '\0';

    if (FileRequest(FALSE, buffer, path)) {
        if (fh = Lock((STRPTR)FileName, ACCESS_READ)) {
            strcpy(ACTIONFILE, FileName); 
            UnLock(fh);
            DoMethod(ob_lv, MUIM_List_Clear);
            BuildList();
            set(ob_ast, MUIA_String_Contents, empty);
        } else {
            err = IoErr();
            Fault(err, NULL, (STRPTR)error, 256);
            sprintf(buffer, (char *)GetString(msgUnableToOpen), FileName, error);
            MUI_Request(app, win, 0, (char *)GetString(msgFAEditMsg), (char *)GetString(msgOK), buffer);
        }
    }
}


void main(void) {
    BOOL      running = TRUE;
    ULONG     sig, leng, state;
    int       i;
    char      *stcontents;
    char      HotLoad, HotSave;
    char      buffer[256];
    char      lProject[30],
              lAbout[30],
              lOpen[30],
              lSave[30],
              lSaveAs[30],
              lQuit[30],
              lDont[40],
              lDo[40],
              lhAbout[2],
              lhOpen[2],
              lhSave[2],
              lhQuit[2];


    OpenAll();
    OpenFAEditCatalog(NULL, NULL);

    i = GetVar((STRPTR)"MegaViewACTION", (STRPTR)ACTIONFILE, 49, 0l);
    if (i==-1)
        strcpy(ACTIONFILE,"s:FileActions");

    lv_Construct.h_Entry    =   HookEntry;
    lv_Construct.h_SubEntry =   ConstructLV;

    lv_Destruct.h_Entry     =   HookEntry;
    lv_Destruct.h_SubEntry  =   DestructLV;

    lv_Display.h_Entry      =   HookEntry;
    lv_Display.h_SubEntry   =   DisplayLV;

    lv_Compare.h_Entry      =   HookEntry;
    lv_Compare.h_SubEntry   =   CompareLV;

    strcpy(buffer, (char *)GetString(msgHotKeys));

    HotLoad        = buffer[0];
    HotSave        = buffer[1];
    lhAbout[0]     = buffer[2];   lhAbout[1]     = 0;
    lhOpen[0]      = buffer[3];   lhOpen[1]      = 0;
    lhSave[0]      = buffer[4];   lhSave[1]      = 0;
    lhQuit[0]      = buffer[5];   lhQuit[1]      = 0;

    strcpy(lProject,    (char *)GetString(msgProject));
    strcpy(lAbout,      (char *)GetString(msgAbout));
    strcpy(lOpen,       (char *)GetString(msgOpen));
    strcpy(lSave,       (char *)GetString(msgSave));
    strcpy(lSaveAs,     (char *)GetString(msgSaveAs));
    strcpy(lQuit,       (char *)GetString(msgQuit));

    strcpy(lDont,       (char *)GetString(msgNoQuotes));
    strcpy(lDo,         (char *)GetString(msgQuotes));

    centries[0]    =    lDont;
    centries[1]    =    lDo;

    NM_Edit[0].nm_Label      =    (STRPTR)lProject;
    NM_Edit[1].nm_Label      =    (STRPTR)lAbout;
    NM_Edit[1].nm_CommKey    =    (STRPTR)lhAbout;
    NM_Edit[3].nm_Label      =    (STRPTR)lOpen;
    NM_Edit[3].nm_CommKey    =    (STRPTR)lhOpen;
    NM_Edit[5].nm_Label      =    (STRPTR)lSave;
    NM_Edit[5].nm_CommKey    =    (STRPTR)lhSave;
    NM_Edit[6].nm_Label      =    (STRPTR)lSaveAs;
    NM_Edit[8].nm_Label      =    (STRPTR)lQuit;
    NM_Edit[8].nm_CommKey    =    (STRPTR)lhQuit;
/*    NM_Edit[8].nm_Type       =    NM_ITEM;
    NM_Edit[8].nm_UserData   =    (APTR)MUIV_Application_ReturnID_Quit; */


    app = ApplicationObject,
        MUIA_Application_Title,         "FAEdit",
        MUIA_Application_Version,       "$VER: FAEdit 1.01",
        MUIA_Application_Copyright,     "© 1993 Thomas & Hans-Joerg Frieden", 
        MUIA_Application_Author,        "Thomas Frieden",
        MUIA_Application_Description,   (char *)GetString(msgFileactionEditor),
        MUIA_Application_Base,          "FAEDIT", 
        MUIA_Application_Menu,          NM_Edit, 

        SubWindow,  win = WindowObject,
            MUIA_Window_Width,          MUIV_Window_Width_Screen(80),
            MUIA_Window_Height,         MUIV_Window_Height_Screen(80),
            MUIA_Window_Title,          "FAEdit V1.01 © 1993 Thomas & Hans-Jörg Frieden",
            WindowContents, HGroup,     MUIA_Group_SameHeight, TRUE,

            Child, VGroup,  GroupFrameT((char *)GetString(msgType)),
                 Child,  ob_lv = ListviewObject,
                     MUIA_Listview_Input,TRUE,
                     MUIA_Listview_List, ListObject,
                         InputListFrame,
                         MUIA_List_DisplayHook,  lv_Display,
                         MUIA_List_CompareHook,  lv_Compare,
                         MUIA_List_ConstructHook,lv_Construct,
                         MUIA_List_DestructHook, lv_Destruct,
                     End, // ListObject
                End,    // ListviewObject
            End,   // VGroup

            Child, VGroup,
                Child, VGroup,  
                       GroupFrameT((char *)GetString(msgAction)),

                        Child,  ob_ast = StringObject,
                            StringFrame,
                        End, // StringObject

                        Child,  ob_qu = CycleObject,
                            MUIA_Cycle_Entries,     centries,
                        End, // CycleObject

                    End,     // VGroup
                    Child,  VSpace(0),
                    Child,  VGroup, GroupFrameT((char *)GetString(msgDiskIO)),
                        Child,  ob_load  =  KeyButton((char *)GetString(msgLoadFileactions), HotLoad),
                        Child,  ob_save  =  KeyButton((char *)GetString(msgSaveFileactions), HotSave),
                    End,     // VGroup
                End,    // VGroup
            End, // HGroup
        End,  // WindowObject
    End; // Application


        DoMethod(win, MUIM_Window_SetCycleChain, ob_lv, ob_ast, ob_qu, 
            ob_load, ob_save);
        DoMethod(win, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
            app, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
        DoMethod(ob_lv, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
            app, 2, MUIM_Application_ReturnID, NO_LISTSELECT);
        DoMethod(ob_ast, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
            app, 2, MUIM_Application_ReturnID, NO_ACTIONTRIGGER);
        DoMethod(ob_qu, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime,  
            app, 2, MUIM_Application_ReturnID, NO_QUOTETRIGGER);
        DoMethod(ob_save, MUIM_Notify, MUIA_Pressed, FALSE, 
            app, 2, MUIM_Application_ReturnID, NO_SAVEACTION);
        DoMethod(ob_load, MUIM_Notify, MUIA_Pressed, FALSE,
            app, 2, MUIM_Application_ReturnID, NO_LOADACTION);

        BuildList();

        set(win, MUIA_Window_Open, TRUE);
        get(win, MUIA_Window_Open, &winopen);

        if (!winopen) {
            MUI_Request(app, win, 0, (char *)GetString(msgFAEditMsg), (char *)GetString(msgOK), (char *)GetString(msgFailedToOpenMUI));
            MUI_DisposeObject(app);
            CloseAll(NULL);
            exit(0);
        }

        running = TRUE;

        while (running) {
            switch(DoMethod(app,MUIM_Application_Input,&sig)) {
            case NO_ACTIONTRIGGER:
                DoMethod(ob_lv, MUIM_List_GetEntry, MUIV_List_GetEntry_Active,
                    &SelectEntry);
                get(ob_ast, MUIA_String_Contents, &stcontents);

                FreeVec(SelectEntry->le_FileAction);
                SelectEntry->le_FileAction = AllocVec(strlen(stcontents), MEMF_ANY);
                strcpy(SelectEntry->le_FileAction, stcontents);

                break;

            case NO_QUOTETRIGGER:
                DoMethod(ob_lv, MUIM_List_GetEntry, MUIV_List_GetEntry_Active,
                    &SelectEntry);
                get(ob_qu, MUIA_Cycle_Active, &state);

                  if (state == 1) 
                    SelectEntry->le_Flags |= LE_QUOTES;
                else
                    SelectEntry->le_Flags = 0;
                        
                break;

            case NO_LISTSELECT:
                DoMethod(ob_lv, MUIM_List_GetEntry, MUIV_List_GetEntry_Active,
                    &SelectEntry);
                if (SelectEntry->le_FileAction)
                    set(ob_ast, MUIA_String_Contents, SelectEntry->le_FileAction);
                set(ob_qu, MUIA_Cycle_Active, (SelectEntry->le_Flags && LE_QUOTES));
                break;

            case NO_SAVEACTION:
                SaveActionList();
                break;

            case NO_SAVEACTIONA:
                WriteActionList(ACTIONFILE);
                break;

            case NO_LOADACTION:
                LoadActionList();
                break;

            case NO_ABOUT:
                MUI_Request(app, win, 0, (char *)GetString(msgFAEditMsg), (char *)GetString(msgOK), (char *)GetString(msgAboutText));
                break;

            case MUIV_Application_ReturnID_Quit:
                running = FALSE;
                break;
            }
            if (running && sig)
                Wait(sig);
        }
        DoMethod(ob_lv, MUIM_List_Clear, NULL);
        MUI_DisposeObject(app);

    CloseFAEditCatalog();
    CloseAll(NULL);
}
