/***************************************************************************

  cbedic.cpp

  This file is part of the CBE Dictionary package

  Copyright (c) 2003 Antoby - antoby@users.sourceforge.net

  This program 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.

  This program 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 this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

****************************************************************************/

#if HAVE_CONFIG_H
#include "config.h"
#else
#ifdef WIN32
#include "config_win.h"
#endif // WIN32
#endif // HAVE_CONFIG_H


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

// engine
#include "translator.h"
#include "registry.h"

// util
#include "getopt.h"

// local
#include "defaults.h"
#include "messages.h"
#include "cbedic.h"

// needed for GetModuleFileName()
#ifdef WIN32
#include <windows.h>
#endif // WIN32


/////////////////////////////////////////////////////////////////////////////
// Globals

DICT_OPTIONS    g_options;
Registry *      g_reg;
bool            g_start_interactive;
char            g_data_dir[FILENAME_LENGTH];


/////////////////////////////////////////////////////////////////////////////


int main(int argc, char **argv)
{
    int c;
    char *translation = NULL;

    printf("CBEdic - Console Bulgarian/English dictionary v%s by Antoby\n", VERSION);

    init_globals();

    // process command line options
    extern int optind;
    int option_index;
    static const struct option long_options[] = 
    {
        {"web",         no_argument, NULL, 'w'},
        {"separate",    no_argument, NULL, 's'},
        {"latinout",    no_argument, NULL, 'l'},
        {"latinin",     no_argument, NULL, 'u'},
        {"exact",       no_argument, NULL, 'e'},

        {"interactive", no_argument, NULL, 'i'},
        {"config",      no_argument, NULL, 'c'},
        {"version",     no_argument, NULL, 'v'},
        {"help",        no_argument, NULL, 'h'},

        {NULL, 0, NULL, 0}
    };

    while((c = getopt_long(argc, argv, "wslueicvh", long_options, &option_index)) != EOF){
        switch(c){
        case 'w':
            g_options.html_output = true;
            break;
        case 's':
            g_options.separate_meanings = true;
            break;
        case 'l':
            g_options.latin_output = true;
            break;
        case 'u':
            g_options.latin_input = true;
            break;
        case 'e':
            g_options.exact_match = true;
            break;
        case 'i':
            g_start_interactive = !g_start_interactive;
            break;
        case 'c':
            cbeconfig();
            delete g_reg;
            exit(0);
        case 'v':
            delete g_reg;
            exit(0);
        case 'h':
        default:
            printf("Usage: %s [-c|-v|-h|-i|-wslue] [word]\n", argv[0]);
            printf("\t-c | --configure\tconfigure cbedic (create %s)\n", REGISTRY_FILE);
            printf("\t-v | --version\t\tprint version information\n");
            printf("\t-h | --help\t\tthis help screen\n");
            printf("\t-w | --web\t\tweb output (HTML)\n");
            printf("\t-s | --separate\t\tseparate meanings\n");
            printf("\t-l | --latinout\t\tlatin output\n");
            printf("\t-u | --latinin\t\tlatin input\n");
            printf("\t-e | --exact\t\tmatch the exact word\n");
            printf("\t-i | --interactive\tswitch to interactive mode\n\n");
            delete g_reg;
            exit(1);
        };
    };

    delete g_reg;
    printf("\n");

    // init engine
    Translator dict(MAX_WORD_LEN, MAX_WORDS_ALLOWED);

    // load EN->BG dictionary
    if(!dict.createDictionary(g_data_dir, dict.ENG_BUL)){
        printf("Can not find English->Bulgarian dictionary in '%s'\n", g_data_dir);
        exit(1);
    }

    // load BG->EN dictionary
    if(!dict.createDictionary(g_data_dir, dict.BUL_ENG)){
        printf("Can not find Bulgarian->English dictionary in '%s'\n", g_data_dir);
        exit(1);
    }

    dict.latinInput         = g_options.latin_input;
    dict.latinOutput        = g_options.latin_output;
    dict.separateMeanings   = g_options.separate_meanings;
    dict.boldDecoration     = true;
    dict.htmlOutput         = g_options.html_output;

    if(g_start_interactive){
        interactive_loop(&dict, g_options.exact_match);
    } else {
        if(optind < argc){
            if(!dict.findWord(argv[optind], &translation)){
                printf("word not found.\n");
                if(g_options.exact_match) {
                    return 1;
                }
            }

            if (translation[0] != '\0') {
                printf("%s", translation);
            }
        } else {
            printf("Please specify a word to translate or type '%s -h' for help\n",argv[0]);
            return 1;
        }
    }

    printf("\n");

    return 0;
}

/////////////////////////////////////////////////////////////////////////////

