/*
    Tucnak - VHF contest log
    Copyright (C) 2002-2022  Ladislav Vaiz <ok1zia@nagano.cz>
    and authors of web browser Links 0.96

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

*/

#include "header.h"

#include "cwdaemon.h"
#include "fifo.h"
#include "inputln.h"
#include "kbdbind.h"
#include "kbd.h"
#include "qsodb.h"
#include "rc.h"
#include "session.h"
#include "subwin.h"
#include "terminal.h"
#include "tregex.h"
#include "zosk.h"

#define FREE_Cx if (c1) {g_free(c1); c1=NULL;}\
                if (c2) {g_free(c2); c2=NULL;}\
                if (c3) {g_free(c3); c3=NULL;}

void draw_inputln(struct inputln *il, int selx){
	unsigned color = COL_INV;
	if (il->is_susp) color = (COL_DARKRED << 3) | COL_WHITE;

    /*dbg("draw_inputln (%d,%d)\n",il->x,il->y);*/
    if (il->vpos + il->l <= il->cpos) il->vpos = il->cpos - il->l + 1;
    if (il->vpos > il->cpos) il->vpos = il->cpos;
    if (il->vpos < 0) il->vpos = 0;
	fill_area(il->x, il->y, il->l, 1, color);
    
	print_text(il->x, il->y, strlen(il->cdata + il->vpos) <= il->l ? strlen(il->cdata + il->vpos) : il->l, il->cdata + il->vpos, color);
#ifdef Z_HAVE_SDL
	if (sdl && cfg->usetouch) print_text(il->x + il->l, il->y, 1, "\x19", color);
#endif



    if (il->focused) {
/*        dbg("draw_inputln: set_cursor %d %d \n", il->x + il->cpos - il->vpos, il->y);*/
        set_cursor(il->x + il->cpos - il->vpos, il->y, il->x + il->cpos - il->vpos, il->y);
    }
}

void clear_inputline(struct inputln *il){
    //if (il->band && il->band->readonly) return;
    il->cpos = 0;
    memset(il->cdata,0,il->dlen);
}
    
static void il_hist_check_bounds(struct inputln *il){
    if (il->hist_i < -1 ) il->hist_i = -1;
    if ((signed)il->hist_i >= (signed)il->history->len) il->hist_i = il->history->len - 1;
}

void il_add_to_history(struct inputln *il, char *s){
    if (strlen(s)==0) return;
    g_ptr_array_add(il->history, g_strdup(s));
    if (il->history->len == IL_HIST_LEN){
        gpointer p;
        p = g_ptr_array_index(il->history, 0);
        g_free(p);
        g_ptr_array_remove_index(il->history, 0);
    }
}

static struct inputln *gil;

void il_history_func (void *arg, void *unused){
    int active;
    struct inputln *il;

    active=GPOINTER_TO_INT(arg);
    il=gil;
    
    if (active<0 || active>il->history->len) return;
    strncpy(il->cdata,
            (char *)g_ptr_array_index(il->history, active),
            il->dlen);
    il->cpos = strlen(il->cdata);

    redraw_later();
}

