/****************************************/
/* ML-Support                           */
/* Freeware                             */
/* © 1998-2000 Christian Hattemer       */
/* email: chris@riednet.tu-darmstadt.de */
/* 17.08.2000 16:12                     */
/****************************************/

#ifndef MAKE_ID
   #define MAKE_ID(a,b,c,d) ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
#endif

/* stormamiga.lib */
#ifdef USESTORMAMIGA
   #define STORMAMIGA
   #include <stormamiga.h>
   #define sprintf SPRINTF
#endif

/* Ansi */
#include <string.h>

/* ML-Support */
#include "GUI.h"
#include "Creator.h"
#include "ML_Support_Cat.h"
#include "Mainwin.h"
#include "MLList.h"

/* Protos */
#include <proto/utility.h>

#include <libraries/asl.h>
#include <libraries/gadtools.h>

/* Functions */
METHOD Mainwin_New       (Class *cl, Object *obj, struct opSet *msg);
METHOD Mainwin_Finish    (Class *cl, Object *obj, Msg msg);
METHOD Mainwin_CYCmdState(Class *cl, Object *obj, Msg msg);
METHOD Mainwin_Ghostings (Class *cl, Object *obj, Msg msg);
METHOD Mainwin_ShowAbout (Class *cl, Object *obj, Msg msg);
METHOD Mainwin_Write     (Class *cl, Object *obj, Msg msg);
METHOD Mainwin_Merge     (Class *cl, Object *obj, Msg msg);
ULONG SAVEDS Mainwin_Dispatcher(REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) Msg msg);

void  SAVEDS IntuiMsgFunc(REG(a1) struct IntuiMessage *IMsg, REG(a2) struct FileRequester *Req);
static STRPTR GetFilename(Object *Win, STRPTR Title, STRPTR OldFile, BOOL Save);

/* Structures */
static struct MUI_CustomClass *CL_MLList;

static struct Mainwin_Data
{
   Object *LV_MLNames;
   Object *CY_Command;
   Object *STR_Custom;
   Object *BT_Write;

   struct MsgPort *ReplyPort;
   STRPTR CreatorName;
};