int interactive_loop(Translator *dict, int exact_match)
{
    char word[MAX_WORD_LEN];
    char *translation = NULL;
    const char *msg_onoff[] = { "off", "on" };

    printf("Entered interactive mode, type /help to list commands\n");

    while(1){
        printf("word: ");
        fflush(stdin);
        fgets(word, MAX_WORD_LEN, stdin);

        if(strlen(word) < 1){
            continue;
        }

        switch(check_word((char *)&word)){
            case NORMAL_WORD:
                // normal word to translate
                if(!dict->findWord(word, &translation)){
                    printf("word not found.\n");
                    if(exact_match){
                        break;
                    }
                }

                if (translation[0] != '\0') {
                    printf("%s", translation);
                }
                break;
            case CMD_HELP:
                // help
                printf(
                    "These are the allowed commands:\n\n" \
                    "/help\t\tThis help screen\n" \
                    "/status\t\tShow the status of the dictionary settings\n" \
                    "/separate\tToggle on/off the flag for separate meanings\n" \
                    "/latinin\tToggle on/off the flag for latin input\n" \
                    "/latinout\tToggle on/off the flag for latin output\n" \
                    "/web\t\tToggle on/off the flag for HTML output\n" \
                    "/exact\t\tToggle on/off the flag for exact match\n" \
                    "/quit\t\tQuit the program\n\n" \
                    "To translate a word just type it and press <Enter>\n" );
                break;
            case CMD_STATUS:
                // status
                printf("These are the effective settings:\n\n");
                printf("Separate meanings:\t%s\n", msg_onoff[dict->separateMeanings]);
                printf("Latin input:\t\t%s\n", msg_onoff[dict->latinInput]);
                printf("Latin output:\t\t%s\n", msg_onoff[dict->latinOutput]);
                printf("HTML output:\t\t%s\n", msg_onoff[dict->htmlOutput]);
                printf("Exact match:\t\t%s\n", msg_onoff[exact_match]);
                break;
            case CMD_TOG_SEPARATE:
                // separate
                dict->separateMeanings = !dict->separateMeanings;
                printf("Separate meanings are now - %s\n", msg_onoff[dict->separateMeanings]);
                break;
            case CMD_TOG_LATININ:
                // latinin
                dict->latinInput = !dict->latinInput;
                printf("Latin input is now - %s\n", msg_onoff[dict->latinInput]);
                break;
            case CMD_TOG_LATINOUT:
                // latinout
                dict->latinOutput = !dict->latinOutput;
                printf("Latin output is now - %s\n", msg_onoff[dict->latinOutput]);
                break;
            case CMD_TOG_HTML:
                // html
                dict->htmlOutput = !dict->htmlOutput;
                printf("HTML output is now - %s\n", msg_onoff[dict->htmlOutput]);
                break;
            case CMD_TOG_EXACT:
                // exact
                exact_match = !exact_match;
                printf("Exact match is now - %s\n", msg_onoff[exact_match]);
                break;
            case CMD_QUIT:
                // quit
                return 0;
            case CMD_UNKNOWN:
                printf("The numbers say that you are lucky today :)\n");
                break;
            default:
                printf("internal error :), bye for now\n");
                return 1;
        } // switch
        printf("\n");

    } // while

    return 0;
}

/////////////////////////////////////////////////////////////////////////////

INTERACTIVE_CMD check_word(const char *word)
{
    INTERACTIVE_CMD cmd = CMD_UNKNOWN;

    if(*word++ != '/'){
        cmd = NORMAL_WORD;
    } else {
        if(!strncasecmp("help", word, 4)){
            // help
            cmd = CMD_HELP;
        } else if(!strncasecmp("status", word, 6)){
            // status
            cmd = CMD_STATUS;
        } else if(!strncasecmp("separ", word, 5)){
            // separate meanings
            cmd = CMD_TOG_SEPARATE;
        } else if(!strncasecmp("latinin", word, 7)){
            // latin input
            cmd = CMD_TOG_LATININ;
        } else if(!strncasecmp("latinout", word, 8)){
            // latin output
            cmd = CMD_TOG_LATINOUT;
        } else if(!strncasecmp("web", word, 3)){
            // web output
            cmd = CMD_TOG_HTML;
        } else if(!strncasecmp("exact", word, 5)){
            // exact match
            cmd = CMD_TOG_EXACT;
        } else if(!strncasecmp("quit", word, 4)){
            // quit
            cmd = CMD_QUIT;
        }
    }

    return cmd;
}

/////////////////////////////////////////////////////////////////////////////

