#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <stdlib.h>

#include "opts.h"

char *get_str_help()
{
    static char str_help[] =
        "Options :\n"
        "[--out|-o {nom fichier sortie}]\n"
        "    Nom du fichier de sortie\n"
        "[--width|-x {largeur}]\n"
        "    Largeur du labyrinthe à calculer\n"
        "[--length|-y {longueur}]\n"
        "    Longueur du labyrinthe à calculer\n"
        "[--height|-z {hauteur}]\n"
        "    Hauteur du labyrinthe à calculer\n"
        "[--help | -h]\n"
        "    Help = afficher l'aide\n"
        "[--silent | -s]\n"
        "    Mode silencieux (sauf si erreur critique).\n";
    return str_help;
}

int valide_nom_fichier(char *dst, unsigned int max_len_dst, char *src,
                       char *buffer_erreur, int maxlen_erreur)
{
    /* la chaine dest doit être vide sinon ça signifie
       qu'on a passé deux fois la même option */
    if (strlen(dst)) {
        snprintf(buffer_erreur, maxlen_erreur,
                 "Vous avez passé deux fois la même option.\n"
                 "La deuxième fois vous avec passé :\n"
                 "<%s> en paramètre.\n", src);
        return -1;
    }
    if (strlen(src) >= max_len_dst) {
        snprintf(buffer_erreur, maxlen_erreur,
                 "Nom de fichier trop long.\n"
                 "il ne doit pas dépasser %u caractères\n",
                 max_len_dst - 1);
        return -1;
    }
    return 0;
}

int valide_ulong(char *param, unsigned long *retour,
                 char *buffer_erreur, int maxlen_erreur)
{
    char *ptr;

    *retour = strtoul(param, &ptr, 10);
    if ((param[0] != 0) && (ptr[0] == 0)) {
        return 0;
    }
    snprintf(buffer_erreur, maxlen_erreur,
             "Paramètre en entrée <%s> invalide.\n"
             "Il faut un nombre entier positif.\n", param);
    return -1;
}

int valide_opts(int argc, char *argv[], unsigned char *help,
                unsigned char *silent_mode, char *nom_fichier_sortie,
                int maxlen_nom_fichier_sortie,
                unsigned long *taille_x,
                unsigned long *taille_y,
                unsigned long *taille_z,
                char *buffer_erreur, int maxlen_erreur)
{
    /* paramètres possibles :
       --in {nom fichier entrée} 
       --out {nom fichier sortie}
       --append
       --silent
     */
    static struct option long_options[] = {
        {"out", 1, 0, 0},
        {"width", 1, 0, 0},
        {"length", 1, 0, 0},
        {"height", 1, 0, 0},
        {"help", 0, 0, 0},
        {"silent", 0, 0, 0},
        {0, 0, 0, 0}
    };

    /* lecture des options : */
    int this_option_optind;
    int option_index;
    int i;
    *taille_x = 0;
    *taille_y = 0;
    *taille_z = 0;

    while (1) {
        this_option_optind = optind ? optind : 1;
        option_index = 0;

        i = getopt_long(argc, argv, "o:x:y:z:hs", long_options,
                        &option_index);
        if (i == -1)
            break;

        switch (i) {
        case 0:
            switch (option_index) {
            case 0:
                /* "out" */
                if (valide_nom_fichier
                    (nom_fichier_sortie, maxlen_nom_fichier_sortie,
                     optarg, buffer_erreur, maxlen_erreur)) {
                    STRCAT_STR_USAGE(buffer_erreur, maxlen_erreur);
                    return -1;
                }
                strcpy(nom_fichier_sortie, optarg);
                break;
            case 1:
                /* "width" */
                if (valide_ulong(optarg,
                                 taille_x, buffer_erreur, maxlen_erreur)) {
                    STRCAT_STR_USAGE(buffer_erreur, maxlen_erreur);
                    return -1;
                }
                break;
            case 2:
                /* "length" */
                if (valide_ulong(optarg,
                                 taille_y, buffer_erreur, maxlen_erreur)) {
                    STRCAT_STR_USAGE(buffer_erreur, maxlen_erreur);
                    return -1;
                }
                break;
            case 3:
                /* "height" */
                if (valide_ulong(optarg,
                                 taille_z, buffer_erreur, maxlen_erreur)) {
                    STRCAT_STR_USAGE(buffer_erreur, maxlen_erreur);
                    return -1;
                }
                break;
            case 4:
                /* "help" */
                *help = 1;
                return 0;
                break;
            case 5:
                /* "silent" */
                *silent_mode = 1;
                break;
            default:
                snprintf(buffer_erreur, maxlen_erreur,
                         "?? option non gérée, c'est anormal.\n");
                STRCAT_STR_USAGE(buffer_erreur, maxlen_erreur);
                return -1;

            }
            break;
        case 'x':
            if (valide_ulong(optarg,
                             taille_x, buffer_erreur, maxlen_erreur)) {
                STRCAT_STR_USAGE(buffer_erreur, maxlen_erreur);
                return -1;
            }
            break;
        case 'y':
            if (valide_ulong(optarg,
                             taille_y, buffer_erreur, maxlen_erreur)) {
                STRCAT_STR_USAGE(buffer_erreur, maxlen_erreur);
                return -1;
            }
            break;
        case 'z':
            if (valide_ulong(optarg,
                             taille_z, buffer_erreur, maxlen_erreur)) {
                STRCAT_STR_USAGE(buffer_erreur, maxlen_erreur);
                return -1;
            }
            break;
        case 'o':
            if (valide_nom_fichier
                (nom_fichier_sortie, maxlen_nom_fichier_sortie,
                 optarg, buffer_erreur, maxlen_erreur)) {
                STRCAT_STR_USAGE(buffer_erreur, maxlen_erreur);
                return -1;
            }
            strcpy(nom_fichier_sortie, optarg);
            break;
        case 'h':
            /* "help" */
            *help = 1;
            return 0;
            break;
        case 's':
            /* "silent" */
            *silent_mode = 1;
            break;
        }
    }

    if (optind < argc) {
        printf("Options ignorées :");
        while (optind < argc)
            printf("%s ", argv[optind++]);
        printf("\n");
    }
    if (strlen(nom_fichier_sortie) == 0) {
        snprintf(buffer_erreur, maxlen_erreur,
                 "Vous n'avez passé aucun fichier en sortie.\n");
        STRCAT_STR_USAGE(buffer_erreur, maxlen_erreur);
        return -1;
    }
    if ((*taille_x) == 0) {
        snprintf(buffer_erreur, maxlen_erreur,
                 "Vous n'avez pas passé de largeur en paramètre.\n");
        STRCAT_STR_USAGE(buffer_erreur, maxlen_erreur);
        return -1;
    }
    if ((*taille_y) == 0) {
        snprintf(buffer_erreur, maxlen_erreur,
                 "Vous n'avez pas passé de longueur en paramètre.\n");
        STRCAT_STR_USAGE(buffer_erreur, maxlen_erreur);
        return -1;
    }
    if ((*taille_z) == 0) {
        snprintf(buffer_erreur, maxlen_erreur,
                 "Vous n'avez pas passé de hauteur en paramètre.\n");
        STRCAT_STR_USAGE(buffer_erreur, maxlen_erreur);
        return -1;
    }
    return 0;
}
