/*
 *  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 "context.h"
#include "sequences.h"


void
Context_store_bank(Context_t *ctx, const uint8_t bank)
{
  assert(bank < MAX_BANKS);
  ctx->bank = bank;
  ctx->banks[ctx->bank_set][bank] = ctx->sm->cur->id;
}


void
Context_clear_bank(Context_t *ctx, const uint8_t bank)
{
  assert(bank < MAX_BANKS);
  ctx->banks[ctx->bank_set][bank] = 0;
}


void
Context_use_bank(Context_t *ctx, const uint8_t bank)
{
  assert(bank < MAX_BANKS);
  ctx->bank = bank;

  uint32_t id = ctx->banks[ctx->bank_set][bank];

  if (id) {
    GList *seq = Sequences_find(id);

    if (NULL != seq) {
      const Sequence_t *s = (const Sequence_t *)seq->data;

      VERBOSE(printf("[i] Using sequence in bank %d: %s\n", bank + 1, s->name));
      Sequence_copy(ctx, s, ctx->sm->next);
      Context_set(ctx);
    } else {
      VERBOSE(printf("[!] Sequence %d not found\n", id));
    }
  }
}


void
Context_save_banks(const Context_t *ctx)
{
  gchar *filename = NULL;
  json_t *banks = json_array();

  // create ~/.lebiniou directory (be safe if it doesn't exist)
  filename = g_strdup_printf("%s/." PACKAGE_NAME, g_get_home_dir());
  g_mkdir_with_parents(filename, DIRECTORY_MODE);
  g_free(filename);

  filename = g_strdup_printf("%s/." PACKAGE_NAME "/banks.json", g_get_home_dir());
  printf("[s] Banks filename: %s\n", filename);

  for (uint8_t bs = 0; bs < MAX_BANKS; bs++)
    for (uint8_t b = 0; b < MAX_BANKS; b++)
      if (ctx->banks[bs][b]) {
        json_array_append_new(banks, json_pack("{si si si}",
                                               "bankSet", bs,
                                               "bank", b,
                                               "sequence", ctx->banks[bs][b]));
      }

  json_dump_file(banks, filename, JSON_INDENT(4));
  json_decref(banks);
  g_free(filename);
}


/*
 * There will be some loss when migrating an XML banks file
 * to the new banks/shortcuts model:
 *
 *   - we can map all the bank sets/banks/sequences, but
 *   - only 10 shortcuts are available so we'll try to map
 *     as many colormaps/images found as possible to free slots
 */
enum BankMode { SEQUENCES = 0, COLORMAPS, IMAGES };


static void
Context_load_banks_json(Context_t *ctx, gchar *filename)
{
  json_t *j_banks = json_load_file(filename, 0, NULL);

  for (uint16_t b = 0; b < json_array_size(j_banks); b++) {
    json_t *j_bank_object = json_array_get(j_banks, b);
    json_t *j_bank_set = json_object_get(j_bank_object, "bankSet");
    json_t *j_bank = json_object_get(j_bank_object, "bank");
    json_t *sequence = json_object_get(j_bank_object, "sequence");

    uint8_t bank_set = json_integer_value(j_bank_set);
    uint8_t bank = json_integer_value(j_bank);

    if (NULL != sequence) {
      ctx->banks[bank_set][bank] = json_integer_value(sequence);
#ifdef DEBUG_BANKS
      printf("[b] Sequence %d-%d: %lld\n", bank_set, bank, json_integer_value(sequence));
#endif
    }
  }

  json_decref(j_banks);
}


void
Context_load_banks(Context_t *ctx)
{
  gchar *filename;
  int res;
  struct stat dummy;

  filename = g_strdup_printf("%s/." PACKAGE_NAME "/banks.json", g_get_home_dir());
  res = stat(filename, &dummy);

  if (!res) {
    Context_load_banks_json(ctx, filename);
  }
  g_free(filename);
}


json_t *
Context_get_bank_set(const Context_t *ctx, const uint8_t bs)
{
  json_t *res = NULL;

  if (bs < MAX_BANKS) {
    res = json_array();

    for (uint8_t i = 0; i < MAX_BANKS; i++) {
      char *name = NULL;
      uint32_t id = ctx->banks[bs][i];

      if (id) {
        GList *tmp = Sequences_find(id);

        if (NULL != tmp) {
          Sequence_t *seq = (Sequence_t *)tmp->data;

          name = seq->name;
          json_array_append_new(res, json_string(name));
        } else {
          json_array_append_new(res, json_null());
        }
      } else {
        json_array_append_new(res, json_null());
      }
    }
  }

  return res;
}