void cbeconfig()
{
    char parameter;
    char **msg = NULL;

    printf("configuration utility:\n\n");

    // select language
    msg = select_language();

    while(1) {
        parameter = 0;
        printf("\n");
        printf("1) %s - %s\n",  msg[MSG_SEPARATE_MEANINGS], msg[g_options.separate_meanings]);
        printf("2) %s - %s\n",  msg[MSG_LATIN_INPUT],       msg[g_options.latin_input]);
        printf("3) %s - %s\n",  msg[MSG_LATIN_OUTPUT],      msg[g_options.latin_output]);
        printf("4) %s - %s\n",  msg[MSG_HTML_OUTPUT],       msg[g_options.html_output]);
        printf("5) %s - %s\n",  msg[MSG_EXACT_MATCH],       msg[g_options.exact_match]);
        printf("6) %s - %s\n",  msg[MSG_START_INTERACTIVE], msg[g_start_interactive]);
        printf("7) %s - %s\n",  msg[MSG_DATA_DIR],          g_data_dir);
        printf("s) %s\n",       msg[MSG_SAVE_AND_QUIT]);
        printf("q) %s\n\n",     msg[MSG_QUIT_WITHOUT_SAVE]);
        printf("%s: ",          msg[MSG_CHANGE_OPTION]);

        fflush(stdin);
        scanf("%c", &parameter);

        switch (parameter){
            case '1':
                g_options.separate_meanings = !g_options.separate_meanings;
                break;
            case '2':
                g_options.latin_input = !g_options.latin_input;
                break;
            case '3':
                g_options.latin_output = !g_options.latin_output;
                break;
            case '4':
                g_options.html_output = !g_options.html_output;
                break;
            case '5':
                g_options.exact_match = !g_options.exact_match;
                break;
            case '6':
                g_start_interactive = !g_start_interactive;
                break;
            case '7':
                printf("\n%s: ", msg[MSG_PROMPT_DATA_DIR_CHANGE]);
                fflush(stdin);
                fgets(g_data_dir, FILENAME_LENGTH, stdin);
                break;
            case 's':
            case 'S':
                g_reg->setString(OPTION_DATA_DIR, g_data_dir);
                g_reg->setBool(OPTION_SEPARATE_MEANINGS, g_options.separate_meanings);
                g_reg->setBool(OPTION_LATIN_INPUT, g_options.latin_input);
                g_reg->setBool(OPTION_LATIN_OUTPUT, g_options.latin_output);
                g_reg->setBool(OPTION_HTML_OUTPUT, g_options.html_output);
                g_reg->setBool(OPTION_EXACT_MATCH, g_options.exact_match);

                printf("%s\n", msg[MSG_CONFIG_SAVED]);
                printf("%s\n", msg[MSG_QUITTING]);
                return;
            case 'q':
            case 'Q':
                printf("%s\n", msg[MSG_QUITTING]);
                return;
            default:
                printf("%s\n", msg[MSG_INCORRECT_OPTION_INDEX]);
        }; // switch
    }; // while

}

/////////////////////////////////////////////////////////////////////////////

const char *get_home()
{
    const char *path = NULL;

#ifdef WIN32
    static char bufPathName[_MAX_PATH+1];
    static char bufDrive[_MAX_DRIVE+1];
    static char bufDir[_MAX_PATH+1];
    DWORD nLen;

    nLen = ::GetModuleFileName(NULL, bufPathName, _MAX_PATH);
    if(nLen) {
        _splitpath(bufPathName, bufDrive, bufDir, NULL, NULL);
        _makepath(bufPathName, bufDrive, bufDir, NULL, NULL);
    }

    path = bufPathName;
#else
    path = getenv(ENV_HOME);
#endif // WIN32

    if( (path == NULL) || (strlen(path) < 1) ) {
        path = "./";
    }

    return path;
}

/////////////////////////////////////////////////////////////////////////////

void init_globals()
{
    const char * cfg_home;

    g_options.separate_meanings     = false;
    g_options.latin_input           = false;
    g_options.latin_output          = false;
    g_options.html_output           = false;
    g_options.exact_match           = false;
    g_start_interactive             = false;

    // Read data from config file
    cfg_home = get_home();
    g_reg = new Registry(cfg_home, REGISTRY_FILE, REGISTRY_FILE_SUFFIX);

    g_options.separate_meanings = g_reg->getBool(OPTION_SEPARATE_MEANINGS, DEFAULT_SEPARATE_MEANINGS);
    g_options.latin_input       = g_reg->getBool(OPTION_LATIN_INPUT, DEFAULT_LATIN_INPUT);
    g_options.latin_output      = g_reg->getBool(OPTION_LATIN_OUTPUT, DEFAULT_LATIN_OUTPUT);
    g_options.html_output       = g_reg->getBool(OPTION_HTML_OUTPUT, DEFAULT_HTML_OUTPUT);
    g_options.exact_match       = g_reg->getBool(OPTION_EXACT_MATCH, DEFAULT_EXACT_MATCH);

#ifdef WIN32
    strncpy(g_data_dir, g_reg->getString(OPTION_DATA_DIR, cfg_home), FILENAME_LENGTH-1);
#else
    strncpy(g_data_dir, g_reg->getString(OPTION_DATA_DIR, DICTIONARY_DATA_DIR), FILENAME_LENGTH-1);
#endif // WIN32

    g_data_dir[FILENAME_LENGTH-1] = '\0';
}

