
#include "installergui_base.h"
#include "includes.h"
#include "installergui_data.h"

#include <string.h>

/********************************************************************
 *
 *  DESCRIPTION
 *
 *  - private for initialisation and cleanup code for the
 *    library; you may also declare library-global data here
 *    (note that libcode must be re-entrant!)
 *  - several support functions
 *
 */

/********************************************************************
 *
 *  STATIC
 *
 */

/********************************************************************
 *
 *  EXTERN
 *
 */

/********************************************************************
 *
 *  PUBLIC
 *
 */

struct Library *MUIMasterBase = NULL;

/********************************************************************
 *
 *  CODE
 *
 */

/********************************************************************/

// this helps to center the a text within a floattext object!
// (suggested by Jens Langner)
char *guistuff_CenterText(char *text)
{
  char *centtext;
  int i, numlf;

  for (i=0, numlf=0; text[i]; i++, numlf += (text[i]=='\n')?1:0);

  centtext = sav_AllocVec(strlen(text) + (numlf*4) + 1, MEMF_ANY|MEMF_CLEAR);
  if (!centtext) { return(text); }

  for(i=0; strlen(text) > 0; text += i)
  {
    char *poschr = strstr(text, "\n");

    i = 1 + strlen(text) - (poschr ? strlen(poschr) : 1);
    strcat(centtext, "\33c");
    strncat(centtext, text, i);
  }

  return(centtext);
}

/********************************************************************/

// create a radio-button
APTR guistuff_InitRadio(BOOL selected, BOOL disabled)
{
  #ifdef DEBUG
  DEBUG_MAKRO
  #endif

  return(ImageObject,
           MUIA_Image_Spec, 16,
           MUIA_InputMode, MUIV_InputMode_Immediate,
           MUIA_Selected, selected,
           MUIA_Disabled, disabled,
         End);
}

/********************************************************************/

// handle a gui event: return TRUE if the gui has to wait, FALSE otherwise
BOOL guistuff_HandleGUIEvent(APTR application, long event)
{
  #ifdef DEBUG
  DEBUG_MAKRO
  #endif

  {
    // set app->app_Quit to TRUE when quit, otherwise do "nothing"
    struct Application *app = application;

    switch (event)
    {
      // der proceed button
      case GUIEVENT_BACK:
      case GUIEVENT_PROCEED: { return (FALSE); }

      // abort button
      // (special handling in special cases: SWING mode: if set, then
      // the "cancel" button is quiet!)
      case GUIEVENT_ABORT:
      {
        if (app->app_SWING_Mode) { return (FALSE); }
      }

      // user wants to quit
      case GUIEVENT_QUIT:
      {
        // do not prompt the user within TRAP handling
        if (app->app_TRAP_Mode) { return (FALSE); }

        //
        else if (igui_Request(app, NULL, app->app_Texts[YES_NO], app->app_Texts[REALLY_QUIT], NULL))
        {
          // if we are in SWING mode, we have to reset the SWING mode first
          igui_SWING_Mode(app, FALSE);

          app->app_Quit = TRUE;
          return (FALSE);
        }
      }
    }

    // ansonsten weiter warten!
    return (TRUE);
  }
}

/********************************************************************/

// change tho panels of the installer gui
BOOL guistuff_NewContent(APTR application, APTR newobject)
{
  #ifdef DEBUG
  DEBUG_MAKRO
  #endif

  {
    struct Application *app = (struct Application *) application;

    if (!newobject)
    {
      app->app_Error = GUIERROR_NO_GUI_OBJECT;
      return(FALSE);
    }

    if(DoMethod(app->app_MainRoot, MUIM_Group_InitChange))
    {
      // remove old object. Add new one.
      DoMethod(app->app_MainRoot, OM_REMMEMBER, app->app_CurrentObject);
      DoMethod(app->app_MainRoot, OM_ADDMEMBER, newobject);

      // dispose old object
      DisposeObject(app->app_CurrentObject);

      // new object gets the current one
      app->app_CurrentObject = newobject;

      // let the group relayout itself.
      DoMethod(app->app_MainRoot, MUIM_Group_ExitChange);
    }
    return(TRUE);
  }
}

/********************************************************************/

