/*
 *  Copyright 1994-2022 Olivier Girondel
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou 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.
 *
 *  lebiniou 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 lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#include <inttypes.h>
#include "images.h"
#include "brandom.h"
#include "settings.h"


static int
Images_compare(const void *_a, const void *_b)
{
  Image8_t **a = (Image8_t **)_a;
  Image8_t **b = (Image8_t **)_b;

  assert(NULL != *a);
  assert(NULL != *b);
  assert(NULL != (*a)->dname);
  assert(NULL != (*b)->dname);

  return strcasecmp((*a)->dname, (*b)->dname);
}


void
Images_new(const char *basedir, const char *themes)
{
  DIR *dir;
  struct dirent *entry;
  GSList *tmp = NULL;
  uint16_t size = 0;
  GSList *t;

  assert(NULL != basedir);
  json_t *themes_j = NULL;
  if (NULL != themes) {
    themes_j = json_strtok(themes, ",");
  } else {
    themes_j = Settings_get_themes();
  }

  size_t index;
  json_t *value;

  json_array_foreach(themes_j, index, value) {
    gchar *directoryname;
    const char *th = json_string_value(value);

    VERBOSE(printf("[+] Loading theme '%s'\n", th));
    fflush(stdout);
    if (*th == '~') {
      th++;
      if (*th != '\0') {
        directoryname = g_strdup_printf("%s/." PACKAGE_NAME "/images/%s", g_get_home_dir(), th);
      } else {
        fprintf(stderr, "[!] Not a valid tilde-theme: %s\n", th);
        continue;
      }
    } else {
      directoryname = g_strdup_printf("%s/%s", basedir, th);
    }

    dir = opendir(directoryname);
    if (NULL == dir) {
      fprintf(stderr, "[!] Error while reading image directory %s content: %s\n",
              directoryname, strerror(errno));
      g_free(directoryname);
      continue;
    }

    while (NULL != (entry = readdir(dir))) {
      uint32_t hash;
      Image8_t *pic;

      if (entry->d_name[0] == '.') {
        continue;
      }

      hash = FNV_hash(entry->d_name);

      char ignore = 0;
      for (t = g_slist_next(tmp); NULL != t; t = g_slist_next(t))
        if (((Image8_t *)t->data)->id == hash) {
          const char *name = ((Image8_t *)t->data)->name;

          if (!is_equal(name, entry->d_name))
            printf("[!] Ignoring image '%s'\n"
                   "[!]   (same hash as '%s': %"PRIu32")\n",
                   entry->d_name, name, hash);
          ignore = 1;
        }

      if (!ignore) {
        pic = Image8_new();

        if (Image8_load(pic, hash, directoryname,
                        entry->d_name) != 0) {
          Image8_delete(pic);
        } else {
          size++;
          tmp = g_slist_prepend(tmp, (gpointer)pic);
        }
      }
    }

    if (closedir(dir) == -1) {
      xperror("closedir");
    }
    g_free(directoryname);
  }
  json_decref(themes_j);

  images = xmalloc(sizeof(Images_t));
  if (libbiniou_verbose) {
    VERBOSE(printf("[p] Loaded %d images\n", size));
  }

  if (size) {
    uint16_t i;

    images->imgs = xmalloc(size * sizeof(Image8_t *));
    for (i = 0, t = tmp; NULL != t; t = g_slist_next(t), i++) {
      images->imgs[i] = (Image8_t *)t->data;
    }
    g_slist_free(tmp);
    images->size = size;

    qsort((void *)images->imgs, (size_t)images->size,
          (size_t)sizeof(Image8_t *), &Images_compare);
  } else {
    xfree(images);
  }
}


void
Images_delete(void)
{
  if (NULL != images) {
    uint16_t i;

    for (i = 0; i < images->size; i++) {
      Image8_delete(images->imgs[i]);
    }
    xfree(images->imgs);
    xfree(images);
  }
}


uint16_t
Images_name_to_index(const char *name)
{
  assert(NULL != images);
  for (uint16_t i = 0; i < images->size; i++)
    if (is_equal(images->imgs[i]->name, name)) {
      return i;
    }

  VERBOSE(fprintf(stderr, "[!] Image '%s' not found\n", name));

  return 0; /* Return the default image */
}
