/****************************************/
/* ML-Support                           */
/* Freeware                             */
/* © 1998-2000 Christian Hattemer       */
/* email: chris@riednet.tu-darmstadt.de */
/* 23.08.2000 18:37                     */
/****************************************/

/* stormamiga.lib */
#ifdef USESTORMAMIGA
   #define STORMAMIGA
   #include <stormamiga.h>
   #define snprintf snprintf_
#endif

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

/* ML-Support */
#include "GUI.h"
#include "ML_Support_Cat.h"
#include "MLList.h"
#include "Editwin.h"
#include "Config.h"

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

#include <utility/hooks.h>

/* Functions */
METHOD MLList_New  (Class *cl, Object *obj, struct opSet *msg);
METHOD MLList_Set  (Class *cl, Object *obj, struct opSet *msg);
METHOD MLList_Get  (Class *cl, Object *obj, struct opGet *msg);
METHOD MLList_Add  (Class *cl, Object *obj, Msg msg);
METHOD MLList_Clone(Class *cl, Object *obj, Msg msg);
METHOD MLList_Edit (Class *cl, Object *obj, struct MUIP_MLList_Edit *msg);
METHOD MLList_Load (Class *cl, Object *obj, struct MUIP_MLList_Load *msg);
METHOD MLList_Save (Class *cl, Object *obj, Msg msg);
METHOD MLList_Remove (Class *cl, Object *obj, Msg msg);
METHOD MLList_BTState(Class *cl, Object *obj, Msg msg);
METHOD MLList_Setup  (Class *cl, Object *obj, struct MUIP_Setup *msg);
ULONG SAVEDS MLList_Dispatcher(REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) Msg msg);

APTR  SAVEDS ConstructFunc(REG(a0) struct Hook *hook, REG(a2) APTR pool   , REG(a1) struct MLListNode *MLN);
void  SAVEDS DestructFunc (REG(a0) struct Hook *hook, REG(a2) APTR pool   , REG(a1) struct MLListNode *MLN);
ULONG SAVEDS DisplayFunc  (REG(a0) struct Hook *hook, REG(a2) char **array, REG(a1) struct MLListNode *MLN);

/* Structures */
static const struct Hook ConstructHook = { {0, 0}, (HOOKFUNC)ConstructFunc, NULL, NULL };
static const struct Hook DestructHook  = { {0, 0}, (HOOKFUNC)DestructFunc , NULL, NULL };
static const struct Hook DisplayHook   = { {0, 0}, (HOOKFUNC)DisplayFunc  , NULL, NULL };

static struct MUI_CustomClass *CL_Editwin;

static struct MUIP_MLList_Edit
{
   ULONG MethodID;
   LONG  IsNewEntry;
};

static struct MUIP_MLList_Load
{
   ULONG  MethodID;
   STRPTR Filename;
   LONG   DoMerge;
};

static struct MLList_Data
{
   Object *LV_MLNames;
   Object *BT_Add;
   Object *BT_Clone;
   Object *BT_Edit;
   Object *BT_Remove;
   Object *BT_All;
   Object *BT_None;
   Object *WI_Edit;

   LONG Changed;
   LONG Edited;
};


