
#include "gkbd_histo.h"

#include "gsys/cfc.h"
#include "gcore/gcommand_line.h"

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

/* 1000 for command history, 1 for current line */
#define HISTO_MAX 1001
static char histo_list[HISTO_MAX][MAXBUF];
static int histo_count = 0;
static int histo_end = 0;
static int histo_index = 0;
static int histo_disabled = 0;
static int histo_skip_duplicates = 1;
static int histo_new_search = 0;
static int histo_do_not_search = 0;

void gkbd_histo_enable( )
{
    histo_disabled = 0;
}

void gkbd_histo_disable( )
{
    histo_disabled = 1;
}

void gkbd_histo_reset( )
{
    if (histo_disabled)
        return;

    histo_index = histo_end;
}

static void histo_copy_line( char *line)
{
    /* skip blanks */
    while (*line == ' ')
        line++;
    strcpy( histo_list[histo_end], line);
}

void gkbd_histo_push( char *line)
{
    if (histo_disabled)
        return;

    histo_new_search = 0;
    histo_copy_line( line);
    if (!histo_list[histo_end][0])
        return;
    if (histo_end < HISTO_MAX - 1) {
        histo_end++;
        if (histo_count < histo_end)
            histo_count = histo_end;
    } else {
        histo_end = 0;
        histo_count = HISTO_MAX;
    }
    histo_index = histo_end;
}

void gkbd_histo_pop( )
{
    int new_histo_end;

    if (histo_disabled)
        return;

    if (histo_end > 0)
        new_histo_end = histo_end - 1;
    else
        new_histo_end = HISTO_MAX - 1;

#if 0
    if (strcmp( histo_list[new_histo_end], cur_line)) {
        /* different line */
        return;
    }
#endif

    histo_index = histo_end = new_histo_end;
    strcpy( histo_list[histo_end], "");
}

static int histo_do_not_match( int l)
{
    return strncasecmp( histo_list[histo_index], histo_list[histo_end], l);
}

void gkbd_histo_prev( char *line)
{
    int last_index;
    int l;
    static char new_search_string[MAXBUF];

    if (histo_disabled)
        return;

    if (histo_index == histo_end) {
        /* keep current line */
        histo_copy_line( line);
    }
    l = strlen( histo_list[histo_end]);
    if (l) {
        if (histo_index == histo_end) {
            if (histo_new_search == 1
            && !strcmp( new_search_string, histo_list[histo_end])) {
                /* same search without match then go previous normally */
                histo_do_not_search = 1;
                histo_new_search = 0;
                l = 0;
            } else {
                histo_do_not_search = 0;
                histo_new_search = 1;
                strcpy( new_search_string, histo_list[histo_end]);
            }
        } else {
            if (histo_do_not_search)
                l = 0;
            histo_new_search = 0;
        }
    } else {
        histo_do_not_search = 0;
        histo_new_search = 0;
    }

    last_index = histo_index;
    do {
        if (histo_index == histo_end + 1
        || (histo_index == 0
        && (histo_count < HISTO_MAX || histo_end == HISTO_MAX - 1))) {
            if (l)
                histo_index = last_index;
            break;
        }
        if (histo_index == 0) {
            histo_index = HISTO_MAX - 1;
        } else {
            histo_index--;
        }
    } while ((histo_skip_duplicates && !strcmp( histo_list[histo_index], histo_list[last_index]))
     || (l && histo_do_not_match( l)));
    strcpy( line, histo_list[histo_index]);
}

void gkbd_histo_next( char *line)
{
    int last_index;
    int l;

    if (histo_disabled)
        return;

    if (histo_index == histo_end) {
        /* keep current line */
        histo_copy_line( line);
    }
    l = strlen( histo_list[histo_end]);
    if (histo_do_not_search)
        l = 0;

    last_index = histo_index;
    do {
        if (histo_index == histo_end)
            break;
        if (histo_index == HISTO_MAX - 1) {
            histo_index = 0;
        } else {
            histo_index++;
        }
    } while ((histo_skip_duplicates && !strcmp( histo_list[histo_index],
     histo_list[last_index])) || (l && histo_do_not_match( l)));
    strcpy( line, histo_list[histo_index]);
}

static char s_history_filename[1024] = { '\0' };

void gkbd_histo_set_filename( char *filename)
{
    strcpy( s_history_filename, filename);
}

#define gkbd_f_histo_set_filename CFC_EXPORT_NAME( gkbd_f_histo_set_filename)
void CFC_API gkbd_f_histo_set_filename( CFC_FString filename CFC_DECLARE_STRING_LENGTH(filename))
{
    CFC_f2c_strcpy( s_history_filename, filename,
     CFC_STRING_LENGTH_MIN( filename, sizeof( s_history_filename)));
}

void gkbd_histo_save( )
{
    FILE *fp;
    int i;

    if (!s_history_filename[0])
        /* gkbd_histo_set_filename not called */
        return;
    fp = fopen( s_history_filename, "w");
    if (fp == NULL)
        return;
    if (histo_count < HISTO_MAX) {
        for (i = 0; i < histo_count; i++)
            fprintf( fp, "%s\n", histo_list[i]);
    } else {
        for (i = histo_end + 1; i < HISTO_MAX; i++)
            fprintf( fp, "%s\n", histo_list[i]);
        for (i = 0; i < histo_end; i++)
            fprintf( fp, "%s\n", histo_list[i]);
    }
    fclose( fp);
}

void gkbd_histo_load( )
{
    FILE *fp;
    int i;
    char line[MAXBUF];

    if (!s_history_filename[0])
        /* gkbd_histo_set_filename not called */
        return;
    fp = fopen( s_history_filename, "r");
    if (fp == NULL)
        return;
    i = 0;
    while (fgets( line, sizeof( line), fp) != NULL) {
        int l = strlen( line);
        if (l <= 1)
            continue;
        /* suppress line feed */
        line[l - 1] = '\0';
        strcpy( histo_list[i++], line);
        if (i == HISTO_MAX)
            break;
    }
    histo_count = i;
    if (histo_count == HISTO_MAX)
        histo_end = 0;
    else
        histo_end = histo_count;
    histo_index = histo_end;
    fclose( fp);
}