APTR guistuff_InitSimpleText(char *text)
{
  #ifdef DEBUG
  DEBUG_MAKRO
  #endif

  return(ListviewObject,
           MUIA_Listview_Input, FALSE,
           //MUIA_List_Format, "P=\33c",
           MUIA_Listview_List, FloattextObject,
             MUIA_Frame, MUIV_Frame_None,
             MUIA_Floattext_Text, guistuff_CenterText(text),
             MUIA_Background, MUII_TextBack,
             //MUIA_Font, MUIV_Font_Fixed,
           End,
         End);
}

/********************************************************************/

// mx implementation for two mx buttons
void __asm __saveds guistuff_MXTwoFun(register __a1 APTR *data)
{
  set((APTR) data[0], MUIA_Selected, TRUE);
  set((APTR) data[0], MUIA_Pressed, FALSE);
  set((APTR) data[1], MUIA_Selected, FALSE);
}

/********************************************************************/

// mx implementation for three mx buttons
void __asm __saveds guistuff_MXThreeFun(register __a1 APTR *data)
{
  set((APTR) data[0], MUIA_Selected, TRUE);
  set((APTR) data[0], MUIA_Pressed, FALSE);
  set((APTR) data[1], MUIA_Selected, FALSE);
  set((APTR) data[2], MUIA_Selected, FALSE);
}

/********************************************************************/

// peek anything to anywhere :)
void __asm guistuff_SetValFun(register __a1 APTR *data)
{
  *((APTR *) data[0]) = (APTR) data[1];
}

/********************************************************************/

// just refresh the gui
void guistuff_Refresh(APTR application)
{
  #ifdef DEBUG
  DEBUG_MAKRO
  #endif

  DoMethod(((struct Application *) application)->app_Application, MUIM_Application_InputBuffered);
}

/********************************************************************/

// build a new path
char *guistuff_BuildPath(char *path, char *file)
{
  long newpathlen = strlen(path) + strlen(file) + 5;
  char *newpath;

  if (newpath = sav_AllocVec(newpathlen, MEMF_ANY))
  {
    strcpy(newpath, path);
    if (DOSFALSE == AddPart(newpath, file, newpathlen)) { sav_FreeVec(newpath); newpath = NULL; }
  }

  return(newpath);
}

/********************************************************************/

static void __asm __saveds gui_BTMKDirOpenFun(register __a2 APTR, register __a1 APTR *);
static void __asm __saveds gui_BTMKDirDrivesFun(register __a2 APTR, register __a1 APTR *);
static void __asm __saveds gui_BTParentFun(register __a2 APTR, register __a1 APTR *);
static void __asm __saveds gui_LVDirlistSelectFun(register __a2 APTR, register __a1 APTR *);
static void __asm __saveds gui_LVDriveslistSelectFun(register __a2 APTR, register __a1 APTR *);
static void __asm __saveds gui_STNewDirFun(register __a2 APTR, register __a1 APTR *);

static const struct Hook gui_bt_parent_hook = { { NULL, NULL }, (VOID *) gui_BTParentFun, NULL, NULL };
static const struct Hook gui_lv_dirlistselect_hook = { { NULL, NULL }, (VOID *) gui_LVDirlistSelectFun, NULL, NULL };
static const struct Hook gui_lv_driveslistselect_hook = { { NULL, NULL }, (VOID *) gui_LVDriveslistSelectFun, NULL, NULL };
static const struct Hook gui_bt_mkdiropen_hook = { { NULL, NULL }, (VOID *) gui_BTMKDirOpenFun, NULL, NULL };
static const struct Hook gui_bt_mkdirdrives_hook = { { NULL, NULL }, (VOID *) gui_BTMKDirDrivesFun, NULL, NULL };
static const struct Hook gui_st_newdir_hook = { { NULL, NULL }, (VOID *) gui_STNewDirFun, NULL, NULL };

