#include<conio.h>
#include<ctype.h>
#include<direct.h>
#include<errno.h>
#include<fcntl.h>
#include<io.h>
#include<malloc.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<sys/stat.h>

/* #define __OS2 */

   #ifdef __OS2
        #define CLEAR()      printf("\033[2J")                   /*Lschen des Monitors*/
   #else
    #define CLEAR()      if (system("cls")) system("clear");
   #endif

void back_up(char *filename);
int f_strlen(char *buffer);
int comp_number_number(const void *b1, const void *b2);
int comp_number_wert(const void *b1, const void *b2);
int comp_number_zufall(const void *b1, const void *b2);
int print_number(int lang, int ex, int counter, int sentence);
int up(int min, int max);


typedef struct vocal
    {
    int number;       /*  0 */
    int wert;           /*  4 */
    int zufalls_wert;   /*  8 */
    char *las;          /* 12 */
    char *espagna;      /* 16 */
    char *frase;        /* 20 */
    char *die;          /* 24 */
    char *german;       /* 28 */
    char *satz;         /* 32 */
    char *remark;
    } vocal;

    struct vocal *prof_list = NULL;




int main (int argc, char *argv[])
    {
    char *begin = NULL;
    int counter = 0;
    int coma_counter = 0;
    char *end = NULL;
    int ex = 0;
    int first_round = 0;
    int key = 0;
    int lang = 0;
    int leave = 0;
    int len = 0;
    char *line_end = NULL;
    char *line_ptr = NULL;
    int num = 0;
    int number = 0;
    int number_of_words = 0;
    int num_vokabel = 0;
    int rest = 0;
    int sentence = 1;
    int word = 0;
    char work_filename[260];
    int written = 0;
    char vokabel_filename[260];

    struct stat vokabel_buffer;
    int vokabel_buffer_size = 0;
    char *vokabel_memory = NULL;
    struct stat vokabel_stat_buffer;
    struct stat work_stat_buffer;
    struct stat work_buffer;
    int temp_int = 0;
    char wish [260];
    int wished_number_of_words = 0;
    int word_counter = 0;
    int work_buffer_size = 0;
    char *work_memory = NULL;

    FILE *vokabel_stream = NULL;
    FILE *work_stream = NULL;


    if(argc == 1)
        {
        printf("bitte Filenamen eingeben. Zum Beispiel Fritz\n");
        fgets(work_filename, 260, stdin);
        len = f_strlen(work_filename);
        if(len)
            {
            len--;
            }
        memset(&work_filename[len], '\0',1);
        work_stream = fopen(work_filename, "r+");
        if(! work_stream)
            {
            work_stream = fopen(work_filename, "a+");
            }
        printf("bitte Vokabelfile eingeben:\n");
        fgets(vokabel_filename, 260, stdin);
        len = f_strlen(vokabel_filename);
        if(len)
            {
            len--;
            }
        memset(&vokabel_filename[len], '\0',1);
        while(! vokabel_filename)
            {
            printf("bitte Vokabelfile eingeben:\n");
            fgets(vokabel_filename, 260, stdin);
            len = f_strlen(vokabel_filename);
            if(len)
                {
                len--;
                }
            memset(&vokabel_filename[len], '\0',1);
            fopen(vokabel_filename, "r");
            }
        if(!vokabel_stream)
            {
            vokabel_stream = fopen(vokabel_filename, "r");
            }
        }


    else if(argc == 2)
        {
        strcpy(work_filename, argv[1]);
        work_stream = fopen(work_filename, "r+");
        printf("bitte Vokabelfile eingeben:\n");
        fgets(vokabel_filename, 260, stdin);
        len = f_strlen(vokabel_filename);
        if(len)
            {
            len--;
            }
        memset(&vokabel_filename[len], '\0',1);
        while(! vokabel_filename)
            {
            printf("bitte Vokabelfile eingeben:\n");
            fgets(vokabel_filename, 260, stdin);
            len = f_strlen(vokabel_filename);
            if(len)
                {
                len--;
                }
            memset(&vokabel_filename[len], '\0',1);
            vokabel_stream = fopen(vokabel_filename, "r");
            }
        if(!vokabel_filename)
            {
            vokabel_stream = fopen(vokabel_filename, "r");
            }
        }
    else
        {
        strcpy(work_filename, argv[1]);
        work_stream = fopen(work_filename, "r");
        strcpy(vokabel_filename, argv[2]);
        vokabel_stream = fopen(vokabel_filename, "r");
        }



    stat(work_filename, &work_stat_buffer);
    stat(vokabel_filename, &vokabel_stat_buffer);

    if(work_stat_buffer.st_size < 9216)
        {
        work_buffer_size = 9216;
        }

    vokabel_buffer_size = vokabel_stat_buffer.st_size + 9216;
    vokabel_memory = (char*) calloc(vokabel_stat_buffer.st_size + 1024, sizeof(char));
    num_vokabel = fread(vokabel_memory, sizeof(char), vokabel_buffer_size, vokabel_stream);
    fclose(vokabel_stream);
    rest = num_vokabel;
    line_ptr = vokabel_memory;
    begin = vokabel_memory;

    while(begin < &vokabel_memory[num_vokabel])
        {
        line_end = memchr(begin, '\n', rest);
        if(line_end)
            {
            memset(line_end, '\0', 1);
            number_of_words++;
            }
        else
            {
            number_of_words++;
            break;
            }
        if(line_end - begin < 3)
            {
            number_of_words--;
            }
        begin = ++line_end;
        rest = &vokabel_memory[num_vokabel] - begin;
        }

    work_buffer_size = work_stat_buffer.st_size + number_of_words * 2 * sizeof(int);

    work_memory = (char*) calloc(work_buffer_size, sizeof(char));            /*speicher reservieren*/
    num = fread(work_memory, sizeof(char), work_stat_buffer.st_size, work_stream);
    fclose(work_stream);

    prof_list = (struct vocal*)calloc(number_of_words + 1024, sizeof(struct vocal));

    if(! num)
        {
        for(counter = 0; counter < number_of_words ; counter++)
            {
            memcpy(&prof_list[counter].number, &counter, sizeof(int));
            memset(&prof_list[counter].wert, '\0', sizeof(int));           /* wert zuweisen */
            prof_list[counter].zufalls_wert = rand();
            }
         }


    else
        {
        rest = num;
        end = memchr(work_memory, 32, rest);
        memset(end, '\0', 1);
        temp_int = atoi(work_memory);
        memcpy(&prof_list[counter].number, &temp_int, sizeof(int));
        begin = ++end;
        rest = &work_memory[num] - end;
        end = memchr(begin, '\n', rest);
        memset(end, '\0', 1);
        temp_int = atoi(begin);
        memcpy(&prof_list[counter].wert, &temp_int, sizeof(int));           /* wert zuweisen */
        prof_list[counter].zufalls_wert = rand();
        begin = ++end;
        rest = &work_memory[num] - end;
        counter++;


        while(end <= &work_memory[num] && counter < number_of_words)
            {
            end = memchr(begin, 32, rest);
            if(! end)
                {
                break;
                }
            memset(end, '\0', 1);
            temp_int = atoi(begin);
            memcpy(&prof_list[counter].number, &temp_int, sizeof(int));
            begin = ++end;
            rest = &work_memory[num] - end;
            end = memchr(begin, '\n', rest);
            memset(end, '\0', 1);
            temp_int = atoi(begin);
            memcpy(&prof_list[counter].wert, &temp_int, sizeof(int));           /* wert zuweisen */
            prof_list[counter].zufalls_wert = rand();
            begin = ++end;
            rest = &work_memory[num] - end;
            counter++;
            if(end >= &work_memory[num])
                {
                break;
                }
            }


        while(counter < number_of_words)
            {
            memcpy(&prof_list[counter].number, &counter, sizeof(int));
            memset(&prof_list[counter].wert, '\0', sizeof(int));           /* wert zuweisen */
            prof_list[counter].zufalls_wert = rand();
            counter++;
            }
        }

    free(work_memory);

    for(counter = 0; counter < number_of_words; counter++)
        {
        coma_counter = 0;
        if(counter)
            {
            line_ptr = line_end + 1;
            }

        len = f_strlen(line_ptr);
        line_end = &line_ptr[len];
        end = line_ptr;

        if(memcmp(line_ptr, "\"", 1) == 0)
            {
            begin = &line_ptr[1];
            rest = len;
            end = memchr(begin, '\"', rest);
            memset(end, '\0', 1);
            prof_list[counter].las = begin;
            coma_counter++;
            }
        else
            {
            prof_list[counter].las = line_end;
            end = line_ptr;
            coma_counter++;
            }

        if(memcmp(line_ptr,",,\"", 3) == 0)
            {
            prof_list[counter].espagna = line_end;
            coma_counter++;
            }
        else if(end == line_ptr && (memcmp(end, ",\"", 2) == 0))
            {
            begin =  end + 3;
            rest = line_end - end;
            end = memchr(begin, '\"', rest);
            memset(end, '\0', 1);
            prof_list[counter].espagna = begin;
            coma_counter++;
            }
        else if(memcmp(end + 1, ",\"", 2) == 0)
            {
            begin =  end + 3;
            rest = line_end - end;
            end = memchr(begin, '\"', rest);
            memset(end, '\0', 1);
            prof_list[counter].espagna = begin;
            coma_counter++;
            }
        else
            {
            prof_list[counter].espagna = line_end;
            end++;
            coma_counter++;
            }


        if(memcmp(end + 1, ",\"", 2) == 0)
            {
            begin =  end + 3;
            rest = line_end - end;
            end = memchr(begin, '\"', rest);
            memset(end, '\0', 1);
            prof_list[counter].frase = begin;
            coma_counter++;
            }
        else if(memcmp(end + 1, ",,", 2) == 0)
            {
            prof_list[counter].frase = line_end;
            end++;
            coma_counter++;
            }


        if(memcmp(end + 1, ",\"", 2) == 0)
            {
            begin =  end + 3;
            rest = line_end - end;
            end = memchr(begin, '\"', rest);
            memset(end, '\0', 1);
            prof_list[counter].die = begin;
            coma_counter++;
            }
        else if(memcmp(end + 1, ",,", 2) == 0)
            {
            prof_list[counter].die = line_end;
            end++;
            coma_counter++;
            }


        if(memcmp(end + 1, ",\"", 2) == 0)
            {
            begin =  end + 3;
            rest = line_end - end;
            end = memchr(begin, '\"', rest);
            memset(end, '\0', 1);
            prof_list[counter].german = begin;
            coma_counter++;
            }
        else if(memcmp(end + 1, ",,", 2) == 0)
            {
            prof_list[counter].german = line_end;
            end++;
            coma_counter++;
            }

        if(memcmp(end + 1, ",\"", 2) == 0)
            {
            begin =  end + 3;
            rest = line_end - end;
            end = memchr(begin, '\"', rest);
            if(end == NULL)
                {
                CLEAR();
                printf("Error in line %i missing "" at the end\n%s %s %s %s %s\n", counter + 1, prof_list[counter].las, prof_list[counter].espagna, prof_list[counter].frase, prof_list[counter].die, prof_list[counter].german, prof_list[counter].satz);
                getch();
                }
            memset(end, '\0', 1);
            prof_list[counter].satz = begin;
            coma_counter++;
            }
        else if(memcmp(end + 1, ",,", 2) == 0)
            {
            prof_list[counter].satz = line_end;
            end++;
            coma_counter++;
            }

        if(memcmp(end + 1, ",\"", 2) == 0)
            {
            begin =  end + 3;
            rest = line_end - end;
            end = memchr(begin, '\"', rest);
            if(end == NULL)
                {
                CLEAR();
                printf("Error in line %i missing "" at the end\n%s %s %s %s %s\n", counter + 1, prof_list[counter].las, prof_list[counter].espagna, prof_list[counter].frase, prof_list[counter].die, prof_list[counter].german, prof_list[counter].satz);
                getch();
                }
            memset(end, '\0', 1);
            prof_list[counter].remark = begin;
            coma_counter++;
            }
        else if(memcmp(end + 1, ",,", 2) == 0)
            {
            prof_list[counter].remark = line_end;
            coma_counter++;
            }
        else
            {
            prof_list[counter].remark = line_end;
            }




        if(coma_counter < 5)
            {
            CLEAR();
            printf("Error in line %i\n%s %s %s %s %s %s\n", counter + 1, prof_list[counter].las, prof_list[counter].espagna, prof_list[counter].frase, prof_list[counter].die, prof_list[counter].german, prof_list[counter].satz);
            getch();
            }
        }


    CLEAR();
    printf("Es sind %i Wrter, bitte geben Sie an, wieviele Worter sie haben mchten:\nWenn sie alle haben mchten, dann geben sie 0 ein\n", number_of_words);
    memset(wish, '\0', 260);
    fgets(wish, 260, stdin);
    wished_number_of_words = atoi(wish);
    if(!wished_number_of_words || wished_number_of_words >= number_of_words)
        {
        wished_number_of_words = number_of_words;
        }


    qsort((struct vocal*)prof_list, wished_number_of_words, sizeof(struct vocal), comp_number_wert);
    word_counter = 0;


    while(word_counter < number_of_words )
        {
        if((word_counter + 10) < wished_number_of_words )
            {
            qsort((struct vocal*)&prof_list[word_counter], 10, sizeof(struct vocal), comp_number_zufall);
            word_counter += 10;
            }
        else
            {
            rest = wished_number_of_words - word_counter;
            if(rest > 1)
                {
                qsort((struct vocal*)&prof_list[word_counter], rest, sizeof(struct vocal), comp_number_zufall);
                }
            break;
            }
        }

    counter = 0;
    number = prof_list[counter].number;
    CLEAR();
    ex = print_number(lang, ex, counter, sentence);


    while(! leave)
        {

        if(key == 'w' || key == 'W')     /* Sprache wechseln*/
            {
            if(lang == 0)
                {
                lang = 1;
                }
            else
                {
                lang = 0;
                }
            }

        if(key == 's' || key == 'S')
            {
            if(sentence)
                {
                sentence = 0;
                }
            else
                {
                sentence = 1;
                }
            }

        if(key == '8' || key == 56) /* Page Up, number stark erhhen */
            {
            number = prof_list[counter].number;
            ex = print_number(lang, ex,  counter, sentence);
            if(ex == 0)
                {
                counter++;
                }
            else
                {
                if(counter)
                    {
                    prof_list[counter - 1].wert += up(8, 16);
                    }
                else
                    {
                    prof_list[counter].wert += up(8, 16);
                    }
                }
            }

        if(key == 'x' || key == 'X' || key == 88 || key == 120) /* quasi so start erhhen, dass das Wort ausgeschlossen wird. */
            {
            number = prof_list[counter].number;
            ex = print_number(lang, ex,  counter, sentence);
            if(ex == 0)
                {
                counter++;
                }
            else
                {
                if(counter)
                    {
                    prof_list[counter - 1].wert += up(90, 110);
                    }
                else
                    {
                    prof_list[counter].wert += up(90, 110);
                    }
                }
            }

        if(key == '7' || key == 55) /* Page Up, number mssig erhhen */
            {
            number = prof_list[counter].number;
            ex = print_number(lang, ex,  counter, sentence);
            if(ex == 0)
                {
                counter++;
                }
            else
                {
                if(counter)
                    {
                    prof_list[counter - 1].wert += up(3, 7);
                    }
                else
                    {
                    prof_list[counter].wert += up(3, 7);
                    }
                }
            }

        if(key == '9' || key == 57) /* Page Up, number sehr stark erhhen 9*/
            {
            word = prof_list[counter].number;
            ex = print_number(lang, ex,  counter, sentence);
            if(ex == 0)
                {
                counter++;
                }
            else
                {
                if(counter)
                    {
                    prof_list[counter - 1].wert += up(17, 32);
                    }
                else
                    {
                    prof_list[counter].wert += up(17, 32);
                    }
                }
            }


        if(key == '2' || key == 50) /* page down, number stark erniedrigen 2*/
            {
            word = prof_list[counter].number;
            ex = print_number(lang, ex, counter, sentence);
            if(ex == 0)
                {
                counter++;
                }
            else
                {
                if(counter)
                    {
                    prof_list[counter - 1].wert -= 10;
                    }
                else
                    {
                    prof_list[counter].wert -= 10;
                    }
                }
            }

        if(key == '3' || key == 51) /* page down, number mssig erniedrigen 3*/
            {
            word = prof_list[counter].number;
            ex = print_number(lang, ex,  counter, sentence);
            if(ex == 0)
                {
                counter++;
                }
            else
                {
                if(counter)
                    {
                    prof_list[counter - 1].wert -= 5;
                    }
                else
                    {
                    prof_list[counter].wert -= 5;
                    }
                }
            }

        if(key == '1' || key == 49) /* F9, number stark erniedrigen 1*/
            {
            word = prof_list[counter].number;
            ex = print_number(lang, ex, counter, sentence);
            if(ex == 0)
                {
                counter++;
                }
            else
                {
                if(counter)
                    {
                    if(prof_list[counter - 1].wert < 25)
                        {
                        prof_list[counter - 1].wert = 0;
                        }
                    else
                        {
                        prof_list[counter - 1].wert -= 25;
                        }
                    }
                else
                    {
                    if(prof_list[counter].wert < 25)
                        {
                        prof_list[counter].wert = 0;
                        }
                    else
                        {
                        prof_list[counter].wert -= 25;
                        }
                    }
                }
            }


        if(key == 13 || key == 10 || key == ' ' || key == 32) /* enter, number korrekt */
            {
            word = prof_list[counter].number;
            ex = print_number(lang, ex, counter, sentence);
            if(ex == 0)
                {
                counter++;
                }
            else
                {
                if(counter)
                    {
                    prof_list[counter - 1].wert++;
                    }
                else
                    {
                    prof_list[counter].wert++;
                    }
                }
            }

        if(key == '-' || key == '4' || key == 45 || key == 52) /* number falsch - */
            {
            word = prof_list[counter].number;
            ex = print_number(lang, ex, counter, sentence);
            if(ex == 0)
                {
                counter++;
                }
            else
                {
                if(counter)
                    {
                    if(prof_list[counter - 1].wert)
                        {
                        if(prof_list[counter - 1].wert > 1)
                            {
                            prof_list[counter - 1].wert -= 2;
                            }
                        else
                            {
                            prof_list[counter - 1].wert--;
                            }
                        }
                    }
                else
                    {
                    if(prof_list[counter].wert)
                        {
                        if(prof_list[counter].wert > 1)
                            {
                            prof_list[counter].wert -= 2;
                            }
                        else
                            {
                            prof_list[counter].wert--;
                            }
                        }
                    }
                }
            }



        if(key == 'v' || key == 'V' || key == 118 || key == 86) /*zurck zum vorherigen Datensatz V*/
            {
            key = 0;
            if(counter)
                {
                counter--;
                }
            word = prof_list[counter].number;
            ex = 0;
            CLEAR();
            ex = print_number(lang, ex, counter, sentence);
            }

        if(counter >= number_of_words && ex == 1)
            {
            leave = 1;
            break;
            }

        if(key == 27 || key == 113 || key == 81)
            {
            break;
            }
        key = getch();

        }


    qsort((struct vocal*)prof_list, number_of_words, sizeof (struct vocal), comp_number_number);
    back_up(work_filename);
    work_stream = fopen(work_filename, "w");
    for(counter = 0; counter < number_of_words; counter++)
        {
        fprintf(work_stream, "%i %i\n", prof_list[counter].number, prof_list[counter].wert);
        }

    fclose(work_stream);
    free(prof_list);
    free(vokabel_memory);

    return(0);
    }