METHOD Mainwin_New(Class *cl, Object *obj, struct opSet *msg)
{
   Object *MN_Root;

   static STRPTR CYA_Command[] =
   {
      (STRPTR)_LBL_CMD_SUBSCRIBE,
      (STRPTR)_LBL_CMD_UNSUBSCRIBE,
      (STRPTR)_LBL_CMD_CUSTOM,
      NULL
   };

   enum {MEN_PROJECT_MERGE = 1, MEN_PROJECT_ABOUT,  MEN_PROJECT_ABOUT_MUI,
         MEN_PROJECT_QUIT, MEN_SETTINGS_SAVE, MEN_SETTINGS_MUI
        };

   struct NewMenu NM_Mainwin[] =
   {
      {NM_TITLE, (STRPTR)_LBL_MN_PROJECT  , NULL, 0, 0, NULL                       },
      { NM_ITEM, (STRPTR)_LBL_MN_MERGE    , NULL, 0, 0, (APTR)MEN_PROJECT_MERGE    },
      { NM_ITEM, NM_BARLABEL              , NULL, 0, 0, NULL                       },
      { NM_ITEM, (STRPTR)_LBL_MN_ABOUT    , NULL, 0, 0, (APTR)MEN_PROJECT_ABOUT    },
      { NM_ITEM, (STRPTR)_LBL_MN_ABOUT_MUI, NULL, 0, 0, (APTR)MEN_PROJECT_ABOUT_MUI},
      { NM_ITEM, NM_BARLABEL              , NULL, 0, 0, NULL                       },
      { NM_ITEM, (STRPTR)_LBL_MN_QUIT     , NULL, 0, 0, (APTR)MEN_PROJECT_QUIT     },

      {NM_TITLE, (STRPTR)_LBL_MN_SETTINGS , NULL, 0, 0, NULL                       },
      { NM_ITEM, (STRPTR)_LBL_MN_SAVE     , NULL, 0, 0, (APTR)MEN_SETTINGS_SAVE    },
      { NM_ITEM, (STRPTR)_LBL_MN_MUI      , NULL, 0, 0, (APTR)MEN_SETTINGS_MUI     },

      {NM_END  , NULL                     , NULL, 0, 0, NULL                       }
   };

   struct Mainwin_Data Temp, *Data;

   LocalizeStringArray(CYA_Command);
   LocalizeNewMenu(NM_Mainwin);

   obj = (Object *)DoSuperNew(cl, obj,
      MUIA_Window_Title, TITLE_MAINWIN,
      MUIA_Window_ID, MAKE_ID('M', 'A', 'I', 'N'),
      MUIA_Window_Menustrip, MN_Root = MUI_MakeObject(MUIO_MenustripNM, NM_Mainwin, 0),

      WindowContents, VGroup,
         Child, Temp.LV_MLNames = MLListObject,
         End,

         Child, VSpace(-2),

         Child, ColGroup(2),
            Child, Label1(LBL_COMMAND),
            Child, Temp.CY_Command = MUI_MakeObject(MUIO_Cycle, LBL_COMMAND, &CYA_Command),

            Child, Label2(LBL_CUSTOM),
            Child, Temp.STR_Custom = MUI_MakeObject(MUIO_String, LBL_CUSTOM, MAX_TEXT),
         End,

         Child, VSpace(-2),

         Child, HCenter(Temp.BT_Write = SimpleButton(LBL_WRITE)),
      End,
   End;

   if (!obj)
   {
      return NULL;
   }

   set(Temp.STR_Custom, MUIA_String_Contents, "HELP");

   DoMethod(obj, MUIM_MultiSet,
            MUIA_CycleChain, 1,
            Temp.CY_Command, Temp.STR_Custom, Temp.BT_Write, NULL
           );

   set(Temp.CY_Command, MUIA_ShortHelp, BBL_COMMAND);
   set(Temp.STR_Custom, MUIA_ShortHelp, BBL_CUSTOM );
   set(Temp.BT_Write  , MUIA_ShortHelp, BBL_WRITE  );

   Data = INST_DATA(cl, obj);
   *Data = Temp;
   Data->CreatorName = (STRPTR)GetTagData(MUIA_Mainwin_Creator, NULL, msg->ops_AttrList);

   // Load List Contents
   DoMethod(Data->LV_MLNames, MUIM_MLList_Load, "PROGDIR:ML-Support.cfg", FALSE);

   // set GUI state
   DoMethod(obj, MUIM_Mainwin_Ghostings);
   DoMethod(obj, MUIM_Mainwin_CYCmdState);

   // Notify Menus
   DoMethod(FINDOBJ(MN_Root, MEN_PROJECT_MERGE),
            MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
            obj,
            1,
            MUIM_Mainwin_Merge
           );

   DoMethod(FINDOBJ(MN_Root, MEN_PROJECT_ABOUT),
            MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
            obj,
            1,
            MUIM_Mainwin_ShowAbout
           );

   DoMethod(FINDOBJ(MN_Root, MEN_PROJECT_ABOUT_MUI),
            MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
            MUIV_Notify_Application,
            2,
            MUIM_Application_AboutMUI, obj
           );

   DoMethod(FINDOBJ(MN_Root, MEN_PROJECT_QUIT),
            MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
            obj,
            1,
            MUIM_Mainwin_Finish
           );

   DoMethod(FINDOBJ(MN_Root, MEN_SETTINGS_SAVE),
            MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
            Data->LV_MLNames,
            1,
            MUIM_MLList_Save
           );

   DoMethod(FINDOBJ(MN_Root, MEN_SETTINGS_MUI),
            MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
            MUIV_Notify_Application,
            2,
            MUIM_Application_OpenConfigWindow, 0
           );

   // Notify Window
   DoMethod(obj,
            MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
            obj,
            1,
            MUIM_Mainwin_Finish
           );

   DoMethod(Data->LV_MLNames,
            MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
            obj,
            1,
            MUIM_Mainwin_CYCmdState
           );

   DoMethod(Data->LV_MLNames,
            MUIM_Notify, MUIA_MLList_Edited, MUIV_EveryTime,
            obj,
            1,
            MUIM_Mainwin_CYCmdState
           );

   DoMethod(Data->LV_MLNames,
            MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
            obj,
            1,
            MUIM_Mainwin_Ghostings
           );

   DoMethod(Data->CY_Command,
            MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime,
            obj,
            1,
            MUIM_Mainwin_Ghostings
           );

   DoMethod(Data->BT_Write,
            MUIM_Notify, MUIA_Pressed, FALSE,
            obj,
            1,
            MUIM_Mainwin_Write
           );

   return (ULONG)obj;
}

METHOD Mainwin_Finish(Class *cl, Object *obj, Msg msg)
{
   LONG Choice;

   struct Mainwin_Data *Data = INST_DATA(cl, obj);

   if (xget(Data->LV_MLNames, MUIA_MLList_Changed))
   {
      Choice = MUI_Request(_app(obj),
                           obj,
                           0,
                           TITLE_MAINWIN,
                           LBL_SAVEQUIT,
                           MSG_UNSAVED
                          );

      if (Choice == 1)
      {
         if (DoMethod(Data->LV_MLNames, MUIM_MLList_Save) == FALSE)
         {
            return 0;
         }
      }

      if (Choice == 0)
      {
         return 0;
      }
   }

   DoMethod(_app(obj), MUIM_Application_ReturnID,
                       MUIV_Application_ReturnID_Quit
           );

   return 0;
}

METHOD Mainwin_CYCmdState(Class *cl, Object *obj, Msg msg)
{
   struct MLListNode *MLN;
   struct Mainwin_Data *Data = INST_DATA(cl, obj);

   DoMethod(Data->LV_MLNames, MUIM_List_GetEntry,
            MUIV_List_GetEntry_Active, &MLN
           );

   if (MLN)
   {
      set(Data->CY_Command, MUIA_Cycle_Active, MLN->IsSubs ? 1 : 0);
   }

   return 0;
}

METHOD Mainwin_Ghostings(Class *cl, Object *obj, Msg msg)
{
   struct Mainwin_Data *Data = INST_DATA(cl, obj);

   // Write Button

   if (xget(Data->LV_MLNames, MUIA_List_Active) == MUIV_List_Active_Off)
   {
      set(Data->BT_Write, MUIA_Disabled, TRUE);
   }
   else
   {
      set(Data->BT_Write, MUIA_Disabled, FALSE);
   }

   // Custom String

   if (xget(Data->CY_Command, MUIA_Cycle_Active) == CY_COMMAND_ENTRY_CUSTOM)
   {
      set(Data->STR_Custom, MUIA_Disabled, FALSE);
   }
   else
   {
      set(Data->STR_Custom, MUIA_Disabled, TRUE);
   }

   return 0;
}

METHOD Mainwin_ShowAbout(Class *cl, Object *obj, Msg msg)
{
   //struct Mainwin_Data *Data = INST_DATA(cl, obj);

   MUI_Request(_app(obj), obj, 0,
               TITLE_APP_ABOUT,
               LBL_OK_ACTIVE,
               MSG_APP_ABOUT,
               xget(_app(obj), MUIA_Application_Version) + 6
              );

   return 0;
}

METHOD Mainwin_Write(Class *cl, Object *obj, Msg msg)
{
   Object *CreatorObj;

   struct Mainwin_Data *Data = INST_DATA(cl, obj);

   CreatorObj = MUI_NewObject(Data->CreatorName, TAG_DONE);

   if (CreatorObj == NULL)
   {
      MUI_RequestA(_app(obj), obj, 0,
                   TITLE_MAINWIN,
                   LBL_OK_ACTIVE,
                   MSG_CREATOR_INIT_FAILED,
                   NULL
                  );

      return 0;
   }

   DoMethod(CreatorObj, MUIM_Creator_Create,
            _app(obj), obj,
            Data->LV_MLNames, Data->CY_Command, Data->STR_Custom
           );

   MUI_DisposeObject(CreatorObj);

   return 0;
}

METHOD Mainwin_Merge(Class *cl, Object *obj, Msg msg)
{
   struct Mainwin_Data *Data = INST_DATA(cl, obj);

   STRPTR Filename;

   if (Filename = GetFilename(obj, TITLE_FR_MERGE, "PROGDIR:", FALSE))
   {
      set(Data->LV_MLNames, MUIA_List_Quiet, TRUE);
      DoMethod(Data->LV_MLNames, MUIM_MLList_Load, Filename, TRUE);
      DoMethod(Data->LV_MLNames, MUIM_List_Sort);
      set(Data->LV_MLNames, MUIA_List_Quiet, FALSE);
      set(Data->LV_MLNames, MUIA_MLList_Changed, TRUE);
   }

   return 0;
}

ULONG SAVEDS Mainwin_Dispatcher(REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) Msg msg)
{
   switch (msg->MethodID)
   {
      case OM_NEW                 : return Mainwin_New       (cl, obj, (APTR)msg);
      case MUIM_Mainwin_Finish    : return Mainwin_Finish    (cl, obj, (APTR)msg);
      case MUIM_Mainwin_CYCmdState: return Mainwin_CYCmdState(cl, obj, (APTR)msg);
      case MUIM_Mainwin_Ghostings : return Mainwin_Ghostings (cl, obj, (APTR)msg);
      case MUIM_Mainwin_ShowAbout : return Mainwin_ShowAbout (cl, obj, (APTR)msg);
      case MUIM_Mainwin_Write     : return Mainwin_Write     (cl, obj, (APTR)msg);
      case MUIM_Mainwin_Merge     : return Mainwin_Merge     (cl, obj, (APTR)msg);
   }

   return DoSuperMethodA(cl, obj, msg);
}