// since ASKFILE and ASKDIR do nearly the same, we can put them together into
// only one function
char *guistuff_AskFile_AskDir(APTR application, struct FunctionEnvironment *localenv, BOOL askdir)
{
  #ifdef DEBUG
  DEBUG_MAKRO
  #endif

  {
    struct Application *app = (struct Application *) application;

    char *path, *newpath,
         *file;

    char file_cpy[128], dir_cpy[256];

    // error or default: return the empty string ""
    char *retval = app->app_Texts[EMPTY];

    APTR ASKDIR_ST_Path, ASKDIR_ST_File, ASKDIR_LV_Dirlist;

    APTR BT_parent, BT_drives, BT_mkdir,
         LV_DrivesLV, LV_DirLV, LV_Driveslist,
         GR_buttons,
         obj;

    // extract path and file for better handling with mui
    strncpy((char *) &dir_cpy, (char *) localenv->fe_Default, 255);
    if (askdir) { file_cpy[0] = 0; }
    else
    {
      sav_PutChar(PathPart((STRPTR) &dir_cpy), 0L);
      strncpy((char *) &file_cpy, (char *) FilePart((char *) localenv->fe_Default), 128);
    }

    // create the gui object
    obj = GroupObject,
            Child, TextObject,
              MUIA_Frame, MUIV_Frame_None,
              MUIA_Text_Contents, localenv->fe_Prompt,
              MUIA_Text_SetMin, TRUE,
              MUIA_Text_PreParse, "\33c",
            End,
            Child, LV_DirLV = ListviewObject,
              MUIA_Listview_List, app->app_MkdirRelatedDirlist = ASKDIR_LV_Dirlist = DirlistObject,
                MUIA_Dirlist_DrawersOnly, askdir,
                MUIA_Dirlist_Directory, &dir_cpy,
              End,
              MUIA_Background, MUII_ListBack,
              MUIA_Frame, MUIV_Frame_InputList,
              MUIA_ShowMe, !localenv->fe_Disk,
            End,
            Child, LV_DrivesLV = ListviewObject,
              MUIA_Background, MUII_ListBack,
              MUIA_Frame, MUIV_Frame_InputList,
              MUIA_Listview_List, LV_Driveslist = VolumelistObject,
                //
              End,
              MUIA_ShowMe, localenv->fe_Disk,
            End,
            Child, ASKDIR_ST_Path = StringObject,
              MUIA_Frame, MUIV_Frame_String,
              MUIA_String_Format, MUIV_String_Format_Center,
              MUIA_String_Contents, &dir_cpy,
              MUIA_String_MaxLen, 128,
              MUIA_ShowMe, !localenv->fe_Disk,
            End,
            Child, ASKDIR_ST_File = StringObject,
              MUIA_Frame, MUIV_Frame_String,
              MUIA_String_Format, MUIV_String_Format_Center,
              MUIA_String_Contents, &file_cpy,
              MUIA_String_MaxLen, 128,
              MUIA_ShowMe, !askdir,
            End,
            Child, GR_buttons = GroupObject,
              MUIA_Group_Horiz, TRUE,
              Child, BT_parent = SimpleButton(app->app_Texts[BUTTON_PARENT]),
              Child, BT_drives = SimpleButton(app->app_Texts[BUTTON_DRIVES]),
              Child, BT_mkdir = SimpleButton(app->app_Texts[BUTTON_MKDIR]),
            End,
          End;

    if (obj)
    {
      // join the string gadget and the listview, so they notify each other
      DoMethod(ASKDIR_ST_Path, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
               ASKDIR_LV_Dirlist, 3, MUIM_Set, MUIA_Dirlist_Directory, MUIV_TriggerValue);
      DoMethod(ASKDIR_LV_Dirlist, MUIM_Notify, MUIA_Dirlist_Directory, MUIV_EveryTime,
               ASKDIR_ST_Path, 3, MUIM_Set, MUIA_String_Contents, MUIV_TriggerValue);

      // the active lv-entry changed
      DoMethod(ASKDIR_LV_Dirlist, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
               MUIV_Notify_Self, 5, MUIM_CallHook, &gui_lv_dirlistselect_hook,
               ASKDIR_ST_Path, ASKDIR_ST_File, ASKDIR_LV_Dirlist);

      // the user entered a new directory, so we have to update the listview
      DoMethod(ASKDIR_ST_Path, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
               MUIV_Notify_Self, 5, MUIM_CallHook, &gui_st_newdir_hook, ASKDIR_ST_Path, ASKDIR_ST_File, ASKDIR_LV_Dirlist);

      // the user selected a new volume from the volumes list
      DoMethod(LV_Driveslist, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
               MUIV_Notify_Self, 10, MUIM_CallHook, &gui_lv_driveslistselect_hook,
               obj, LV_DrivesLV, LV_DirLV, ASKDIR_ST_Path, ASKDIR_ST_File, GR_buttons, ASKDIR_LV_Dirlist, askdir);

      // we have to create a new directory; note, that we created the "makedir" stuff at the beginning
      DoMethod(BT_mkdir, MUIM_Notify, MUIA_Pressed, FALSE,
               MUIV_Notify_Self, 4, MUIM_CallHook, &gui_bt_mkdiropen_hook, ASKDIR_ST_Path, app);

      //
      DoMethod(BT_drives, MUIM_Notify, MUIA_Pressed, FALSE,
               MUIV_Notify_Self, 8, MUIM_CallHook, &gui_bt_mkdirdrives_hook, obj, LV_DrivesLV, LV_DirLV, ASKDIR_ST_Path, ASKDIR_ST_File, GR_buttons);

      // move to parent dir, if one presses "Parent"
      DoMethod(BT_parent, MUIM_Notify, MUIA_Pressed, FALSE,
               MUIV_Notify_Self, 5, MUIM_CallHook, &gui_bt_parent_hook, ASKDIR_ST_Path, ASKDIR_ST_File, ASKDIR_LV_Dirlist);

      //
      if (guistuff_NewContent(app, obj))
      {
        //
        igui_WaitApp(app);
        if (!igui_QuitApp(app))
        {
          // an now get a copy of the selected file-name or just the path-name
          GetAttr(MUIA_String_Contents, ASKDIR_ST_Path, (ULONG *) &path);
          GetAttr(MUIA_String_Contents, ASKDIR_ST_File, (ULONG *) &file);

          //
          if (askdir)
          {
            newpath = sav_DupString2(path);
            if (newpath) { retval = newpath; }
            else         { /* OUT OF MEMORY */ }
          }

          //
          else
          {
            retval = guistuff_BuildPath(path, file);
            if (!retval) { /* OUT OF MEMORY */ retval = app->app_Texts[EMPTY]; }
          }
        }
        else { /* user wants to quit */ }
      }
      else { /* NO GUI OBJECT */ }
    }
    else { /* NO GUI OBJECT */ }

    //
    igui_EmptyPanel(app);
    return(retval);
  }
}

