/*
 *  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 <libavutil/ffversion.h>
#include "main.h"
#include "webcam.h"
#include "settings.h"


#ifdef WITH_WEBCAM
extern uint8_t hflip, vflip, desired_webcams;
extern char *video_base;
#endif
extern uint8_t  statistics;
extern uint16_t http_port;
extern uint8_t  max_fps;
extern uint8_t  use_hard_timers;
extern uint8_t  encoding;
extern char    *playlist_filename;
extern char    *audio_file;
#ifdef WITH_SDL2UI
extern uint8_t  enable_osd;
#endif
extern uint8_t  usage_statistics;
extern uint8_t  launch_browser;
extern char    *http_instance;

#define MIN_WIDTH  80
#define MIN_HEIGHT 60


static void
usage(void)
{
  printf("Usage: " PACKAGE_NAME " [options]\n\n"
         "\t-a, --audio <file>\tSet audio file (sndfile plugin)\n"
         "\t-b, --basedir <path>\tSet base directory [" DEFAULT_PLUGINSDIR "]\n"
         "\t-c, --config <file>\tSet configuration file [~/." PACKAGE_NAME "/" JSON_SETTINGS "]\n"
         "\t-d, --datadir <path>\tSet data directory [" DEFAULT_DATADIR "]\n"
         "\t-f, --fullscreen\tSet fullscreen\n"
         "\t-h, --help\t\tDisplay this help\n"
         "\t-i, --input <plugin>\tSet input plugin [" DEFAULT_INPUT_PLUGIN "]\n"
         "\t-m, --max-fps <fps>\tSet maximum framerate [%d]\n"
         "\t-n, --no-borders\tDisable window borders\n"
         "\t-o, --output <plugin>\tSet output plugin [" DEFAULT_OUTPUT_PLUGIN "]\n"
         "\t-q, --quiet\t\tSuppress messages\n"
         "\t-r, --random <mode>\tSet auto-random mode\n"
         "\t-s, --soft-timers\tUse soft timers instead of the system clock\n"
         "\t-t, --themes <themes>\tComma-separated list of themes to use [biniou,covid-19,zebulon]\n"
         "\t-v, --version\t\tDisplay the version and exit\n"
         "\t-w, --http-port\t\tWeb interface port [%d]\n"
#ifndef FIXED
         "\t-x, --width <width>\tSet width [%d]\n"
         "\t-y, --height <height>\tSet height [%d]\n"
#endif
         "\t-z, --schemes <file>\tSet the schemes file [" DEFAULT_SCHEMES_FILE "]\n"
         "\t-B, --no-browser\tDon't open the web interface in a browser\n"
#ifdef WITH_WEBCAM
         "\t-C, --cam-flip <h|v>\tFlip webcam image horizontally/vertically\n"
         "\t-D, --device <device>\tWebcam base [" DEFAULT_VIDEO_DEVICE "]\n"
#endif
         "\t-E, --start-encoding\tStart encoding directly\n"
         "\t-F, --fade <delay>\tSet fade delay (in seconds)\n"
#ifdef WITH_SDL2UI
         "\t-G, --enable-sdl2-gui\tEnable the legacy SDL2 GUI\n"
#endif
         "\t-I, --instance <name>\tSet the instance name [none]\n"
         "\t-N, --no-statistics\tDo not send usage statistics\n"
         "\t-P, --playlist <file>\tSet playlist file\n"
         "\t-S, --stats\t\tDisplay statistics\n"
#ifdef WITH_WEBCAM
         "\t-W, --webcams <webcams>\tNumber of webcams [%d]\n"
#endif
         "\t-X, --xpos <x position>\tSet left position of the window\n"
         "\t-Y, --ypos <y position>\tSet top position of the window\n"
         "\n"
         PACKAGE_NAME " " LEBINIOU_VERSION " was compiled with:\n"
         "\tInput plugins: " INPUT_PLUGINS "\n"
         "\tOutput plugins: " OUTPUT_PLUGINS "\n"
         "\n"
         , max_fps
         , http_port
#ifndef FIXED
         , DEFAULT_WIDTH
         , DEFAULT_HEIGHT
#endif
#ifdef WITH_WEBCAM
         , desired_webcams
#endif
         );

  /* TODO print default values for all options */
  exit(0);
}