int print_number(int lang, int ex, int counter, int sentence)
    {
    if(lang == 0 && ex == 0 && sentence)
        {
        CLEAR();
        printf("%s\t%s\t%i\t%i\n\n%s\n\n\n\n", prof_list[counter].las, prof_list[counter].espagna, prof_list[counter].wert, counter, prof_list[counter].frase);
        }
    if(lang == 0 && ex == 0 && !sentence)
        {
        CLEAR();
        printf("%s\t%s\t%i\t%i\n\n_\n\n\n\n", prof_list[counter].las, prof_list[counter].espagna, prof_list[counter].wert, counter);
        }
    if(lang == 0 && ex == 1 && sentence)
        {
        printf("%s\t%s\n\n%s\n\n%s\n", prof_list[counter].die, prof_list[counter].german, prof_list[counter].satz, prof_list[counter].remark);
        }
    if(lang == 0 && ex == 1 && ! sentence)
        {
        printf("%s\t%s\n\n_\n\n%s\n", prof_list[counter].die, prof_list[counter].german, prof_list[counter].remark);
        }


    if(lang == 1 && ex == 0 && sentence)
        {
        CLEAR();
        printf("%s\t%s\t%i\t%i\n\n%s\n\n\n\n", prof_list[counter].die, prof_list[counter].german, prof_list[counter].wert, counter, prof_list[counter].satz);
        }
    if(lang == 1 && ex == 0 && !sentence)
        {
        CLEAR();
        printf("%s\t%s\t%i\t%i\n\n_\n\n\n\n", prof_list[counter].die, prof_list[counter].german, prof_list[counter].wert, counter);
        }

    if(lang == 1 && ex == 1 && sentence)
        {
        printf("%s\t%s\n\n%s\n\n%s\n", prof_list[counter].las, prof_list[counter].espagna, prof_list[counter].frase, prof_list[counter].remark);
        }
    if(lang == 1 && ex == 1 && !sentence)
        {
        printf("%s\t%s\n\n_\n\n%s\n", prof_list[counter].las, prof_list[counter].espagna, prof_list[counter].remark);
        }

    if(ex == 1)
        {
        ex = 0;
        }
    else
        {
        ex = 1;
        }
    return(ex);
    }