/* vraci 0 v pripade neobslouzeno */
int inputln_func(struct inputln *il, struct event *ev){
    static char callkst[EQSO_LEN];
    int i;
    struct menu_item *mi;

    //dbg("inputln_func(%p,[%d,%d,%d,%d])\n",il,ev->ev,ev->x,ev->y,ev->b);
    
    switch (ev->ev) {
        case EV_INIT:
/*            dbg("inputln_func EV_INIT\n");*/
            il->x = 20;
            il->y = term->y - cfg->loglines - 1;
			if (il->band && !ctest->oldcontest) il->y -= ctest->spypeers->len;
            
            il->l = 40;
#ifdef Z_HAVE_SDL
			if (cfg->usetouch) il->l--;
#endif
            il->dlen = 256;
            if (!il->cdata)
               il->cdata=(char*)g_malloc(il->dlen);

            memset(il->cdata,0,il->dlen);
            il->cpos = strlen(il->cdata);
            il->term = term;
            if (!il->history) il->history = g_ptr_array_new();
            il->hist_i = -1;
            il_readonly(il, il->readonly);
            draw_inputln(il,1);/*FIXME*/
            
        case EV_RESIZE:
            if (il->sw){ 
                il->x = il->sw->x;
                il->y = il->sw->y + il->sw->h;
                il->l = il->sw->w;
#ifdef Z_HAVE_SDL
				if (cfg->usetouch) il->l--;
#endif
            }else{
                il->x = 20;
                il->y = term->y - cfg->loglines - 1;
				if (il->band && !ctest->oldcontest) il->y -= ctest->spypeers->len;
            }

            /*dbg("inputln_func RESIZE %p term->y=%d il->x=%d il->y=%d il->band=%p\n", il, term->y, il->x, il->y, il->band);*/
        
            
        case EV_REDRAW:      /* unreached for inputline in subwin */
/*            dbg("inputln_func EV_REDRAW\n");*/
            draw_inputln(il,1);/*FIXME*/
            break;
        case EV_KBD:
            if ((ev->y & KBD_CTRL) &&
                z_char_uc(ev->x) == 'V' && il->allow_ctrlv){
                if (il->readonly) break;
                il->wasctrlv=1;
                goto dsp_f;
            }else{   
                if (il->wasctrlv){
                    il->wasctrlv=0;
                    if (il->readonly) break;
/*                    dbg("ctrl+%c\n", ev->x); */
                    if (strlen(il->cdata) < il->dlen - 1) {
                        memmove(il->cdata + il->cpos + 1, il->cdata + il->cpos, strlen(il->cdata) - il->cpos + 1);
						if (ev->x=='[' || ev->x==']')
	                        il->cdata[il->cpos++] = ev->x;
						else
	                        il->cdata[il->cpos++] = tolower(ev->x)-'a'+1;
						
                    }
                    goto dsp_f;
                }
            }
            switch (kbd_action(KM_EDIT, ev)) {
                case ACT_RIGHT:
                    if (il->readonly) break;
                    if (il->cpos < strlen(il->cdata)) il->cpos++;
                    goto dsp_f;
                case ACT_LEFT:
                    if (il->readonly) break;
                    if (il->cpos > 0) il->cpos--;
                    goto dsp_f;
                case ACT_HOME:
                    if (il->readonly) break;
                    il->cpos = 0;
                    goto dsp_f;
                case ACT_END:
                    if (il->readonly) break;
                    il->cpos = strlen(il->cdata);
                    goto dsp_f;
                case ACT_BACKSPACE:
                    if (il->readonly) break;
                    if (il->cpos) {
                        memmove(il->cdata + il->cpos - 1, il->cdata + il->cpos, strlen(il->cdata) - il->cpos + 1);
                        il->cpos--;
//                        if (aband) dbg("inputln_func: call_played='%s'\n", aband->call_played);
                        if (il->band && 
                            il->band->tmpqsos[0].callsign == NULL &&
                            il->band->call_played == NULL && 
                            cwda && 
                            cwda->back && 
                            cfg->cwda_autgive > 0 &&
                            get_mode() == MOD_CW_CW){

                            cwda->back(cwda); 
                        }
                    }
                    goto dsp_f;
                case ACT_DELETE:
                    if (il->readonly) break;
                    if (il->cpos < strlen(il->cdata))
                        memmove(il->cdata + il->cpos, il->cdata + il->cpos + 1, strlen(il->cdata) - il->cpos + 1);
                    goto dsp_f;
                case ACT_KILL_LINE:
                    if (il->readonly) break;
                    clear_inputline(il);
#ifdef Z_HAVE_SDL
					if (gses->osk){
						zosk_clear(gses->osk);
					}
#endif
                    goto dsp_f;    
                case ACT_KILL_TO_BOL:
                    if (il->readonly) break;
                    memmove(il->cdata, il->cdata + il->cpos, strlen(il->cdata + il->cpos) + 1);
                    il->cpos = 0;
                    goto dsp_f;
/*                case ACT_KILL_TO_EOL:
                    if (il->readonly) break;
                    il->cdata[il->cpos] = 0;
                    goto dsp_f;
                    break;*/
                case ACT_NEWCALL_KST:
                    if (il->band) break; // only for subwin inputline
                    if (il->readonly) break;

                    strcpy(callkst, "");
                    input_field(NULL, CTEXT(T_CALLSIGN3), CTEXT(T_CALLSIGN_KST) ,
                               CTEXT(T_OK), CTEXT(T_CANCEL), il, 
                               NULL, 20, callkst, 0, 0, NULL,
                               (void (*)(void *, char *)) newkst, NULL, 0);
#ifdef Z_HAVE_SDL
					if (gses && cfg->usetouch){
						if (gses->osk) zosk_free(gses->osk);
						gses->osk = zosk_init(sdl->screen, ZOSK_ENTERCLOSE | ZOSK_SENDENTER, il->cdata);
						zosk_portrait(gses->osk);
					}
#endif
                    goto dsp_f;
                    break;
                case ACT_LASTCALL_KST:
                case ACT_KILL_TO_EOL:
                    if (il->readonly) break;
                    il->cdata[il->cpos] = 0;
                    dbg("\ni=%d len=%d\n", il->hist_i, il->history->len);
                    
                    if (il->band) break;
                    if (il->hist_i==-1 && strlen(il->cdata)>0){
                        il_add_to_history(il, il->cdata);
                        il->hist_i++;
                    }
                    for (il->hist_i++; (signed)il->hist_i < (signed)il->history->len; il->hist_i++){
                        char *c, *c1=NULL, *c2=NULL, *c3=NULL;
                        c = (char *)g_ptr_array_index(il->history, il->history->len - il->hist_i - 1);
                        if (!c) continue; /* probably unreached */
                        dbg("regmatch('%s')\n", c);
                        if (regmatch(c, "^/[cC][qQ] ([a-zA-Z0-9/-]{3,14})", &c1, &c2, &c3, NULL)==0){
                            char s[20];
                            dbg("c1=%s c2=%s c3=%s\n", c1, c2, c3);
                            
                            safe_strncpy(s, c2, sizeof(s));
                            z_str_uc(s);
                            g_snprintf(il->cdata, il->dlen, "/cq %s ", s);
                            FREE_Cx;
                            break;
                        }
                        FREE_Cx;
                    }
                    il->cpos = strlen(il->cdata);
#ifdef Z_HAVE_SDL
					if (gses && cfg->usetouch){
						if (gses->osk) zosk_free(gses->osk);
						gses->osk = zosk_init(sdl->screen, ZOSK_ENTERCLOSE | ZOSK_SENDENTER, il->cdata);
						zosk_portrait(gses->osk);
					}
#endif
                    goto dsp_f;
                    break;
                case ACT_PREV_HISTORY:    
                    if (il->readonly) break;
                    if (il->hist_i==-1 && strlen(il->cdata)>0){
                        il_add_to_history(il, il->cdata);
                        il->hist_i++;
                    }
                    il->hist_i++;
                    il_hist_check_bounds(il);
                    if (il->hist_i>=0)
                        strncpy(il->cdata,
                                (char *)g_ptr_array_index(il->history, il->history->len - il->hist_i - 1),
                                il->dlen);
                    else
                        strcpy(il->cdata, ""); /* FIXME */        
                    il->cpos = strlen(il->cdata);
#ifdef Z_HAVE_SDL
					if (gses && cfg->usetouch){
						if (gses->osk) zosk_free(gses->osk);
						gses->osk = zosk_init(sdl->screen, ZOSK_ENTERCLOSE | ZOSK_SENDENTER, il->cdata);
						zosk_portrait(gses->osk);
					}
#endif
                    goto dsp_f;
                    break;
                case ACT_NEXT_HISTORY:
                    if (il->readonly) break;
                    il->hist_i--;
                    il_hist_check_bounds(il);
                    if (il->hist_i>=0)
                        strncpy(il->cdata,
                                (char *)g_ptr_array_index(il->history, il->history->len - il->hist_i - 1),
                                il->dlen);
                    else
                        strcpy(il->cdata, ""); /* FIXME */        
                    il->cpos = strlen(il->cdata);
#ifdef Z_HAVE_SDL
					if (gses && cfg->usetouch){
						if (gses->osk) zosk_free(gses->osk);
						gses->osk = zosk_init(sdl->screen, ZOSK_ENTERCLOSE | ZOSK_SENDENTER, il->cdata);
						zosk_portrait(gses->osk);
					}
#endif
                    goto dsp_f;
                    break;
                case ACT_SHOW_HISTORY:{
show_history:
                    if (il->readonly) break;

                    
                    gil=il;
                    if (il->history->len==0) break;
                    if (!(mi = new_menu(1))) break;
                    for (i = 0; i < il->history->len; i++) {
                        add_to_menu(&mi, (char *)g_ptr_array_index(il->history, i),
                                "", "", il_history_func, GINT_TO_POINTER(i), 0);
                    }
                    set_window_ptr(gses->win,il->x,il->y-2-i);
                    do_menu_selected(mi, GINT_TO_POINTER(0), il->history->len-1);
                    
                    }goto dsp_f;
                case ACT_COPY_CLIPBOARD:
                    if (il->readonly) break;
                    /* Copy to clipboard */
                    set_clipboard_text(il->cdata);
                    break;  /* We don't need to redraw */
                case ACT_CUT_CLIPBOARD:
                    if (il->readonly) break;
                    /* Cut to clipboard */                      
                    set_clipboard_text(il->cdata);
                    il->cdata[0] = 0;
                    il->cpos = 0;
                    goto dsp_f;
                case ACT_PASTE_CLIPBOARD: {
                    if (il->readonly) break;
                    /* Paste from clipboard */
 /*                   unsigned char * clipboard = get_clipboard_text();
                    strncpy(il->cdata , clipboard, il->item->dlen);
                    il->cdata[il->item->dlen - 1] = 0;
                    il->cpos = strlen(il->cdata);
                    g_free(clipboard);*/
                    goto dsp_f;
                }
#ifdef Z_HAVE_SDL                                          
				case ACT_AC_INFO:
					if (il->readonly) break;
					il->cdata[il->cpos] = 0;
					if (il->band) break;
					int i;
					for (i = il->history->len - 1; i >= 0; i--){
						char *c, *c1 = NULL, *c2 = NULL, *c3 = NULL;
						c = (char *)g_ptr_array_index(il->history, i);
						if (!c) continue; /* probably unreached */
						if (regmatch(c, "^/[cC][qQ] ([a-zA-Z0-9/-]{3,14})", &c1, &c2, &c3, NULL) == 0){
							dbg("c1=%s c2=%s c3=%s\n", c1, c2, c3);
							g_free(gses->callunder);
							gses->callunder = g_strdup(c2);
							FREE_Cx;
							if (!gses->callunder || !*gses->callunder) break;
							z_str_uc(gses->callunder);
							fifo_kst_ac_info(NULL, NULL);
							break;
						}
						FREE_Cx;
					}
					goto dsp_f;
					break;
#endif                    
                default:
                    if (cfg->slashkey && *cfg->slashkey){
                        if (ev->x == '/') ev->x = *cfg->slashkey;
                        else if (ev->x == *cfg->slashkey) ev->x = '/';
                    }
                    if (ev->x >= ' ' && ev->x < 0x100 && !ev->y) {
                        char c;
                        if (il->readonly) break;
						dbg("gses->last_cq = %p\n", gses->last_cq);
						if (il->band && gses->last_cq){
							if ((gses->last_cq->mode == MOD_CW_CW && gses->last_cq->cw_breakable) ||
								(gses->last_cq->mode != MOD_CW_CW && gses->last_cq->ssb_breakable)){

								cq_abort(0);
							}
						}
                        if (strlen(il->cdata) < il->dlen - 1) {
                            memmove(il->cdata + il->cpos + 1, il->cdata + il->cpos, strlen(il->cdata) - il->cpos + 1);
                            c = ev->x;
                            if (il->upconvert) c = z_char_uc(c);
                            if (!il->valid_chars || strchr(il->valid_chars, c)!=NULL){
                                il->cdata[il->cpos++] = c;
                                il->cdata[il->dlen-1] = '\0';

//                                if (il->band) dbg("inputln_func2: call_played='%s' agcall='%d'\n", il->band->call_played, il->band->agcall);
                                if (il->band && 
                                    il->band->tmpqsos[0].callsign == NULL && 
                                    il->band->call_played == NULL && 
                                    cwda && 
                                    cwda->text &&
                                    cfg->cwda_autgive > 0 &&
                                    get_mode() == MOD_CW_CW){

                                    if (il->cpos == cfg->cwda_autgive){
                                        cwda->text(cwda, il->cdata);
                                        il->band->agcall = 1;
                                        il->band->iscall = 1;
//                                        dbg("inputln_func2:  agcall='%d' iscall='%d'\n", il->band->agcall, il->band->iscall);
                                    }
                                    if (il->cpos > cfg->cwda_autgive){
                                        char sss[2];
                                        sss[0]=c;
                                        sss[1]='\0';
                                        cwda->text(cwda, sss); 
                                    }
                                }
                                    
                            }
                        }
                        goto dsp_f;
                    }
                goto gh;
                dsp_f:
                draw_inputln(il,1);
                return 1;
            }
            gh:
            if (ev->x == KBD_ENTER) {
                if (il->readonly) return 1;
                if (!il->enter) return 1;
                /*dbg("inputln_func: KBD_ENTER '%s' \n",il->cdata);*/
                
                il_add_to_history(il, il->cdata);
                il->hist_i=-1;
                
                il->enter(il->enterdata, il->cdata, 1);
				if (il->enter != process_input_no_contest) clear_inputline(il);
                draw_inputln(il,1);
                return 1;
            }
                
            break;
        case EV_MOUSE:
            if (ev->b & B_MOVE) break;
#ifdef Z_HAVE_SDL
			if (gses && cfg->usetouch && ev->b & B_CLICK){
				int flg = ZOSK_SENDENTER;
				if (abs(il->x + il->l - ev->x) < 2) goto show_history;
				if (gses->osk) zosk_free(gses->osk);
				if (!il->band) flg |= ZOSK_ENTERCLOSE;
				else flg |= ZOSK_CLEARENTER;
				if (il->upconvert) flg |= ZOSK_UPCONVERT;
				gses->osk = zosk_init(sdl->screen, flg, il->cdata);
				zosk_portrait(gses->osk);
			}
#endif
			if (!cfg->usetouch){
				if (ev->y != il->y || ev->x < il->x || ev->x >= il->x + il->l) return 0;
				if ((il->cpos = il->vpos + ev->x - il->x) > strlen(il->cdata)) il->cpos = strlen(il->cdata);
			}
            draw_inputln(il,1);
            break;

        case EV_ABORT:
            if (il->cdata) g_free(il->cdata);
            zg_ptr_array_free_all(il->history);
            break;
    }
    return 0;
}

void il_set_focus(struct inputln *il){
    if (!il) return;  /* subwins having no inputline */
	//dbg("il_set_focus(%c %p)\n", il->band ? il->band->bandchar : ' ', il->sw);
    il->focused=1;            
}

void il_unset_focus(struct inputln *il){
    if (!il) return;
	//dbg("il_unset_focus(%c %p)\n", il->band ? il->band->bandchar : ' ', il->sw);
    il->focused=0;
}

void il_readonly(struct inputln *il, int ro){
    
    il->readonly=ro;
    if (il->readonly)
        strncpy(il->cdata , VTEXT(T__RO_BAND), il->dlen);
    else
        strncpy(il->cdata , "", il->dlen);
}

void newkst(struct inputln *il, char *callkst){

    if (!il || !callkst) return;
    z_str_uc(callkst);
    //g_snprintf(il->cdata, il->dlen, "/cq %s (%s) ", callkst, callkst);
    g_snprintf(il->cdata, il->dlen, "/cq %s ", callkst);  // new format since abt. jun 2011
    il->cpos = strlen(il->cdata);

}

void askkst(struct inputln *il, char *s){
    if (!il) return;
    g_snprintf(il->cdata, il->dlen, "%s", s);
    il->cpos = strlen(il->cdata);
}
