/**
 *   \file main.c
 *   \brief Fichier principal du programme
 *
 *  Ce fichier contient les fonctions principales du logiciel qui ne sont pas
 *  directement liées à la logique et au traitement des données du logiciel,
 *  mais plutôt au traitement des arguments passés au processus et au lancement
 *  des fonctions cœures du programme.
 */

#include "common.h"
#include <getopt.h>
#include <string.h>

/**
 *  \brief Affiche un message d'aide
 *
 *  Affiche un message d'aide pour le logiciel ainsi que son utilisation, puis
 *  termine le processus avec le code de sortie indiqué par l'argument de la
 *  fonction.
 *
 *  \param[in] t_exit_code Code de sortie du processus
 */
void help(int t_exit_code) {
  puts("Usage:\n\
surfaces-unies -i path [-o path] [-options]\n\n\
The default action is to compress the mandatory input image to a .su\n\
file saved in the current directory.\n\
The input image MUST be saved in the ppm format.\n\
Options available:\n\
-h --help\n\tdisplay the current message\n\
-i --input\n\tpath to the input file (MANDATORY)\n\
-o --output\n\
\tpath to the output file (if the file already exists, it will be overwritten)\n\
-c --compress\n\tcompress the input file\n\
-u --uncompress\n\tuncompresses the input file to the output file.");
  exit(t_exit_code);
}

/**
 *  \struct Argres
 *  \brief Résultats du traitement des arguments du processus
 *
 *  Cette structure est utilisée pour consolider ensemble les résultats du
 *  traitement des arguments et les renvoyer en une fois au lieu d'avoir à
 *  utiliser des variables globales ou des pointeurs en arguments
 *  supplémentaires aux fonctions.
 */
struct Argres {
  char *input;   /*!< Nom du fichier d'entrée */
  char *output;  /*!< Nom du fichier de sortie */
  bool compress; /*!< Le fichier d'entrée doit-il être compressé ? */
};
typedef struct Argres Argres;

/**
 *  \brief Processes independently the arguments of the process
 *
 *  Each option and switch will be processed here and will modify appropriately
 *  the parameter `args`
 *
 *  \param[out] t_args Result of the arguments processing
 *  \param[in] t_c Switch or option passed
 */
void get_args(Argres *t_args, int *t_c) {
  switch (*t_c) {
  case 0:   break;
  case 'h': help(NOERROR); break;
  case 'i': (*t_args).input = optarg;   break;
  case 'o': (*t_args).output = optarg;  break;
  case 'c': (*t_args).compress = true;  break;
  case 'u': (*t_args).compress = false; break;
  case '?':
  default: help(ARGERROR);
  }
}

/**
 *  \brief Traite les arguments passés au processus
 *
 *  Les arguments passés au processus seront traités ici. Les arguments passés
 *  dans cette fonction ne subiront aucune modification. La fonction renvoie une
 *  structure \ref Argres contenant le nom de fichier d’entrée et de sortie
 *  ainsi qu’un booléen indiquant si le fichier d’entrée doit être compressé ou
 *  décompressé.
 *
 *  \param[in] t_argc Nombre d’arguments reçus
 *  \param[in] t_argv Arguments reçus par le processus
 *  \return structure \ref Argres
 */
Argres process_args(const int t_argc, char *t_argv[]) {
  Argres res;
  res.input = NULL;
  res.output = "output.su";
  while (true) {
    int option_index = 0;
    static struct option long_options[] = {
        {"help", no_argument, NULL, 'h'},         {"input", required_argument, NULL, 'i'},
        {"output", required_argument, NULL, 'o'}, {"compress", no_argument, NULL, 'c'},
        {"uncompress", no_argument, NULL, 'u'},   {NULL, 0, NULL, 0}};
    int c = getopt_long(t_argc, t_argv, "hi:o:cu", long_options, &option_index);
    if (c == -1) break;
    get_args(&res, &c);
  }
  return res;
}

/**
 *  \brief Fonction `main` lancée avec le processus
 *
 *  This function is launched with the process. It will analyze the arguments it
 *  received, and depending on them will either compress or uncompress the input
 *  file, or will throw an error and stop in case of incorrect arguments.
 *
 *  \param[in] argc Nombre d’arguments reçus par le processus
 *  \param[in] argv Tableau des arguments reçus par le processus
 *  \return Code de status du processus
 */
int main(int argc, char **argv) {
  Argres argresults = process_args(argc, argv);
  if (NULL == argresults.input) {
    fprintf(stderr, "ERROR: no input file.");
    help(ARGERROR);
  }
  DEBUG {
    printf("input: %s\noutput: %s\n", argresults.input, argresults.output);
  }
  if(argresults.compress) {
    compress(argresults.input);
  } else {
    puts("Uncompressing...");
  }
  return 0;
}