void SAVEDS IntuiMsgFunc(REG(a1) struct IntuiMessage *IMsg, REG(a2) struct FileRequester *Req)
{
   if (IMsg->Class == IDCMP_REFRESHWINDOW)
   {
      DoMethod(Req->fr_UserData, MUIM_Application_CheckRefresh);
   }
}

static STRPTR GetFilename(Object *Win, STRPTR Title, STRPTR OldFile, BOOL Save)
{
   static TEXT Buffer[512];
   struct FileRequester *Req;
   struct Window *w;
   static LONG Left = -1, Top = -1, Width = -1, Height = -1;
   Object *App = (Object *)xget(Win, MUIA_ApplicationObject);
   STRPTR Result = NULL;
   static const struct Hook IntuiMsgHook = { { 0, 0 }, (VOID *)IntuiMsgFunc, NULL, NULL };

   get(Win, MUIA_Window_Window, &w);
   if (Left == -1)
   {
      Left   = w->LeftEdge + w->BorderLeft + 2;
      Top    = w->TopEdge  + w->BorderTop  + 2;
      Width  = w->Width  - w->BorderLeft - w->BorderRight  - 4;
      Height = w->Height - w->BorderTop  - w->BorderBottom - 4;
   }

   stccpy(Buffer, OldFile, sizeof(Buffer));
   *(PathPart(Buffer)) = '\0';

   if (Req = MUI_AllocAslRequestTags(ASL_FileRequest,
      ASLFR_Window, w,
      ASLFR_TitleText, Title,
      ASLFR_InitialLeftEdge, Left,
      ASLFR_InitialTopEdge , Top,
      ASLFR_InitialWidth   , Width,
      ASLFR_InitialHeight  , Height,
      ASLFR_InitialDrawer  , Buffer,
      ASLFR_InitialFile    , FilePart(OldFile),
      ASLFR_InitialPattern , "#?",
      ASLFR_DoSaveMode     , Save,
      ASLFR_DoPatterns     , TRUE,
      ASLFR_RejectIcons    , TRUE,
      ASLFR_UserData       , App,
      ASLFR_IntuiMsgFunc   , &IntuiMsgHook,
      TAG_DONE))
   {
      set(App, MUIA_Application_Sleep, TRUE);
      if (MUI_AslRequestTags(Req, TAG_DONE))
      {
         if (! EMPTYSTR(Req->fr_File))
         {
            Result = Buffer;
            stccpy(Buffer, Req->fr_Drawer, sizeof(Buffer));
            AddPart(Buffer, Req->fr_File, sizeof(Buffer));
         }

         Left   = Req->fr_LeftEdge;
         Top    = Req->fr_TopEdge;
         Width  = Req->fr_Width;
         Height = Req->fr_Height;
      }

      MUI_FreeAslRequest(Req);
      set(App, MUIA_Application_Sleep, FALSE);
   }

   return Result;
}

struct MUI_CustomClass *CreateMainwinClass()
{
   if (CL_MLList = CreateMLListClass())
   {
      struct MUI_CustomClass *CL_Mainwin;

      CL_Mainwin = MUI_CreateCustomClass(NULL,
                                         MUIC_Window, NULL,
                                         sizeof(struct Mainwin_Data),
                                         Mainwin_Dispatcher
                                        );
      if (CL_Mainwin)
      {
         return CL_Mainwin;
      }
   }

   DeleteMainwinClass(NULL);
   return NULL;
}

void DeleteMainwinClass(struct MUI_CustomClass *CL_Mainwin)
{
   if (CL_Mainwin)
   {
      MUI_DeleteCustomClass(CL_Mainwin);
   }

   if (CL_MLList)
   {
      DeleteMLListClass(CL_MLList);
      CL_MLList = NULL;
   }
}