void
getargs(int argc, char **argv)
{
  int ch;
#ifndef FIXED
  int w, h;
#endif

  static const char *arg_list = "a:b:c:BC:d:D:EfF:GhI:i:lm:nNo:P:qr:sSt:x:X:y:Y:vw:W:z:";

#if HAVE_GETOPT_LONG
  static struct option long_opt[] = {
    {"audio", required_argument, NULL, 'a'},
    {"basedir", required_argument, NULL, 'b'},
    {"config", required_argument, NULL, 'c'},
    {"datadir", required_argument, NULL, 'd'},
    {"fullscreen", no_argument, NULL, 'f'},
    {"help", no_argument, NULL, 'h'},
    {"http-port", required_argument, NULL, 'w'},
    {"input", required_argument, NULL, 'i'},
    {"max-fps", required_argument, NULL, 'm'},
    {"no-borders", no_argument, NULL, 'n'},
    {"output", required_argument, NULL, 'o'},
    {"quiet", no_argument, NULL, 'q'},
    {"random", required_argument, NULL, 'r'},
    {"soft-timers", no_argument, NULL, 's'},
    {"start-encoding", no_argument, NULL, 'E'},
    {"themes", required_argument, NULL, 't'},
    {"version", no_argument, NULL, 'v'},
#ifndef FIXED
    {"width", required_argument, NULL, 'x'},
    {"height", required_argument, NULL, 'y'},
#endif
    {"schemes", required_argument, NULL, 'z'},
    {"no-browser", no_argument, NULL, 'B'},
#ifdef WITH_WEBCAM
    {"cam-flip", required_argument, NULL, 'C'},
    {"device", required_argument, NULL, 'D'},
#endif
    {"fade", required_argument, NULL, 'F'},
#ifdef WITH_SDL2UI
    {"enable-sdl2-gui", no_argument, NULL, 'G'},
#endif
    {"instance", required_argument, NULL, 'I'},
    {"no-statistics", no_argument, NULL, 'N'},
    {"playlist", required_argument, NULL, 'P'},
    {"stats", no_argument, NULL, 'S'},
#ifdef WITH_WEBCAM
    {"webcams", required_argument, NULL, 'W'},
#endif
    {"xpos", required_argument, NULL, 'X'},
    {"ypos", required_argument, NULL, 'Y'},

    {0, 0, 0, 0}
  };


  /* Get command line arguments */
  while ((ch = getopt_long(argc, argv, arg_list, long_opt, NULL)) != -1)
#else
    while ((ch = getopt(argc, argv, arg_list)) != -1)
#endif
      switch (ch) {
      case 'a':
        xfree(audio_file);
        if (NULL != optarg) {
          audio_file = strdup(optarg);
          VERBOSE(printf("[c] Setting audio file: %s\n", audio_file));
        }
        break;

      case 'b':
        xfree(base_dir);
        if (NULL != optarg) {
          base_dir = strdup(optarg);
          VERBOSE(printf("[c] Setting base directory: %s\n", base_dir));
        }
        break;

      case 'c':
        if (NULL != optarg) {
          VERBOSE(printf("[c] Loading settings from: %s\n", optarg));
          Settings_set_configuration_file(optarg);
          Settings_load();
        }
        break;

      case 'd':
        xfree(data_dir);
        if (NULL != optarg) {
          data_dir = strdup(optarg);
          VERBOSE(printf("[c] Setting data directory: %s\n", data_dir));
        }
        break;

      case 'E':
        encoding = 1;
        break;

      case 'w':
        if (NULL != optarg) {
          http_port = xstrtol(optarg);
          if (http_port && (http_port < 1024)) {
            xerror("HTTP API port must be >= 1024, or 0 to disable\n");
          } else {
            if (http_port) {
              VERBOSE(printf("[c] Setting HTTP_API port to %d\n", http_port));
            } else {
              VERBOSE(printf("[c] Disabling HTTP_API\n"));
            }
          }
        }
        break;

      case 'z':
        xfree(schemes_file);
        if (NULL != optarg) {
          schemes_file = strdup(optarg);
          VERBOSE(printf("[c] Setting schemes file: %s\n", schemes_file));
        }
        break;

      case 'f':
        fullscreen = 1;
        break;

      case 'h':
        usage();
        break;

      case 'n':
        window_decorations = 0;
        VERBOSE(printf("[c] Deactivate window decorations\n"));
        break;

      case 'i':
        xfree(input_plugin);
        if (NULL != optarg) {
          input_plugin = strdup(optarg);
          VERBOSE(printf("[c] Setting input plugin: %s\n", input_plugin));
        }
        break;

      case 'o':
        xfree(output_plugin);
        if (NULL != optarg) {
          output_plugin = strdup(optarg);
          VERBOSE(printf("[c] Setting output plugin: %s\n", output_plugin));
        }
        break;

      case 'm':
        if (NULL != optarg) {
          max_fps = xstrtol(optarg);
          if (max_fps > 0) {
            VERBOSE(printf("[c] Maximum fps set to %i\n", max_fps));
          } else {
            xerror("Invalid max_fps (%d)\n", max_fps);
          }
        }
        break;

      case 'r':
        if (NULL != optarg) {
          if (optarg[0] != '-') {
            random_mode = (enum RandomMode)xstrtol(optarg);
            if (random_mode > BR_BOTH) {
              xerror("Invalid random mode (%d)\n", random_mode);
            } else {
              VERBOSE(printf("[c] Random mode set to %d\n", random_mode));
            }
          } else {
            xerror("Random mode must be in [0..3]\n");
          }
        }
        break;

      case 't':
        xfree(themes);
        if (NULL != optarg) {
          themes = strdup(optarg);
          VERBOSE(printf("[c] Using themes: %s\n", themes));
        }
        break;

      case 'v':
        printf("%s %s was built using:\n", PACKAGE_NAME, LEBINIOU_VERSION);
#ifdef ULFIUS_VERSION_STR
        printf(" - ulfius %s\n", ULFIUS_VERSION_STR);
#endif
        printf(" - libav %s\n", FFMPEG_VERSION);
        printf(" - glib %d.%d.%d\n", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
#ifdef YDER_VERSION_STR
        printf(" - yder %s\n", YDER_VERSION_STR);
#endif
#ifdef ORCANIA_VERSION_STR
        printf(" - orcania %s\n", ORCANIA_VERSION_STR);
#endif
        exit(0);
        break;

      case 'q':
        libbiniou_verbose = 0;
        break;

      case 'x':
#ifndef FIXED
        if (NULL != optarg) {
          w = xstrtol(optarg);
          if (w >= MIN_WIDTH) {
            width = w;
            VERBOSE(printf("[c] Width set to %i\n", width));
          } else {
            xerror("Invalid width: %d (min: %d)\n", w, MIN_WIDTH);
          }
        }
#else
        VERBOSE(fprintf(stderr, "[!] Compiled with fixed buffers, ignoring width= %li\n", xstrtol(optarg)));
#endif
        break;

      case 'X':
        if (NULL != optarg) {
          x_origin = xstrtol(optarg);
          VERBOSE(printf("[c] X origin set to %i\n", x_origin));
        }
        break;

      case 'y':
#ifndef FIXED
        if (NULL != optarg) {
          h = xstrtol(optarg);
          if (h >= MIN_HEIGHT) {
            height = h;
            VERBOSE(printf("[c] Height set to %i\n", height));
          } else {
            xerror("Invalid height: %d (min: %d)\n", h, MIN_HEIGHT);
          }
        }
#else
        VERBOSE(fprintf(stderr, "[!] Compiled with fixed buffers, ignoring height= %li\n", xstrtol(optarg)));
#endif
        break;

      case 'Y':
        if (NULL != optarg) {
          y_origin = xstrtol(optarg);
          VERBOSE(printf("[c] Y origin set to %i\n", y_origin));
        }
        break;

      case 'B':
        launch_browser = 0;
        break;

#ifdef WITH_WEBCAM
      case 'C':
        if (NULL != optarg) {
          if (*optarg == 'h') {
            hflip = !hflip;
          }
          if (*optarg == 'v') {
            vflip = !vflip;
          }
        }
        break;

      case 'W': /* webcams */
        if (NULL != optarg) {
          desired_webcams = xstrtol(optarg);
          if (desired_webcams <= MAX_CAMS) {
            VERBOSE(printf("[c] webcam: grabbing %d device%s\n", desired_webcams, (desired_webcams == 1 ? "": "s")));
          } else {
            if (desired_webcams) {
              desired_webcams = 1;
            }
          }
        }
        break;

      case 'D': /* video_base */
        xfree(video_base);
        if (NULL != optarg) {
          video_base = strdup(optarg);
          VERBOSE(printf("[c] webcam: first device is %s\n", video_base));
        }
        break;
#endif

      case 's':
        use_hard_timers = 0;
        VERBOSE(printf("[c] Using %s timers\n", use_hard_timers ? "hard" : "soft"));
        break;

      case 'P':
        xfree(playlist_filename);
        if (NULL != optarg) {
          playlist_filename = strdup(optarg);
          VERBOSE(printf("[c] Playlist: %s\n", playlist_filename));
        }
        break;

      case 'S':
        libbiniou_verbose = 0;
        statistics = 1;
        break;

      case 'F':
        if (NULL != optarg) {
          fade_delay = xatof(optarg);
          VERBOSE(printf("[c] Fading delay set to %f\n", fade_delay));
        }
        break;

      case 'G':
#ifdef WITH_SDL2UI
        enable_osd = 1;
        VERBOSE(printf("[c] Enabling legacy SDL2 GUI\n"));
#endif
        break;

      case 'I':
        xfree(http_instance);
        http_instance = strdup(optarg);
        VERBOSE(printf("[c] Instance name: %s\n", http_instance));
        break;

      case 'N':
        usage_statistics = 0;
        VERBOSE(printf("[c] Not sending statistics usage\n"));
        break;

      default:
        usage();
        break;
      }

  if (NULL == base_dir) {
    base_dir = strdup(DEFAULT_PLUGINSDIR);
  }

  if (NULL == data_dir) {
    data_dir = strdup(DEFAULT_DATADIR);
  }

  if (NULL == schemes_file) {
    schemes_file = strdup(DEFAULT_SCHEMES_FILE);
  }

  if (NULL == input_plugin) {
    input_plugin = strdup(DEFAULT_INPUT_PLUGIN);
  } else if (is_equal(input_plugin, "NULL")) {
    input_plugin = NULL;
  }

  if (NULL == output_plugin) {
    output_plugin = strdup(DEFAULT_OUTPUT_PLUGIN);
  }  else if (is_equal(output_plugin, "NULL")) {
    output_plugin = NULL;
  }

#ifdef WITH_WEBCAM
  if (NULL == video_base) {
    video_base = strdup(DEFAULT_VIDEO_DEVICE);
  }
#endif
}
