/*
 *  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 "main.h"
#include "images.h"
#include "colormaps.h"
#include "settings.h"
#include "paths.h"


char *base_dir = NULL;
char *schemes_file = NULL;
extern char *input_plugin;
char *output_plugin = NULL;
char fullscreen = 0;
extern uint8_t max_fps;
char window_decorations = 1;
int32_t x_origin = INT32_MIN;
int32_t y_origin = INT32_MIN;
extern uint16_t width, height;
extern char *themes;
uint8_t statistics = 0; // Display statistics
extern uint16_t http_port;
extern char *http_instance;
extern double volume_scale;
extern uint8_t usage_statistics;
extern Timer_t *session_timer;
extern char *video_base;
extern char *audio_file;
extern char *playlist_filename;

/* default input size (samples) */
#define DEFAULT_INPUT_SIZE 1024
uint32_t input_size = DEFAULT_INPUT_SIZE;


#define _BANNER "\n"                               \
  "      _          ___ _      _          \n"      \
  "     | |   ___  | _ | )_ _ ( )___ _  _ \n"      \
  "     | |__/ -_) | _ \\ | ' \\| / _ \\ || |\n"   \
  "     |____\\___| |___/_|_||_|_\\___/\\_,_|\n"   \
  "\n"                                             \
  "           .:[ " PACKAGE_STRING " ]:.\n"        \
  " -------------------------------------------\n" \
  "  \"Une cause très petite, qui nous échappe,\n" \
  "  détermine un effet considérable que nous \n"  \
  "  ne pouvons pas ne pas voir, et alors nous\n"  \
  "  disons que cet effet est dû au hasard.\" \n"  \
  "\n"                                             \
  "    -- Henri Poincaré, 1908\n"                  \
  " -------------------------------------------\n"


static inline void
do_banner(void)
{
  VERBOSE(printf(_BANNER));
}


void
cleanup(void)
{
  Settings_delete();

  // command-line
  // xfree(audio_file); // raises a weird ASan bug
  xfree(base_dir);
  xfree(data_dir);
  xfree(schemes_file);
  xfree(input_plugin);
  xfree(output_plugin);
  xfree(themes);
#ifdef WITH_WEBCAM
  xfree(video_base);
#endif
  xfree(playlist_filename);
  xfree(http_instance);
}


int
main(int argc, char **argv)
{
  Settings_new();
  Settings_load();
  getargs(argc, argv);

  // signal handling
  register_signals();

  /* Banner */
  if (NULL == getenv("LEBINIOU_NO_BANNER")) {
    do_banner();
  }

  WIDTH_ORIGIN = x_origin;
  HEIGHT_ORIGIN = y_origin;
#ifndef FIXED
  WIDTH = width;
  HEIGHT = height;
#endif

  /* PRNG */
  b_rand_init();

  /* Create context */
  context = Context_new(desired_webcams);
  Context_set_input_size(context, input_size);

  biniou_set_max_fps(max_fps);

  /* Load input */
  if (NULL != input_plugin) {
    biniou_load_input(base_dir, input_plugin, volume_scale);
  }

  /* Initialize */
  biniou_new(data_dir, base_dir, schemes_file, themes,
             B_INIT_ALL
#ifdef DEBUG
             |B_INIT_VERBOSE
#endif
             , input_size, desired_webcams);
  Settings_finish(context);

  json_t *settings = Settings_get();
  const char *current_version = json_string_value(json_object_get(settings, "version"));
  if ((NULL == current_version) || !is_equal(current_version, LEBINIOU_VERSION)) {
    usage_statistics = 1;
  }
  json_decref(settings);

  if (statistics) {
    if (NULL != plugins) {
      printf("[i] Plugins: %d\n", plugins->size);
    } else { // Should not happen, added just in case
      printf("[i] No plugins\n");
    }
    if (NULL != colormaps) {
      printf("[i] Colormaps: %d\n", colormaps->size);
    } else { // Should not happen, added just in case
      printf("[i] No colormaps\n");
    }
    if (NULL != images) {
      printf("[i] Images: %d\n", images->size);
    } else { // Should not happen, added just in case
      printf("[i] No images\n");
    }
    if (NULL != paths) {
      printf("[i] Paths: %d\n", paths->size);
    } else { // Should not happen, added just in case
      printf("[i] No paths\n");
    }
    printf("[i] Sequences: %d\n", sequences->size);
    printf("[i] Schemes: %d\n", schemes->size);
    libbiniou_verbose = 0;
    biniou_go(1);
    biniou_delete();

    return 0;
  }

  /* Load output */
  if (NULL != output_plugin) {
    context->window_decorations = window_decorations;
    biniou_load_output(base_dir, output_plugin);
    biniou_set_full_screen(fullscreen);
  }

  biniou_set_random_mode(random_mode);

  if (http_port) {
    Context_start_vui(context);
  }

  /* Main loop */
  biniou_run();

  if (http_port) {
    Context_stop_vui(context);
  }

  /* All done */
  biniou_delete();
  cleanup();

  okdone("Quit: ouh-ouuuuh \\o/");

  return 0;
}