int f_strlen(char *buffer)
    {
    int counter = 0;
    int leave = 1;

    if(buffer == NULL)
        {
        leave = 0;
        }

    while(leave)
        {
        leave = memcmp(&buffer[counter], "\0", 1);
        if(leave)
            {
            counter++;
            }
        }
    return(counter);
    }

int comp_number_number(const void *b1, const void *b2)
    {
    int value = 0;
    struct vocal *sb1 = (struct vocal *)b1;
    struct vocal *sb2 = (struct vocal *)b2;

    if(sb1->number < sb2->number)
        {
        value = -1;
        }
    else if(sb1->number > sb2->number)
        {
        value = 1;
        }
    return(value);
    }


int comp_number_wert(const void *b1, const void *b2)
    {
    int value = 0;
    struct vocal *sb1 = (struct vocal *)b1;
    struct vocal *sb2 = (struct vocal *)b2;

    if(sb1->wert < sb2->wert)
        {
        value = -1;
        }
    else if(sb1->wert > sb2->wert)
        {
        value = 1;
        }
    return(value);
    }





int comp_number_zufall(const void *b1, const void *b2)
    {
    int value = 0;
    struct vocal *sb1 = (struct vocal *)b1;
    struct vocal *sb2 = (struct vocal *)b2;

    if(sb1->zufalls_wert < sb2->zufalls_wert)
        {
        value = -1;
        }
    else if(sb1->zufalls_wert > sb2->zufalls_wert)
        {
        value = 1;
        }
    return(value);
    }


