/* ====================================================================
 * FTD4Linux Software License, Version 1.0
 *
 * Copyright (c) 2000-2004 The FTD4Linux Development Team.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        FTD4Linux Development Team (http://www.ftd4linux.2y.net/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "FTD" and "FTD4Linux" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact alguno@ftd4linux.2y.net.
 *
 * 5. Products derived from this software may not be called "FTD4Linux",
 *    nor may "FTD4Linux" appear in their name, without prior written
 *    permission of the FTD4Linux Development Team.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE FTD4LINUX DEVELOPMENT TEAM OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

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

#include "ftd4linux.h"
#include "ftd_con.h"

#ifdef HAVE_GTK
#include "ftd_gui_config.h"
#endif

#ifdef WIN32
#include <windows.h>
#endif

typedef struct command_line_opts {
#ifdef HAVE_GTK
    gboolean    config;
#endif
    gboolean    updateList;
    gboolean    showList;
    gboolean    showEvent;
    gboolean    showMemberCount;
    int         eventID;
    gboolean    xmlOutput;
    time_t      age;
    char       *zoekterm;
    gboolean    offline;
} CommandLineOpts;

void
print_help()
{
    g_print("====================================================================\n");
    g_print("                                                                    \n");
    g_print("              OpenFTD 1.0 Beta 6 - Command Line Versie              \n");
    g_print("                                                                    \n");
    g_print("====================================================================\n");
    g_print("\n");
    g_print("WAARSCHUWING:\tHet publiekelijk beschikbaar maken van FTD gegevens\n");
    g_print("\t\tkan leiden tot een ban of accountverwijdering.\n");
    g_print("\t\tDit programma is alleen bedoeld voor eigen gebruik.\n");
    g_print("\n");
    g_print("--------------------------------------------------------------------\n");
    g_print("\n");
    g_print("De geldige command line opties voor dit programma zijn :\n");
    g_print("\n");
    g_print("-h / --help\n");
    g_print("\tToont deze help documentatie\n");
    g_print("\n");
#ifdef HAVE_GTK
    g_print("-c / --config\n");
    g_print("\tToont het configuratievenster\n");
    g_print("\n");
#endif
    g_print("-u / --update\n");
    g_print("\tUpdate de lijst met FTD postings\n");
    g_print("\n");
    g_print("-m / --membercount\n");
    g_print("\tToont het aantal geregistreerde leden op de FTD server\n");
    g_print("\n");
    g_print("-l / --list\n");
    g_print("\tToont de lijst met FTD postings\n");
    g_print("\n");
    g_print("-p <id> / --postinfo <id>\n");
    g_print("\tToont de informatie van FTD posting <id>\n");
    g_print("\n");
    g_print("-a <age> / --age <age>\n");
    g_print("\tDeze optie kan alleen gebruikt worden in combinatie met de -l/--list\n");
    g_print("\tparameter. Deze optie zorgt ervoor dat alleen FTD postings die\n");
    g_print("\tgeplaatst zijn binnen de laatste <age> seconden getoond worden.\n");
    g_print("\tIndien deze optie weggelaten wordt dan zullen alle nieuwe FTD\n");
    g_print("\tpostings getoond worden die opgehaald zijn bij de laaatste update.\n");
    g_print("\tIndien <age> 0 is, dan zullen alle bekende FTD postings getoond worden.\n");
    g_print("\n");
    g_print("-x / --xml\n");
    g_print("\tDeze optie kan alleen gebruikt worden in combinatie met de\n");
    g_print("\t-l / --list en de -p / --postinfo parameters. Deze optie\n");
    g_print("\tzorgt ervoor dat de gegevens in XML notatie getoond worden.\n");
    g_print("\n");
    g_print("-z / --zoekterm\n");
    g_print("\tLaat alleen postings zien die aan een bepaalde zoekterm voldoen.\n");
    g_print("\tDeze optie kan alleen gebruikt worden in combinatie met de\n");
    g_print("\t-l / --list parameters.\n");
    g_print("\n");
    g_print("-o / --offline\n");
    g_print("\tVoorkom dat extra gegevens behorende bij een FTD posting\n");
    g_print("\top internet opgezocht worden. Deze optie kan alleen gebruikt\n");
    g_print("\tworden in combinatie met de -p / --postinfo parameters.\n");
    g_print("\n");
}

CommandLineOpts
parse_cmdline(int argc, char *argv[])
{
    CommandLineOpts opts;
    int c;

    memset(&opts, 0, sizeof(opts));
    opts.age = -1;

    if (argc == 1) {
        print_help();
        ftd_app_core_cleanup();
        exit(0);
    }

    while (1) {
        int option_index = 0;
        static struct option long_options[] = {
#ifdef HAVE_GTK
            {"config", 0, 0, 'c'},
#endif
            {"help", 0, 0, 'h'},
            {"update", 0, 0, 'u'},
            {"list", 0, 0, 'l'},
            {"postinfo", 1, 0, 'p'},
            {"age", 1, 0, 'a'},
            {"xml", 0, 0, 'x'},
            {"membercount", 0, 0, 'm'},
            {"zoekterm", 1, 0, 'z'},
            {"offline", 0, 0, 'o'},
            {0, 0, 0, 0}
        };

#ifdef HAVE_GTK
        c = getopt_long (argc, argv, "ochulmp:a:xz:", long_options, &option_index);
#else
        c = getopt_long (argc, argv, "ohulmp:a:xz:", long_options, &option_index);
#endif
        if (c == -1)
            break;

        switch (c) {
#ifdef HAVE_GTK
        case 'c':
            opts.config = TRUE;
            break;
#endif

        case 'h':
            print_help();
            ftd_app_core_cleanup();
            exit(0);
            break;

        case 'o':
            opts.offline = TRUE;
            break;

        case 'z':
            opts.zoekterm = g_strdup(optarg);
            break;

        case 'u':
            opts.updateList = TRUE;
            break;

        case 'l':
            opts.showList = TRUE;
            break;

        case 'p':
            opts.showEvent = TRUE;
            opts.eventID = atoi(optarg);
            break;

        case 'a':
            opts.age = atoi(optarg);
            break;

        case 'x':
            opts.xmlOutput = TRUE;
            break;

        case 'm':
            opts.showMemberCount = TRUE;
            break;

        case '?':
            break;

        default:
            printf ("?? getopt returned character code 0%o ??\n", c);
        }
    }

    if (optind < argc) {
        printf ("non-option ARGV-elements: ");
        while (optind < argc) {
            printf ("%s ", argv[optind++]);
        }
        printf ("\n");
    }

    return opts;
}

gboolean
check_invalid_opts(CommandLineOpts opts)
{
    if (opts.updateList && opts.showList) {
        return TRUE;
    }

    if (opts.updateList && opts.showEvent) {
        return TRUE;
    }

    if (opts.showList && opts.showEvent) {
        return TRUE;
    }

    if (opts.age > 0 && !opts.showList) {
        return TRUE;
    }

    if (opts.zoekterm && !opts.showList) {
        return TRUE;
    }

    if (opts.offline && !opts.showEvent) {
        return TRUE;
    }

    if (opts.xmlOutput && !(opts.showList || opts.showEvent)) {
        return TRUE;
    }

#ifdef HAVE_GTK
    if (opts.config && (opts.updateList || opts.showList || opts.showEvent || opts.xmlOutput)) {
        return TRUE;
    }
#endif

    if (opts.showMemberCount && (opts.updateList || opts.showList || opts.showEvent || opts.age > 0 || opts.xmlOutput)) {
        return TRUE;
    }

    return FALSE;
}

int
execute_opts(CommandLineOpts opts, int argc, char *argv[])
{
#ifdef HAVE_GTK
    if (opts.config) {
        FtdGuiConfig *config;
        gtk_set_locale ();
        gtk_init (&argc, &argv);
        config = ftd_gui_config_new(NULL, FALSE, FALSE);
        gtk_main();
        ftd_gui_config_free(config);
    }
#endif

    if (opts.updateList) {
        char *errmsg = NULL;
        int retval = ftd_events_fetch(NULL, NULL, NULL, &errmsg, NULL);
        if (retval && retval != ERROR_NEW) {
            gchar *msg = ftd_error_msg(retval, errmsg);
            g_warning("Updaten van lijst met FTD postings mislukt!\n%s\n", msg);
            g_free(msg);
            return retval;
        } else {
            g_print("Updaten van lijst met FTD postings geslaagd\n");
            return 0;
        }
    }

    if (opts.showList) {
        if (!opts.xmlOutput) {
            return ftd_con_list_print(opts.age, opts.zoekterm);
        } else {
            return ftd_con_list_print_xml(opts.age, opts.zoekterm);
        }
    }

    if (opts.showEvent) {
        if (!opts.xmlOutput) {
            return ftd_con_event_print(opts.eventID, opts.offline);
        } else {
            return ftd_con_event_print_xml(opts.eventID, opts.offline);
        }
    }

    if (opts.showMemberCount) {
        g_print("%i\n", ftd_config_get()->ledenCount);
        return 0;
    }

    return -1;
}

#ifdef WIN32
void my_log_handler                         (const gchar *log_domain,
                                             GLogLevelFlags log_level,
                                             const gchar *message,
                                             gpointer user_data)
{
    gunichar2 *msg = g_utf8_to_utf16 (message, -1, NULL, NULL, NULL);
    if ((log_level & G_LOG_FLAG_FATAL) == G_LOG_FLAG_FATAL) {
        MessageBoxW(NULL, (LPCWSTR) msg, NULL, MB_OK);
        PostQuitMessage(0);
    } else {
        MessageBoxW(NULL, (LPCWSTR) msg, NULL, MB_OK);
    }

    g_free(msg);
}
#endif

int main(int argc, char *argv[])
{
    CommandLineOpts opts;
    int retval;
    char *errmsg = NULL;
    gboolean dbus_init_success;

#ifdef WIN32
    g_log_set_handler (NULL, (GLogLevelFlags) (G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION), my_log_handler, NULL);
#endif

    g_set_prgname("OpenFTD_console");

    if (!ftd_app_core_init(g_getenv("FTD_DATA_DIR"), NULL, g_getenv("FTD_LIB_DIR"), "Console", FALSE, &errmsg, &dbus_init_success)) {
        ftd_app_core_cleanup();
        g_error("ftd_app_core_init() failed!\n");
    }

    if (ftd_app_core_is_first_time()) {
        /* Dit is de eerste keer dat we opgestart worden. */