METHOD MLList_New(Class *cl, Object *obj, struct opSet *msg)
{
   struct MLList_Data Temp, *Data;

   obj = (Object *)DoSuperNew(cl, obj,
      MUIA_Group_Spacing, 0,
      Child, Temp.LV_MLNames = ListviewObject,
         MUIA_CycleChain, 1,
         MUIA_Listview_MultiSelect, MUIV_Listview_MultiSelect_Default,
         MUIA_Listview_List, ListObject,
            InputListFrame,
            MUIA_List_ConstructHook, &ConstructHook,
            MUIA_List_DestructHook, &DestructHook,
            MUIA_List_DisplayHook, &DisplayHook,
            MUIA_List_Format, "BAR,",
            MUIA_ShortHelp, BBL_MLLIST,
         End,
      End,

      Child, HGroup,
         MUIA_Group_Spacing, 0,
         MUIA_Group_SameSize, TRUE,
         Child, Temp.BT_Add    = SimpleButton(LBL_ADD),
         Child, Temp.BT_Clone  = SimpleButton(LBL_CLONE),
         Child, Temp.BT_Edit   = SimpleButton(LBL_EDIT),
         Child, Temp.BT_Remove = SimpleButton(LBL_REMOVE),
         Child, Temp.BT_All    = SimpleButton(LBL_ALL),
         Child, Temp.BT_None   = SimpleButton(LBL_NONE),
      End,
   End;

   if (!obj)
   {
      return NULL;
   }

   DoMethod(obj, MUIM_MultiSet,
            MUIA_Disabled, TRUE,
            Temp.BT_Clone, Temp.BT_Edit, Temp.BT_Remove,
            Temp.BT_All  , Temp.BT_None, NULL
           );

   DoMethod(obj, MUIM_MultiSet,
            MUIA_CycleChain, 1,
            Temp.BT_Add   , Temp.BT_Clone, Temp.BT_Edit,
            Temp.BT_Remove, Temp.BT_All  , Temp.BT_None, NULL
           );

   Data = INST_DATA(cl, obj);
   *Data = Temp;
   Data->WI_Edit = NULL;

   Data->Changed = FALSE;
   Data->Edited  = FALSE;

   DoMethod(Data->BT_Add,
            MUIM_Notify, MUIA_Pressed, FALSE,
            obj,
            1,
            MUIM_MLList_Add
           );

   DoMethod(Data->BT_Clone,
            MUIM_Notify, MUIA_Pressed, FALSE,
            obj,
            1,
            MUIM_MLList_Clone
           );

   DoMethod(Data->BT_Edit,
            MUIM_Notify, MUIA_Pressed, FALSE,
            obj,
            2,
            MUIM_MLList_Edit, FALSE
           );

   DoMethod(Data->BT_Remove,
            MUIM_Notify, MUIA_Pressed, FALSE,
            obj,
            1,
            MUIM_MLList_Remove
           );

   DoMethod(Data->BT_All,
            MUIM_Notify, MUIA_Pressed, FALSE,
            Data->LV_MLNames,
            4,
            MUIM_List_Select,
            MUIV_List_Select_All, MUIV_List_Select_On, NULL
           );

   DoMethod(Data->BT_None,
            MUIM_Notify, MUIA_Pressed, FALSE,
            Data->LV_MLNames,
            4,
            MUIM_List_Select,
            MUIV_List_Select_All, MUIV_List_Select_Off, NULL
           );

   DoMethod(Data->LV_MLNames,
            MUIM_Notify, MUIA_Listview_DoubleClick, TRUE,
            obj,
            2,
            MUIM_MLList_Edit, FALSE
           );

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

   return ((ULONG)obj);
}

METHOD MLList_Set(Class *cl, Object *obj, struct opSet *msg)
{
   struct MLList_Data *Data = INST_DATA(cl, obj);
   struct TagItem *tags, *tag;

   for (tags = msg->ops_AttrList; tag = NextTagItem(&tags); )
   {
      switch (tag->ti_Tag)
      {
         case MUIA_MLList_Changed:
            Data->Changed = tag->ti_Data;
            break;

         case MUIA_MLList_Edited:
            Data->Edited = tag->ti_Data;
            break;
      }
   }

   return (DoSuperMethodA(cl, obj, (Msg)msg));
}

METHOD MLList_Get(Class *cl, Object *obj, struct opGet *msg)
{
   struct MLList_Data *Data = INST_DATA(cl, obj);

   switch (msg->opg_AttrID)
   {
      case MUIA_MLList_Changed:
         *(msg->opg_Storage) = Data->Changed;
         return TRUE;

      case MUIA_MLList_Edited:
         *(msg->opg_Storage) = Data->Edited;
         return TRUE;
   }

   return (DoSuperMethodA(cl, obj, (Msg)msg));
}

METHOD MLList_Add(Class *cl, Object *obj, Msg msg)
{
   struct MLList_Data *Data = INST_DATA(cl, obj);
   struct MLListNode New;

   New.MLName[0] = '\0';
   strcpy(New.SubsCmd, "SUBSCRIBE");
   strcpy(New.UnsubsCmd, "UNSUBSCRIBE");
   New.ServerAdd[0] = '\0';
   New.AddData = 0L;
   New.Comment[0] = '\0';
   New.ToCmd   = 0L;
   New.IsSubs  = 0L;

   DoMethod(Data->LV_MLNames, MUIM_List_InsertSingle,
            &New, MUIV_List_Insert_Bottom
           );

   set(Data->LV_MLNames, MUIA_List_Active, MUIV_List_Active_Bottom);

   DoMethod(obj, MUIM_MLList_Edit, TRUE);

   return 0;
}

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

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

   if (MLN)
   {
      DoMethod(Data->LV_MLNames, MUIM_List_InsertSingle,
               MLN, MUIV_List_Insert_Active
              );

      DoMethod(obj, MUIM_MLList_Edit, TRUE);
   }

   return 0;
}