static void __asm __saveds gui_BTParentFun(register __a2 APTR obj, register __a1 APTR *data)
{
  // move to the parent directory

  // data[0] - string gadget "Directory"
  // data[1] - string gadget "File"
  // data[2] - Dirlist object

  BPTR lock, parent;

  char *str,
       path[128];

  GetAttr(MUIA_String_Contents, (APTR) data[0], (ULONG *) &str);
  if (lock = Lock(str, SHARED_LOCK))
  {
    if (parent = ParentDir(lock))
    {
      if (DOSFALSE != NameFromLock(parent, (char *) &path, 127))
      {
        SetAttrs(data[1], MUIA_String_Contents, NULL, TAG_DONE);
        SetAttrs(data[2], MUIA_Dirlist_Directory, &path, TAG_DONE);
      }
      else { /* path[128] may be too short */ DisplayBeep(NULL); }

      UnLock(parent);
    }
    else { /* unable to move to parent */ DisplayBeep(NULL); }

    UnLock(lock);
  }
  else { /* no lock */ DisplayBeep(NULL); }
}

static void __asm __saveds gui_LVDirlistSelectFun(register __a2 APTR obj, register __a1 APTR *data)
{
  // the active item of the dirlist changed; if the new ective one is
  // a file, then copy the name to the string gadget, otherweise
  // selected item is a dir) change to the new directory

  // data[0] - string gadget "Directory"
  // data[1] - string gadget "File"
  // data[2] - Dirlist object

  long active, path;
  struct FileInfoBlock *fib;
  char str_copy[256];

  GetAttr(MUIA_List_Active, obj, (ULONG *) &active);
  if (active >= 0)
  {
    DoMethod(obj, MUIM_List_GetEntry, active, &fib);

    // selected item is a directory
    if (fib->fib_DirEntryType > 0)
    {
      GetAttr(MUIA_String_Contents, data[0], (ULONG *) &path);

      strncpy((char *) &str_copy, (char *) path, 255);
      AddPart((STRPTR) &str_copy, (STRPTR) &(fib->fib_FileName), 255);

      SetAttrs(data[1], MUIA_String_Contents, NULL, TAG_DONE);
      SetAttrs(data[2], MUIA_Dirlist_Directory, &str_copy, TAG_DONE);
    }

    // the selected item is a file
    else if (fib->fib_DirEntryType < 0)
    {
      SetAttrs(data[1], MUIA_String_Contents, &(fib->fib_FileName), TAG_DONE);
    }
  }
}