#ifdef HAVE_GTK
        FtdGuiConfig *config;
        gtk_set_locale ();
        gtk_init (&argc, &argv);
        config = ftd_gui_config_new(NULL, FALSE, FALSE);
        gtk_main();

        /* Voer de controle nogmaals uit. Indien de gebruiker
           geen of geen geldige gegevens heeft ingevoerd heeft
           het totaal geen zin om het programma verder te starten. */
        if (ftd_app_core_is_first_time()) {
            ftd_app_core_cleanup();
            g_error("First time setup mislukt!");
        }
#else
        // Maak een dummy config bestand aan
        ftd_config_create_dummy();
        ftd_app_core_cleanup();
        g_error("OpenFTD is nog niet geconfigureerd.\n"
                "Gelieve het bestand 'openftd.conf' te bewerken.\n"
                "Een dummy bestand is zojuist aangemaakt.\n");
#endif
    }

#ifdef HAVE_DBUS
    if (!dbus_init_success) {
        g_print(errmsg);
        g_free(errmsg);
    }
#endif

    // Moet nog netter kunnen
    if (!ftd_group_list_ready()) {
        char *errmsg;
        ftd_group_fetch(&errmsg);
    }

    opts = parse_cmdline(argc, argv);

    if (check_invalid_opts(opts)) {
        ftd_app_core_cleanup();
        g_error("Ongeldige combinatie van command-line opties opgegeven!\n");
    }

    retval = execute_opts(opts, argc, argv);

    ftd_app_core_cleanup();

    return retval;
}
