/************************************************************
**
** Application: SyncDiscs
**
** Title:       c.dirlist
**
*************************************************************/

/*
*
* Copyright (c) 2017, David Pilling and Chris Johnson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the copyright holder nor the names of their
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

/* Include files */
/* from standard clib */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/* From TaskLib */
#include "Tasklib:h.os"
#include "Tasklib:h.akbd"
#include "Tasklib:h.etc"
#include "Tasklib:h.mlo"
#include "Tasklib:h.mym"
#include "Tasklib:h.wimp"
#include "Tasklib:h.wimpt"
#include "Tasklib:h.wos"
#include "Tasklib:h.werr"
#include "Tasklib:h.flex"
#include "Tasklib:alloc.h"


/* from application */

#include "dbox.h"
#include "dirlist.h"


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

/* Local defines */

#define LIST_MAX_LENGTH 32
#define PATH_LENGTH 256


typedef struct dir_list
{
  int    iEntries;
  int    iPos[LIST_MAX_LENGTH];
  char   names[LIST_MAX_LENGTH][FSMAXWIMPMSGPATH];
} dir_list;

static char *leaf = "LastDirs";

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

/* exported variables */


/* global variables */

static dir_list dlist[NUMBER_OF_LISTS];

static int menulist;
static int *menudata;

/* forward function declarations */



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

static os_error * dirlistmenu_decode (int * menu)

{
  int iChoice;
  int iPrev;
  int j;
  int shift;

  iChoice = menu[0];
  if (iChoice >= 0)
  {
    /* Get state of SHIFT key */
    shift = akbd_pollsh();
    /* There has been a choice */
    /* Write the path into the appropriate field in the control dbox */
    dbox_insert_path (dlist[menulist].names[dlist[menulist].iPos[iChoice]], menulist, (BOOL)shift);

    /* Now reorder the master list to bring choice to top */
    /* If already at top of list, no need to do anything */
    if (iChoice != 0)
    {
      iPrev = dlist[menulist].iPos[iChoice];
      for ( j = iChoice; j >= 1; j--)
      {
        dlist[menulist].iPos[j] = dlist[menulist].iPos[j - 1];
      }
      dlist[menulist].iPos[0] = iPrev;
    }
  }

  return (NULL);
}


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

#define PRI_PATH "Primaries"
#define SEC_PATH "Secondaries"
#define SCRAP_PATH "Scrap dirs"

void dirlist_openmenu (int list)

{
  os_error * err;
  int i;


  err=NULL;

  menulist = list;


  if (dlist[list].iEntries > 0)
  {
    err = createusermenu (dirlistmenu_decode, NULL);
    if (!err)
    {
      for (i = 0; i < dlist[list].iEntries; i++)
      {
        err = addusermenu (dlist[list].names[dlist[list].iPos[i]], 0);
      }
      switch (menulist)
      {
        case PRIMARY_LIST:
          menudata = completeusermenu (PRI_PATH);
          break;
        case SECONDARY_LIST:
          menudata = completeusermenu (SEC_PATH);
          break;
        case SCRAP_LIST:
          menudata = completeusermenu (SCRAP_PATH);
          break;
      }
      openupmenu (usermenuindex);
    }
  }

  return;
}





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


void dirlist_save (void)

{
  os_error  *err;
  char   *spath;
  FILE       *handle;
  int i;
  int j;


  err = FLEXALLOC (spath, FSMAXWIMPMSGPATH);
  if (!err)
  {
    make_choices_path (CHSAVE, spath, leaf);
    handle = fopen (spath, "w");

    if (handle)
    {
      for (i = 0; i < NUMBER_OF_LISTS; i++)
      {
        fprintf(handle, "%d\n",dlist[i].iEntries);

        if (dlist[i].iEntries > 0)
        {
          for (j = 0; j < dlist[i].iEntries; j++)
          {
            fprintf(handle, "%s\n", dlist[i].names[dlist[i].iPos[j]]);
          }
        }

      }
      fclose (handle);
    }
  }
  FLEXFREE(spath);
  return;
}





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


static void dirlist_loadlist (FILE  *handle, char  **sIn, int list)