METHOD MLList_Edit(Class *cl, Object *obj, struct MUIP_MLList_Edit *msg)
{
   struct MLListNode *MLN;
   struct MLList_Data *Data = INST_DATA(cl, obj);

   if (Data->WI_Edit == NULL)
   {
      Data->WI_Edit = EditwinObject,
      End;

      if (Data->WI_Edit)
      {
         DoMethod(_app(obj), OM_ADDMEMBER, Data->WI_Edit);
      }
      else
      {
         DisplayBeep(_screen(obj));
         return 0;
      }
   }

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

   if (MLN)
   {
      set(_win(obj), MUIA_Window_Sleep, TRUE);

      switch (DoMethod(Data->WI_Edit, MUIM_Editwin_Edit, MLN))
      {
         case MUIV_Editwin_Ok:
            DoMethod(Data->LV_MLNames, MUIM_List_Sort);
            DoMethod(Data->LV_MLNames, MUIM_List_Redraw, MUIV_List_Redraw_Active);
            set(obj, MUIA_MLList_Edited, TRUE);
            Data->Changed = TRUE;
            break;

         case MUIV_Editwin_Cancel:
            if (msg->IsNewEntry)
            {
               DoMethod(Data->LV_MLNames, MUIM_List_Remove, MUIV_List_Remove_Active);
            }
            break;
      }

      set(_win(obj), MUIA_Window_Sleep, FALSE);
   }

   return 0;
}

METHOD MLList_Load(Class *cl, Object *obj, struct MUIP_MLList_Load *msg)
{
   TEXT Buf[20];
   BOOL Merge = msg->DoMerge;
   int i = 0;

   struct ConfigData  *Config;
   struct MLListNode   New;
   struct MLList_Data *Data = INST_DATA(cl, obj);

   Config = OpenConfig(msg->Filename);

   if (Config == NULL)
   {
      return 0;
   }

   for (;;)
   {
      snprintf(Buf, sizeof(Buf), "MLName%02ld   ", i);
      ReadConfig(Config, "MLList", Buf, New.MLName, MAX_TEXT, "");

      snprintf(Buf, sizeof(Buf), "SubsCmd%02ld  ", i);
      ReadConfig(Config, "MLList", Buf, New.SubsCmd, MAX_TEXT, "");

      snprintf(Buf, sizeof(Buf), "UnsubsCmd%02ld", i);
      ReadConfig(Config, "MLList", Buf, New.UnsubsCmd, MAX_TEXT, "");

      snprintf(Buf, sizeof(Buf), "ServerAdd%02ld", i);
      ReadConfig(Config, "MLList", Buf, New.ServerAdd, MAX_TEXT, "");

      snprintf(Buf, sizeof(Buf), "AddData%02ld  ", i);
      New.AddData = ReadConfigNumber(Config, "MLList", Buf, 0);

      snprintf(Buf, sizeof(Buf), "Comment%02ld  ", i);
      ReadConfig(Config, "MLList", Buf, New.Comment, MAX_TEXT, "");

      if (Merge)
      {
         New.IsSubs = FALSE;
      }
      else
      {
         snprintf(Buf, sizeof(Buf), "IsSubs%02ld   ", i);
         New.IsSubs  = ReadConfigNumber(Config, "MLList", Buf, 0);
      }

      snprintf(Buf, sizeof(Buf), "ToCmd%02ld    ", i);
      New.ToCmd   = ReadConfigNumber(Config, "MLList", Buf, 0);

      if (EMPTYSTR(New.MLName))
      {
         break;
      }

      DoMethod(Data->LV_MLNames, MUIM_List_InsertSingle,
               &New, MUIV_List_Insert_Bottom
              );

      i++;
   }

   CloseConfig(Config);

   set(Data->LV_MLNames, MUIA_List_Active, MUIV_List_Active_Top);

   return 0;
}

