/* iconsel.c
 * Copyright (C) 2002-2004 Pascal Eberhard <pascal.ebo@netcourrier.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */


#include "common.h"
#include <dirent.h>
#include <string.h>
#include <errno.h>

#include "iconsel_private.h"

#define _GNU_SOURCE 1
#include <fnmatch.h>

//#ifndef FNM_CASEFOLD            // case insensitive but is not defined... ?
//#define FNM_CASEFOLD  (1 << 4)
//#endif

// ----------------------------------------------------------------------------
icon_dir_t *icon_dir_new(gchar *path, gboolean selected, gboolean recursive)
{
  icon_dir_t *icon_dir;
  g_assert(path != NULL);
  icon_dir = (icon_dir_t *) malloc(sizeof(icon_dir_t));
  g_assert(icon_dir != NULL);
  icon_dir->path = path;
  icon_dir->selected = selected;
  icon_dir->recursive = recursive;
  return icon_dir;
}
// ----------------------------------------------------------------------------
void icon_dir_free(icon_dir_t *icon_dir)
{
  g_assert(icon_dir != NULL);
  if (icon_dir->path)
    g_free(icon_dir->path);
  g_free(icon_dir);
}
// ----------------------------------------------------------------------------
gint icon_dir_compare(icon_dir_t *a, icon_dir_t *b)
{
  g_assert(a != NULL && b != NULL);
  return strcmp(a->path, b->path);
}
// ----------------------------------------------------------------------------
void icon_dir_list_append(GList **list, icon_dir_t *dir)
{
  g_assert(list != NULL && dir != NULL);
  *list = g_list_insert_sorted(*list, dir, (GCompareFunc) icon_dir_compare);
}
// ----------------------------------------------------------------------------
icon_dir_t * icon_dir_list_find(GList *list, char *olddir)
{
  GList *hamster;
  icon_dir_t *dir;
  g_assert(olddir != NULL);
  hamster = g_list_first(list);
  while(hamster != NULL)
  {
    dir = hamster->data;
    if (strcmp(dir->path, olddir) == 0)
      break;
    hamster = g_list_next(hamster);
  }
  if (hamster == NULL)
    return NULL;
  else
    return dir;
}
// ----------------------------------------------------------------------------
void icon_dir_list_remove(GList **list, char *olddir)
{
  GList *hamster;
  icon_dir_t *dir;
  g_assert(list != NULL && olddir != NULL);
  hamster = g_list_first(*list);
  while(hamster != NULL)
  {
    dir = hamster->data;
    if (strcmp(dir->path, olddir) == 0)
      break;
    hamster = g_list_next(hamster);
  }
  if (hamster == NULL)
    ERR("icon_dir_list_remove() olddir:%s not found", olddir);

  *list = g_list_remove(*list, dir);
  icon_dir_free(dir);
}
// ----------------------------------------------------------------------------
void icon_dir_list_modify(GList **list, char *olddir, char *newdir)
{
  GList *hamster;
  icon_dir_t *dir;
  g_assert(list != NULL && olddir != NULL && newdir != NULL);
  hamster = g_list_first(*list);
  while(hamster != NULL)
  {
    dir = hamster->data;
    if (strcmp(dir->path, newdir) == 0)
      break;
    hamster = g_list_next(hamster);
  }
  if (hamster != NULL)
  {
      WARN("icon_dir_list_modify() olddir:%s, newdir:%s, "
                "newdir already exist", olddir, newdir);
      return;
   }

  hamster = g_list_first(*list);
  while(hamster != NULL)
  {
    dir = hamster->data;
    if (strcmp(dir->path, olddir) == 0)
      break;
    hamster = g_list_next(hamster);
  }
  if (hamster == NULL)
    ERR("icon_dir_list_modify() olddir:%s not found", olddir);
  g_free(dir->path);
  dir->path = g_strdup(newdir);
  *list = g_list_sort(*list, (GCompareFunc) icon_dir_compare);
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
file_ext_t *file_ext_new(gchar *extension, gboolean selected)
{
  file_ext_t *file_ext;
  g_assert(extension != NULL);
  file_ext = (file_ext_t *) malloc(sizeof(file_ext_t));
  g_assert(file_ext != NULL);
  file_ext->extension = extension;
  file_ext->selected = selected;
  return file_ext;
}
// ----------------------------------------------------------------------------
void file_ext_free(file_ext_t *file_ext)
{
  if (file_ext->extension)
    g_free(file_ext->extension);
  g_free(file_ext);
}
// ----------------------------------------------------------------------------
gint file_ext_compare(file_ext_t *a, file_ext_t *b)
{
  g_assert(a != NULL && b != NULL);
  return strcmp(a->extension, b->extension);
}
// ----------------------------------------------------------------------------
void file_ext_list_append(GList **list, file_ext_t *ext)
{
  g_assert(list != NULL && ext != NULL);
  *list = g_list_insert_sorted(*list, ext, (GCompareFunc) file_ext_compare);
}
// ----------------------------------------------------------------------------
file_ext_t * file_ext_list_find(GList *list, char *oldext)
{
  GList *hamster;
  file_ext_t *ext;
  g_assert(oldext != NULL);
  hamster = g_list_first(list);
  while(hamster != NULL)
  {
    ext = hamster->data;
    if (strcmp(ext->extension, oldext) == 0)
      break;
    hamster = g_list_next(hamster);
  }
  if (hamster == NULL)
    return NULL;
  else
    return ext;
}
// ----------------------------------------------------------------------------
void file_ext_list_remove(GList **list, char *oldext)
{
  GList *hamster;
  file_ext_t *ext;
  g_assert(list != NULL && oldext != NULL);
  hamster = g_list_first(*list);
  while(hamster != NULL)
  {
    ext = hamster->data;
    if (strcmp(ext->extension, oldext) == 0)
      break;
    hamster = g_list_next(hamster);
  }
  if (hamster == NULL)
    ERR("file_ext_list_remove() oldext:%s not found", oldext);

  *list = g_list_remove(*list, ext);
  file_ext_free(ext);
}
// ----------------------------------------------------------------------------
void file_ext_list_modify(GList **list, char *oldext, char *newext)
{
  GList *hamster;
  file_ext_t *ext;
  g_assert(list != NULL && oldext != NULL && newext != NULL);
  hamster = g_list_first(*list);
  while(hamster != NULL)
  {
    ext = hamster->data;
    if (strcmp(ext->extension, newext) == 0)
      break;
    hamster = g_list_next(hamster);
  }
  if (hamster != NULL)
  {
    WARN("file_ext_list_modify() oldext:%s, newext:%s, "
              "newext already exist", oldext, newext);
    return;
  }
  hamster = g_list_first(*list);
  while(hamster != NULL)
  {
    ext = hamster->data;
    if (strcmp(ext->extension, oldext) == 0)
      break;
    hamster = g_list_next(hamster);
  }
  if (hamster == NULL)
    ERR("file_ext_list_modify() oldext:%s not found", oldext);
  g_free(ext->extension);
  ext->extension = g_strdup(newext);
  *list = g_list_sort(*list, (GCompareFunc) file_ext_compare);
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
iconsel_pref_t * iconsel_pref_new(GList *icon_dirs, GList *file_exts,
                                  gboolean eq48, gboolean lt48,
                                  gboolean gt48, gint sort)
{
  iconsel_pref_t *ispref;
  TRACE("%s", "");
  ispref = (iconsel_pref_t *) malloc(sizeof(iconsel_pref_t));
  g_assert(ispref != NULL);
  ispref->icon_dirs = icon_dirs;
  ispref->file_exts = file_exts;
  ispref->select_48 = eq48;
  ispref->select_lt48 = lt48;
  ispref->select_gt48 = gt48;
  if (sort < 0 || sort > ICONSEL_SORT_LAST)
  {
    WARN("sort_mode:%d invalid, set to default:%d",
              sort, ICONSEL_SORT_DEFAULT);
    sort = ICONSEL_SORT_DEFAULT;
  }
  ispref->sort_mode = sort;
  return ispref;
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
icon_selection_t* icon_selection_new(struct apwalapp_t *apwal)
{
  icon_selection_t *iconsel;

  g_assert(apwal != NULL);
  TRACE("%s", "");

  iconsel = (icon_selection_t *) malloc(sizeof(icon_selection_t));
  g_assert(iconsel != NULL);

  iconsel->apwal = apwal;
  iconsel->filter = g_strdup("*");

  iconsel->image = NULL;

  iconsel->dblclick_timer = NULL;
  iconsel->dblclick_selected_timer = NULL;

  iconsel->never_refreshed = TRUE;
  
  iconsel->icons = icon_list_new(iconsel);
  iconsel_build_interface(iconsel);
  return iconsel;
}

// ----------------------------------------------------------------------------
void icon_selection_load_icons_with_splash(icon_selection_t *iconsel)
{
  GList      *hamster;
  icon_dir_t *icon_dir;
  g_assert(iconsel != NULL);
  splash_show(iconsel->apwal->splash);
  hamster = iconsel->apwal->iconsel_pref->icon_dirs;
  while(hamster != NULL)
  {
    splash_update(iconsel->apwal->splash);
    icon_dir = hamster->data;
    icon_list_append(iconsel->icons, icon_dir->path,
                     icon_dir->selected, icon_dir->recursive);
    hamster = g_list_next(hamster);
  }
  splash_hide(iconsel->apwal->splash);
  iconsel_path_refresh(iconsel);
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// usage: icon_list_select(iconsel->icons, iconsel_select_func, iconsel);
gboolean iconsel_select_func(ico_t *ico, void *data)
{
  gboolean selected;
  int      cc;
  icon_selection_t *iconsel = (icon_selection_t *) data;
  g_assert(ico != NULL && iconsel != NULL);

  selected = TRUE;
  while (1)     // begin of a 'block' which can be aborted by a break
  {
 #if 0
  GList      *ext_hamster;
  file_ext_t *ext;
    // check if the size is selected
    if ((iconsel->ispref->select_48 == TRUE) &&
        (ico->width == 48) && (ico->height == 48))
      selected = TRUE;
    else if ((iconsel->ispref->select_gt48 == TRUE) &&
             ((ico->width > 48) || (ico->height > 48)))
      selected = TRUE;
    else if ((iconsel->ispref->select_lt48 == TRUE) &&
             ((ico->width < 48) || (ico->height < 48)))
      selected = TRUE;
    else
    {
      selected = FALSE;
      break;
    }

    // check if the name is matching one of the patterns
    // if name matches pattern then go out the loop with cc=0
    // if name don't match any pattern then cc!=0 at the end of the loop
    // after the loop, if cc!=0 then don't select the name and return 0
    ext_hamster = g_list_first(iconsel->ispref->file_exts);
    while(ext_hamster != NULL)
    {
      ext = ext_hamster->data;
      if (ext->selected == TRUE)
      {
        cc = fnmatch(ext->extension, ico->name, FNM_CASEFOLD);
        //TRACE("ext:%s, name:%s, cc:%d", ext->extension, ico->name, cc);
        if (cc == 0)        // success
          break;

        if ((cc != 0) && (cc != FNM_NOMATCH))      // error during match
          WARN("fnmatch, ext:%s, name:%s, E:%d", 
                    ext->extension, ico->name, cc);
      }
      ext_hamster = g_list_next(ext_hamster);
    } //end while ext
    if (cc != 0 || ext_hamster == NULL)      // not match
    {
      selected = FALSE;
      break;
    }
 #endif 

    // check if the name match the filter
    cc = fnmatch(iconsel->filter, ico->name, FNM_CASEFOLD);
    if (cc != 0)
    {
      selected = FALSE;
      if (cc != FNM_NOMATCH)
        WARN("fnmatch filter:%s, name:%s, E:%d",
             iconsel->filter, ico->name, cc);
      break;
    }
    break; // end of the 'block'
  } // end of the 'block'
  return selected;
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void iconsel_set_filename(icon_selection_t *iconsel, const char *filename)
{
  g_assert(iconsel != NULL);
  TRACE("%s", "");
  icon_list_set_selected_icon_from_filename(iconsel->icons, filename);
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
char *iconsel_get_filename(icon_selection_t *iconsel)
{
  g_assert(iconsel != NULL);
  TRACE("%s", "");
  return icon_list_get_selected_icon_filename(iconsel->icons);
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