{
  int     i;
  int     iEntries;
  int     iLen;
  char *pTmp;

  fgets (*sIn, PATH_LENGTH, handle);
  iLen = strlen (*sIn);
  /* strlen will include the \n character */
  if (iLen < 2)
  {
    iEntries = 0;
  }
  else
  {
    pTmp = *sIn;
    pTmp[iLen-1] = 0;
    iEntries = atoi (*sIn);
    /* Need to check list is not longer than array size */
    iEntries = MIN (iEntries, LIST_MAX_LENGTH);
    if (iEntries > 0)
    {
      for (i = 0; i < iEntries; i++)
      {
        fgets (*sIn, PATH_LENGTH, handle);
        iLen = strlen (*sIn);
        pTmp = *sIn;
        pTmp[iLen-1] = 0;
        strcpy (dlist[list].names[i], *sIn);
        dlist[list].iPos[i] = i;
      }
    }
  }
  dlist[list].iEntries = iEntries;

  return;
}





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


void dirlist_load (void)

{
  os_error  *err;
  char   *spath;
  FILE   *handle;
  char   *sIn;


  err = FLEXALLOC(spath, FSMAXWIMPMSGPATH);
  if (!err)
  {
    make_choices_path (CHLOAD, spath, leaf);
    handle = fopen (spath, "r");

    if (handle)
    {
      err = FLEXALLOC(sIn, PATH_LENGTH);
      if (!err)
      {
        dirlist_loadlist (handle, &sIn, PRIMARY_LIST);
        dirlist_loadlist (handle, &sIn, SECONDARY_LIST);
        dirlist_loadlist (handle, &sIn, SCRAP_LIST);

        FLEXFREE(sIn);
      }

      fclose (handle);
    }
    FLEXFREE(spath);
  }
  return;
}





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


void dirlist_add_dir (char *name, int iListindex )

{
  int i;
  int j;
  int iPrev;


  if (iListindex > SCRAP_LIST) return;
  if (name[0] == 0x00) return;

  if (dlist[iListindex].iEntries == 0)
  {
    /* Simply add the dir to the beginning of the list */
    strcpy (dlist[iListindex].names[0], name);
    dlist[iListindex].iPos[0] = 0;
    dlist[iListindex].iEntries = 1;
    dbox_shade_menubuttons ( (dlist[PRIMARY_LIST].iEntries == 0),
                             (dlist[SECONDARY_LIST].iEntries == 0),
                             (dlist[SCRAP_LIST].iEntries == 0));
    return;
  }

  /* If we get here, there are already one or more dirs in the list */
  /* Check if already in list */
  i = 0;
  do
  {
    if (!strcmp (dlist[iListindex].names[dlist[iListindex].iPos[i]], name))
    {
      /* Names match - move it to the head of the list */
      /* i will be the index to the entry */
      if ( i == 0 )
      {
        /* already at head - nothing to do */
        return;
      }
      /* need to move up the indexes - from the top */
      iPrev = dlist[iListindex].iPos[i];
      for ( j = i; j >= 1; j--)
      {
        dlist[iListindex].iPos[j] = dlist[iListindex].iPos[j - 1];
      }
      dlist[iListindex].iPos[0] = iPrev;
      return;
    }
    else
    {
      i++;
    }

  } while (i < dlist[iListindex].iEntries);

  /* If we get here there is no match, so just add the name.
     We need to check whether the list is full - if it is, we need to
     drop the oldest entry in the list.
  */
  if (dlist[iListindex].iEntries == LIST_MAX_LENGTH)
  {
    /* Need to drop oldest entry */
    iPrev = dlist[iListindex].iPos[LIST_MAX_LENGTH - 1];
    for ( j = LIST_MAX_LENGTH - 1; j >= 1; j--)
    {
      dlist[iListindex].iPos[j] = dlist[iListindex].iPos[j - 1];
    }
    strcpy (dlist[iListindex].names[iPrev], name);
    dlist[iListindex].iPos[0] = iPrev;
  }
  else
  {
    /* Just add the entry */
    strcpy (dlist[iListindex].names[dlist[iListindex].iEntries], name);
    /* Need to move everything up */
    for (j = dlist[iListindex].iEntries; j > 0; j--)
    {
      dlist[iListindex].iPos[j] = dlist[iListindex].iPos[j - 1];

    }
    dlist[iListindex].iPos[0] = dlist[iListindex].iEntries;
    dlist[iListindex].iEntries++;
  }

  return;
}






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

/* Returns whether the dir lists contain at least 1 entry.
 * Used when setting up the main control window */

void dirlist_status ( BOOL *no_primary, BOOL *no_secondary, BOOL *no_scrap)

{
  *no_primary = (dlist[PRIMARY_LIST].iEntries == 0);
  *no_secondary = (dlist[SECONDARY_LIST].iEntries == 0);
  *no_scrap = (dlist[SCRAP_LIST].iEntries == 0);
  return;
}








/*************  End of c.dirlist  ***********************/






