/*
    Edit line management file
    Copyright (c) Tudor Hulubei & Andrei Pitis, May 1994

This file is part of UIT (UNIX Interactive Tools)

UIT 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, or (at your option) any later version.

UIT 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
UIT; see the file COPYING.  If not, write to the Free Software Foundation,
675 Mass Ave, Cambridge, MA 02139, USA.  */


#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include "tty.h"
#include "window.h"
#include "edit.h"


extern int  LinuxConsole;
extern int  ColorMonitor;
extern char cSection[];
extern char bwSection[];

static char etemp[256];

#define EDIT_FIELDS	3

static char EditFields[EDIT_FIELDS][40] =
{
    "CommandLineForeground",
    "CommandLineBackground",
    "CommandLineBrightness"
};

#ifdef HAVE_LINUX
static int EditColors[EDIT_FIELDS] =
{
    WHITE, BLACK, ON
};
#else
static int EditColors[EDIT_FIELDS] =
{
    WHITE, BLACK, ON
};
#endif

#define CommandLineForeground	EditColors[0]
#define CommandLineBackground	EditColors[1]
#define CommandLineBrightness	EditColors[2]


edit *edit_init(int _columns, int _begin_y, configuration *config)
{
    char *data, *section;
    int sectionptr, index, i;

    edit *this = (edit *)malloc(sizeof(edit));
    this->columns = _columns;
    this->records = this->current_record = 0;
    this->buf         = (char *)malloc(EDIT_BUFLEN);
    this->history_buf = (char *)malloc(EDIT_HISTBUFLEN);
    memset(this->history_buf, 0, EDIT_HISTBUFLEN);
    edit_reset(this);
    this->win = window_init(0, _begin_y, 1, _columns);

    if (configuration_getstatus(config) == STATUS_OK)
    {
	section = (LinuxConsole && ColorMonitor) ? cSection : bwSection;
	sectionptr = configuration_getsectionptr(config, section);
        if (sectionptr != -1)
            for (i = 0; i < EDIT_FIELDS; i++)
            {
                configuration_getfielddata(config, sectionptr, EditFields[i],
					   &data, 1, DO_SEEK);
                if (!data || (index = tty_getcolorindex(data)) == -1)
                    fprintf(stderr, "Invalid %s (%s).\n", EditFields[i], data);
	        else
                    EditColors[i] = index;
            }
    }
    return this;
} 


void edit_end(edit *this)
{
    free(this->buf); 
    free(this->history_buf);
    free(this->win);
}


char *edit_gettext(edit *this, char *dest)
{
    return strcpy(dest, this->buf + this->static_size);
}


void edit_reset(edit *this)
{
    this->buf[this->index = this->static_size = 0] = 0;
}


void edit_putch(edit *this, int key)
{
    tty_status status;

    if (key == KEY_BACKSPACE && this->index == this->static_size) return;
    if (key != KEY_BACKSPACE && this->index == EDIT_BUFLEN - 1)
    {
	tty_beep();
	return;
    }
         
    if (key == KEY_BACKSPACE)
        this->index--;
    else
    {
        if (!is_print(key)) return;
        this->buf[this->index++] = key;
    }

    this->buf[this->index] = 0;

    if (this->index < this->columns - 1)
    {
	tty_save(&status);

	tty_bright(CommandLineBrightness);
	tty_foreground(CommandLineForeground);
	tty_background(CommandLineBackground);

	if (key == KEY_BACKSPACE)
	{
	    window_cursormove(this->win, 0, this->index);
	    window_write(" ", 1);
	    window_cursormove(this->win, 0, this->index);
	}
	else
	    window_write((char *)&key, 1);

	tty_restore(&status);
    }
    else
        edit_update(this);
}


void edit_update(edit *this)
{
    unsigned len;
    tty_status status;

    tty_save(&status);

    tty_bright(CommandLineBrightness);
    tty_foreground(CommandLineForeground);
    tty_background(CommandLineBackground);
    
    memset(etemp, ' ', this->columns);
    len = (this->index >= this->columns) ? this->index - this->columns + 1 : 0;
    memcpy(etemp, this->buf + this->static_size + len,
	   this->index - this->static_size - len);
    window_cursormove(this->win, 0, 0);
    window_write(this->buf, this->static_size);
    window_write(etemp, this->columns - this->static_size);

    tty_restore(&status);
}


void edit_eos(edit *this)
{
    this->static_size = this->index;
}


void edit_setcursor(edit *this)
{
    tty_bright(CommandLineBrightness);
    tty_foreground(CommandLineForeground);
    tty_background(CommandLineBackground);
    window_cursormove(this->win, 0, strlen(this->buf));
}


void edit_del(edit *this)
{
    this->buf[this->index = this->static_size] = 0;
    edit_update(this);
}


void edit_puts(edit *this, char *str)
{
    strncpy(this->buf + this->index, str, EDIT_BUFLEN - this->static_size - 1);
    this->index = strlen(this->buf);
}


char *edit_gets(edit *this, char *static_text, char *dest, char *default_str)
{
    char key;
    struct key_struct *ks;
    int oldindex = this->index, oldstatic_size = this->static_size;
    char oldbuf[EDIT_BUFLEN];

    strcpy(oldbuf, this->buf);
    edit_reset(this);
    edit_puts(this, static_text);
    edit_eos(this);
    if (default_str) edit_puts(this, default_str);
    edit_update(this);
    edit_setcursor(this);

    for (;;)
    {
	ks  = tty_getkey(NULL);
	key = ks->key_seq[0];
	if (ks->aux_data == NULL && (is_print(key) || key == KEY_BACKSPACE))
	    edit_putch(this, key);
	else
	    break;
    }
    
    edit_gettext(this, dest);

    strcpy(this->buf, oldbuf);
    this->index = oldindex;
    this->static_size = oldstatic_size;
    edit_update(this);
    edit_setcursor(this);
    return (key == KEY_ENTER) ? dest : NULL;
}


void edit_history(edit *this, int dir)
{
    switch (dir)
    {
        case EDIT_PREVIOUS:

	    if (this->current_record) this->current_record--;
	    strncpy(this->buf + this->static_size,
		    this->history_buf + this->current_record * EDIT_RECLEN,
		    EDIT_BUFLEN - this->static_size - 1);
	    this->index = strlen(this->buf);
	    edit_update(this);
            break;
             
        case EDIT_NEXT:

            if (this->current_record < this->records)
            {
                strncpy(this->buf + this->static_size,
			this->history_buf +
			++this->current_record * EDIT_RECLEN,
			EDIT_BUFLEN - this->static_size - 1);
		this->index = strlen(this->buf);
		edit_update(this);
	    }
	    else
	        edit_del(this);
	    break;
             
        case EDIT_RECORD:

            if ((this->records &&
		 strcmp(&this->history_buf[(this->records - 1) * EDIT_RECLEN],
			this->buf + this->static_size) == 0) ||
		this->buf[this->static_size] == 0)
	    {
		this->current_record = this->records;
		break;
	    }

	    if (this->records == EDIT_HISTRECS)
	    {
		memcpy(this->history_buf, this->history_buf + EDIT_RECLEN,
		       EDIT_HISTBUFLEN - EDIT_RECLEN);
		this->records--;
	    }
	    strcpy(this->history_buf + this->records * EDIT_RECLEN,
		   this->buf + this->static_size);
	    this->current_record = ++this->records;
	    break;
             
        default:

            break;
    }
}