METHOD MLList_Save(Class *cl, Object *obj, Msg msg)
{
   TEXT Buf[20];
   LONG NumEntries, i;
   BOOL WriteFailed = FALSE;

   struct ConfigData  *Config;
   struct MLListNode  *MLN;
   struct MLList_Data *Data = INST_DATA(cl, obj);

   set(_win(obj), MUIA_Window_Sleep, TRUE);

   Config = OpenConfig("PROGDIR:ML-Support.cfg");

   if (Config)
   {
      DeleteSection(Config, "MLList");

      NumEntries = xget(Data->LV_MLNames, MUIA_List_Entries);

      for (i = 0; i < NumEntries; i++)
      {
         DoMethod(Data->LV_MLNames, MUIM_List_GetEntry, i, &MLN);

         snprintf(Buf, sizeof(Buf), "MLName%02ld   ", i);
         ModifyConfig(Config, "MLList", Buf, MLN->MLName   );

         snprintf(Buf, sizeof(Buf), "SubsCmd%02ld  ", i);
         ModifyConfig(Config, "MLList", Buf, MLN->SubsCmd  );

         snprintf(Buf, sizeof(Buf), "UnsubsCmd%02ld", i);
         ModifyConfig(Config, "MLList", Buf, MLN->UnsubsCmd);

         snprintf(Buf, sizeof(Buf), "ServerAdd%02ld", i);
         ModifyConfig(Config, "MLList", Buf, MLN->ServerAdd);

         snprintf(Buf, sizeof(Buf), "AddData%02ld  ", i);
         ModifyConfigNumber(Config, "MLList", Buf, MLN->AddData);

         snprintf(Buf, sizeof(Buf), "Comment%02ld  ", i);
         ModifyConfig(Config, "MLList", Buf, MLN->Comment);

         snprintf(Buf, sizeof(Buf), "IsSubs%02ld   ", i);
         ModifyConfigNumber(Config, "MLList", Buf, MLN->IsSubs );

         snprintf(Buf, sizeof(Buf), "ToCmd%02ld    ", i);
         ModifyConfigNumber(Config, "MLList", Buf, MLN->ToCmd  );
      }

      if (Config->Failed == FALSE)
      {
         if (WriteConfig(Config) == CFG_WRITE_SUCCESS)
         {
            Data->Changed = FALSE;
         }
         else
         {
            WriteFailed = TRUE;
         }
      }
      else
      {
         WriteFailed = TRUE;
      }

      CloseConfig(Config);
   }

   set(_win(obj), MUIA_Window_Sleep, FALSE);

   if (WriteFailed == TRUE || Config == NULL)
   {
      MUI_RequestA(_app(obj), _win(obj), 0,
                   TITLE_MAINWIN,
                   LBL_OK_ACTIVE,
                   MSG_SAVE_FAILED,
                   NULL
                  );

      return FALSE;
   }

   return TRUE;
}

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

   DoMethod(Data->LV_MLNames, MUIM_List_Remove, MUIV_List_Remove_Selected);
   Data->Changed = TRUE;

   return 0;
}

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

   if (xget(Data->LV_MLNames, MUIA_List_Active) == MUIV_List_Active_Off)
   {
      DoMethod(obj, MUIM_MultiSet, MUIA_Disabled, TRUE,
               Data->BT_Edit, Data->BT_Clone, Data->BT_Remove,
               Data->BT_All , Data->BT_None , NULL
              );
   }
   else
   {
      DoMethod(obj, MUIM_MultiSet, MUIA_Disabled, FALSE,
               Data->BT_Edit, Data->BT_Clone, Data->BT_Remove,
               Data->BT_All , Data->BT_None , NULL
              );
   }

   return 0;
}

METHOD MLList_Setup(Class *cl, Object *obj, struct MUIP_Setup *msg)
{
   struct MLList_Data *Data = INST_DATA(cl, obj);

   if (!(DoSuperMethodA(cl, obj, (Msg)msg)))
   {
      return FALSE;
   }

   set(_win(obj), MUIA_Window_DefaultObject, Data->LV_MLNames);

   return TRUE;
}

ULONG SAVEDS MLList_Dispatcher(REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) Msg msg)
{
   switch (msg->MethodID)
   {
      case OM_NEW: return MLList_New(cl, obj, (APTR)msg);
      case OM_SET: return MLList_Set(cl, obj, (APTR)msg);
      case OM_GET: return MLList_Get(cl, obj, (APTR)msg);
      case MUIM_MLList_Add  : return MLList_Add  (cl, obj, (APTR)msg);
      case MUIM_MLList_Clone: return MLList_Clone(cl, obj, (APTR)msg);
      case MUIM_MLList_Edit : return MLList_Edit (cl, obj, (APTR)msg);
      case MUIM_MLList_Load : return MLList_Load (cl, obj, (APTR)msg);
      case MUIM_MLList_Save : return MLList_Save (cl, obj, (APTR)msg);
      case MUIM_MLList_Remove : return MLList_Remove (cl, obj, (APTR)msg);
      case MUIM_MLList_BTState: return MLList_BTState(cl, obj, (APTR)msg);
      case MUIM_Setup         : return MLList_Setup  (cl, obj, (APTR)msg);
   }

   return DoSuperMethodA(cl, obj, msg);
}

struct MUI_CustomClass *CreateMLListClass()
{
   if (CL_Editwin = CreateEditwinClass())
   {
      struct MUI_CustomClass *CL_MLList;

      CL_MLList = MUI_CreateCustomClass(NULL,
                                        MUIC_Group, NULL,
                                        sizeof(struct MLList_Data),
                                        MLList_Dispatcher
                                       );
      if (CL_MLList)
      {
         return CL_MLList;
      }
   }

   DeleteMLListClass(NULL);
   return NULL;
}

void DeleteMLListClass(struct MUI_CustomClass *CL_MLList)
{
   if (CL_MLList)
   {
      MUI_DeleteCustomClass(CL_MLList);
   }

   if (CL_Editwin)
   {
      DeleteEditwinClass(CL_Editwin);
      CL_Editwin = NULL;
   }
}