int up(int min, int max)
    {
    int number = 0;
    number = rand();
    while(number < min || number > max)
        {
        if(number < min)
            {
            number += (min / 5);
            }
        else if(number > max)
            {
            number = number / 2;
            }
        }
    return(number);
    }

void back_up(char *filename)
    {
    char file[_MAX_PATH];
    char *back_up = NULL;
    char old_file[_MAX_PATH];

    strcpy(file, filename);
    back_up = strcat(file, "_05");
    if(access(back_up, 00) == 0)
        {
        remove(file);
        }
    strcpy(old_file, filename);
    back_up = strcat(old_file, "_04");
    if(access(old_file, 00) == 0)
        {
        rename(old_file, file);
        }

    strcpy(file, filename);
    back_up = strcat(file, "_04");
    strcpy(old_file, filename);
    back_up = strcat(old_file, "_03");
    if(access(old_file, 00) == 0)
        {
        rename(old_file, file);
        }

    strcpy(file, filename);
    back_up = strcat(file, "_03");
    strcpy(old_file, filename);
    back_up = strcat(old_file, "_02");
    if(access(old_file, 00) == 0)
        {
        rename(old_file, file);
        }

    strcpy(file, filename);
    back_up = strcat(file, "_02");
    strcpy(old_file, filename);
    back_up = strcat(old_file, "_01");
    if(access(old_file, 00) == 0)
        {
        rename(old_file, file);
        }

    strcpy(file, filename);
    back_up = strcat(file, "_01");
    rename(filename, old_file);
    }