static void __asm __saveds gui_LVDriveslistSelectFun(register __a2 APTR obj, register __a1 APTR *data)
{
  // the user selected an entry from the drives list -> move to the
  // new directory

  // data[0] - ASKFILE/ASKDIR's root object
  // data[1] - listview for the Volumelist
  // data[2] - listview for the Dirlist
  // data[3] - string gadget "Directory"
  // data[4] - string gadget "File"
  // data[5] - the 3 buttons
  // data[6] - Dirlist object itself
  // data[7] - the flag, if this is called by ASKDIR or ASKFILE

  long active;
  char *path;

  GetAttr(MUIA_List_Active, obj, (ULONG *) &active);
  if (active >= 0)
  {
    DoMethod(obj, MUIM_List_GetEntry, active, &path);
    if (DoMethod((APTR) data[0], MUIM_Group_InitChange))
    {
      set((APTR) data[5], MUIA_ShowMe, TRUE);
      set((APTR) data[4], MUIA_ShowMe, !data[7]);
      set((APTR) data[3], MUIA_ShowMe, TRUE);
      set((APTR) data[2], MUIA_ShowMe, TRUE);
      set((APTR) data[1], MUIA_ShowMe, FALSE);
      DoMethod((APTR) data[0], MUIM_Group_ExitChange);
    }
    SetAttrs(data[4], MUIA_String_Contents, NULL, TAG_DONE);
    SetAttrs(data[6], MUIA_Dirlist_Directory, path, TAG_DONE);
  }
}

static void __asm __saveds gui_BTMKDirOpenFun(register __a2 APTR obj, register __a1 APTR *data)
{
  // open the "MakeDir" window

  // data[0] - string gadget "Directory"
  // data[1] - pointer to the Application structure

  struct Application *app = (struct Application *) data[1];
  long path;

  GetAttr(MUIA_String_Contents, (APTR) data[0], (ULONG *) &path);

  set(app->app_MkdirName, MUIA_String_Contents, path);
  set(app->app_MkdirWindow, MUIA_Window_Open, TRUE);
  set(app->app_MainWindow, MUIA_Window_Sleep, TRUE);
}

static void __asm __saveds gui_BTMKDirDrivesFun(register __a2 APTR obj, register __a1 APTR *data)
{
  // change the gui to the Volumelist, thus, we have to show some
  // objects and "un-show" some others!

  if (DoMethod((APTR) data[0], MUIM_Group_InitChange))
  {
    set((APTR) data[5], MUIA_ShowMe, FALSE);
    set((APTR) data[4], MUIA_ShowMe, FALSE);
    set((APTR) data[3], MUIA_ShowMe, FALSE);
    set((APTR) data[2], MUIA_ShowMe, FALSE);
    set((APTR) data[1], MUIA_ShowMe, TRUE);
    DoMethod((APTR) data[0], MUIM_Group_ExitChange);
  }
}

static void __asm __saveds gui_STNewDirFun(register __a2 APTR obj, register __a1 APTR *data)
{
  // the user entered a new path into the string gadget ->
  // check if this path is valid (if not, use "SYS:") and set
  // the new path to the listview

  // data[0] - string gadget "Directory"
  // data[1] - string gadget "File"
  // data[2] - dirlist gadget

  char *newpath;
  GetAttr(MUIA_String_Contents, (APTR) data[0], (ULONG *) &newpath);

  // if the entered path does not exist, use SYS: instead
  if (!sav_DirExists(newpath)) { newpath = "SYS:"; SetAttrs((APTR) data[0], MUIA_String_Contents, newpath, TAG_DONE); }

  SetAttrs((APTR) data[1], MUIA_String_Contents, NULL, TAG_DONE);
  SetAttrs((APTR) data[2], MUIA_Dirlist_Directory, newpath, TAG_DONE);
}

