
/*

 DIRU v2.0 (November 29th, 2001) -- a Russian <-> English electronic dictionary
 Copyright (c)2001 Daniel Mealha Cabrita (dancab@iname.com)
 This program is under the terms of GNU General Public License (read documentation for details).

 */

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

#include "config.h"

#include "di_tools.h"
#include "txt_filter.h"

#include "alt_unistd.h"
#ifdef OS_UNIX_ALIKE
#include <unistd.h>
#endif

/* #define USER_CHAR_KOI8R */
/* #define USER_CHAR_WIN1251 */

/* checks if there are chars > ASCII 0x7f
   returns !=0 if there are cyrillic chars, ==0 if not */
int are_there_cyrillic_chars(const char *given_string)
{
    const unsigned char *my_pos;

    my_pos=given_string;
    while(*my_pos){
        if(*my_pos++ > '\x7f')
            return(1);
    }
    return(0);
}

/* creates a copy of given string in a self-allocated mem space */
char *replicate_string(const char *given_string)
{
    char *new_buff;

    if(new_buff=malloc((strlen(given_string)+1)*sizeof(char)))
        strcpy(new_buff, given_string);
    return(new_buff);
}

/* auxiliary function which converts a given text
   (source standard defined at compilation time) to koi8
   returns: NULL, given_string or pointer to elsewhere
   (!!!) you don't need to free() given_string anymore, just
   the returned pointer, if != NULL */
/* if do_not_free!=0 do not free given_string
   (for the case given_string reflects a argv[], por example) */
/* if transliteration!=0 the provided data is transliterated */
const char *convert_to_koi8(const char *given_string, int do_not_free, int transliteration)
{
	const char *new_buff=NULL;

	if(!given_string)
		return(NULL);
	if(transliteration){
		new_buff=detransliterate_to_koi8(given_string);
	}else{
#ifdef USER_CHAR_KOI8R
		new_buff=replicate_string(given_string);
#endif
#ifdef USER_CHAR_WIN1251
		new_buff=convert_between_koi8_win1251(replicate_string(given_string), 1);
#endif
	}
	if(!do_not_free)
		free_text(given_string);
	return(new_buff);
}

/* auxiliary function which converts a given text
   (source standard defined at compilation time) from koi8
   returns: NULL, given_string or pointer to elsewhere
   (!!!) you don't need to free() given_string anymore, just
   the returned pointer, if != NULL */
/* if do_not_free!=0 do not free given_string
   (for the case given_string reflects a argv[], por example) */
/* if transliteration!=0 the output data is transliterated */
const char *convert_from_koi8(const char *given_string, int do_not_free, int transliteration)
{
	const char *new_buff=NULL;

	if(!given_string)
		return(NULL);
	if(transliteration){
		new_buff=transliterate_from_koi8(given_string);
	}else{
#ifdef USER_CHAR_KOI8R
		new_buff=replicate_string(given_string);
#endif
#ifdef USER_CHAR_WIN1251
		new_buff=convert_between_koi8_win1251(replicate_string(given_string), 0);
#endif
	}
	if(!do_not_free)
		free_text(given_string);
	return(new_buff);
}

void message_help(void)
{
    printf("DIRU v2.0 (November 29th, 2001)\n"
           "a Russian <-> English electronic dictionary\n"
           "Copyright (c)2001 Daniel Mealha Cabrita (dancab@iname.com)\n"
           "This program is under the terms of GNU General Public License (read documentation for details).\n\n");
    printf(
           "\nInvalid/missing parameter.\n\nUsage: diru [options] <word_to_find>\n\n"
           "Options: -r   translate Russian -> English\n"
           "         -e   translate English -> Russian\n"
           "         -c   cyrillic output\n"
           "         -t   transliterated mode (default)\n"
           "         -s   line input (stdin) -- stop it by typing \".\"\n"
           "\n");
}

/* this is just an example on how a dictionary code can be implemented
   using these routines */
int main(int argc, char *argv[])
{
    struct t_dictionary *my_dictionary;
    const char *query_word=NULL; /* the word which the user provided */
    int source_lang=0; /* 0-()unknown 1-(r)ussian 2-(e)nglish */
    int use_transliteration=1; /* transliterate by default */
    int line_input=0; /* disabled by default */
    int first_time_loop=1;

    if((argc!=2)&&(argc!=3)){
        message_help();
        return(1);
    }

#ifdef DICTIONARY_LOCATION
    if(!(my_dictionary=load_dictionary(DICTIONARY_LOCATION))){
#else
    if(!(my_dictionary=load_dictionary("Mueller24.koi"))){
#endif
        printf("Unable to load dictionary to memory!\n(out of memory or I/O error)\n\n");
        return(2);
    }


	{
		int myopt;

		while((myopt=alt_getopt(argc, argv, "rects"))!=EOF){
			switch(myopt){
			case 'r': source_lang=1; break;
			case 'e': source_lang=2; break;
			case 'c': use_transliteration=0; break;
			case 't': use_transliteration=1; break;
			case 's': line_input=1; break;
			}
		}

		if(alt_optind<argc)
			query_word=argv[alt_optind];
	}

	while(first_time_loop || line_input){
		int word_found_already=0; /* used when no lang specified (tries first en then ru) */
		char line_query_buffer[100];

		first_time_loop=0;

		if(line_input){
			query_word=line_query_buffer;
			scanf("%99s", line_query_buffer);
			if(!strcmp(".", query_word)){
				printf("\n");
				return(0);
			}
		}else if(!query_word){
         message_help();
         return(1);
		}

    /* EN */
    /* if source language is undefined, tries english only if no cyrillic
       chars present for speedup */
    if((source_lang==2)||((!source_lang) && (!are_there_cyrillic_chars(query_word)))){
        const char *found_definition;

        if(found_definition=convert_from_koi8(query_english_word(my_dictionary, query_word), 0, use_transliteration)){
            if(!source_lang)
                printf("English -> Russian\n");
            printf("Word found.\n\n%s\n%s\n\n", query_word, found_definition);
            word_found_already=1;
            free_text(found_definition);
        }else{ /* word not found. try to find close words, if the user specified 'english' */
            if(source_lang){
                const char *possible_words;

                if(possible_words=find_possible_words_en(my_dictionary, query_word)){
                    if(*possible_words){
                        printf("Word not found.\n\nPossible matches for \"%s\":\n%s\n\n", query_word, possible_words);
                    }else{
                        printf("Word not found.\n\nNo possible matches found.\n\n");
                    }
                    free_text(possible_words);
                }
            }
        }
    }

    /* RU */
    if(((source_lang==1)||(!source_lang))&&!word_found_already){
        const char *found_definition;
        const char *query_word_converted;

        query_word_converted=convert_to_koi8(query_word, 1, use_transliteration);
        if(found_definition=convert_from_koi8(query_russian_word(my_dictionary, query_word_converted), 0, use_transliteration)){
            if(!source_lang)
                printf("Russian -> English\n");
            printf("Word found.\n\n%s\n%s\n\n", query_word, found_definition);
            free_text(found_definition);
        }else{ /* word not found. try to find close words */
            const char *possible_words;

            if(possible_words=convert_from_koi8(find_possible_words_ru(my_dictionary, query_word_converted), 0, use_transliteration)){
                if(*possible_words){
                    printf("Word not found.\n\nPossible matches for \"%s\":\n%s\n\n", query_word, possible_words);
                }else{
                    printf("Word not found.\n\nNo possible matches found.\n\n");
                }
                free_text(possible_words);
            }
        }
        free_text(query_word_converted);
    }

	}

	unload_dictionary(my_dictionary);
	return(0);
}
