/*
 * edline.c:
 * Text input on a line of the screen.
 *
 */

static const char rcsid[] = "$Id$";

#include <ctype.h>
#include <curses.h>
#include <string.h>

#include "iftop.h"

static int min(const int a, const int b) {
    return a < b ? a : b;
}

/* edline:
 * Display on line linenum of the screen the prompt and allow the user to input
 * a line of text, whose initial value is as supplied. */
char *edline(int linenum, const char *prompt, const char *initial) {
    int xstart, slen, off = 0, pos, i, c;
    char *str;
    
    xstart = strlen(prompt) + 2;

    if (initial) {
        str = xmalloc(slen = strlen(initial) * 2 + 1);
        strcpy(str, initial);
    } else {
        str = xmalloc(slen = 256);
        *str = 0;
    }

    pos = strlen(str);

    do {
        c = getch();
        switch (c) {
            case KEY_DL:
            case 21:    /* ^U */
                *str = 0;
                pos = 0;
                break;

            case KEY_LEFT:
                --pos;
                if (pos < 0) {
                    beep();
                    pos = 0;
                }
                break;

            case KEY_RIGHT:
                ++pos;
                if (pos > strlen(str)) {
                    beep();
                    pos = strlen(str);
                }
                break;

            case KEY_HOME:
            case 1:         /* ^A */
                pos = 0;
                break;

            case KEY_END:
            case 5:         /* ^E */
                pos = strlen(str);
                break;

            case KEY_DC:
                if (pos == strlen(str))
                    beep();
                else
                    memmove(str + pos, str + pos + 1, strlen(str + pos + 1) + 1);
                break;

            case KEY_BACKSPACE:
                if (pos == 0)
                    beep();
                else {
                    memmove(str + pos - 1, str + pos, strlen(str + pos) + 1);
                    --pos;
                }
                break;

            case 23:    /* ^W */
                for (i = pos; i > 0; --i)
                    if (!isspace((int)str[i])) break;
                for (; i > 0; --i)
                    if (isspace((int)str[i])) break;
                if (i != pos) {
                    memmove(str + i, str + pos, strlen(str + pos) + 1);
                    pos = i;
                }
                break;

            case ERR:
                break;

            default:
                if (isprint(c) && c != '\t') {
                    if (strlen(str) == slen - 1)
                        str = xrealloc(str, slen *= 2);
                    memmove(str + pos + 1, str + pos, strlen(str + pos) + 1);
                    str[pos++] = (char)c;
                } else
                    beep();
                break;
        }

        /* figure out the offset to use for the string */
        off = 0;
        if (pos > COLS - xstart - 1)
            off = pos - (COLS - xstart - 1);
        
        /* display the string */
        mvaddstr(linenum, 0, prompt);
        addstr("> ");
        addnstr(str + off, min(strlen(str + off), COLS - xstart - 1));
        clrtoeol();
        move(linenum, xstart + pos - off);
        refresh();
    } while (c != KEY_ENTER && c != '\r' && c != '\x1b' && c != 7 /* ^G */);

    if (c == KEY_ENTER || c == '\r')
        /* Success */
        return str;
    else {
        xfree(str);
        return NULL;
    }
}
