/*
    Tucnak - VHF contest log
    Copyright (C) 2002-2023  Ladislav Vaiz <ok1zia@nagano.cz>

    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 "bfu.h"
#include "control.h"
#include "fifo.h"
#include "inputln.h"
#include "kbd.h"
#include "net.h"
#include "session.h"
#include "terminal.h"

static char *strstates[]={"RUN","SP","REQR","REQS","RUNNING","GIVEN"};
static char *strccmds[]={"REQ","ACC","REJ","BACK"};


void menu_forcerun(void *arg){
    gchar *c;
    struct band *b;
    if (!ctest || !aband) return;
    
    b=aband;
    dbg("forcerun (st=%s)\n", strstates[b->ctrlstate]);
    c=g_strdup_printf("GR %s;%d;%s\n", b->pband, CCMD_REJ,gnet->myid);
    dbg("   send %s",c);
    rel_write_all(c);
    g_free(c);
    b->ctrlstate=CTRL_RUN;
    redraw_later();
}

int can_cq(struct band *b){
    if (!b) return 1;  /* no contest, no limit */
    return (b->ctrlstate&0x01)==0;
}

int can_tx(struct band *b){
    if (!b) return 1;  /* no contest, no limit */
    return (b->ctrlstate&0x01)==0 || b->ctrlstate==CTRL_GIVEN;
}


void menu_grabband(void *cba){
    gchar *c;
    struct band *b;
    int ctx1,ctx2;
    if (!ctest || !aband) return;
    
    
    b=aband;
    ctx1=can_cq(b);
    dbg("grabband (st=%s)\n", strstates[b->ctrlstate]);
    switch(b->ctrlstate){
        /* RUN */
        case CTRL_RUN:/* mozna poslat CCMD_REJ, aby S&P vychcipali */
            break;
        case CTRL_REQR:
            b->ctrlstate=CTRL_GIVEN;
            c=g_strdup_printf("GR %s;%d;%s\n", b->pband, CCMD_ACC, b->ctrlsp);
            dbg("   send %s",c);
            rel_write_all(c);
            g_free(c);
            break;
        case CTRL_GIVEN:
            break;
        /* S&P */
        case CTRL_SP:
            b->ctrlstate=CTRL_REQS;
            c=g_strdup_printf("GR %s;%d;%s\n", b->pband, CCMD_REQ, gnet->myid);
            dbg("   send %s",c);
            rel_write_all(c);
            g_free(c);
            break;
        case CTRL_REQS:
        case CTRL_RUNNING: /* see ctrl_back */
            b->ctrlstate=CTRL_SP;
            c=g_strdup_printf("GR %s;%d;%s\n", b->pband, CCMD_BACK, gnet->myid);
            dbg("   send %s",c);
            rel_write_all(c);
            g_free(c);
            break;

    }
    ctx2=can_cq(b);
    if (ctx1 && !ctx2) rx();
    dbg("         (st=%s)\n", strstates[b->ctrlstate]);
    redraw_later();
    
}

void net_grab(struct band *b, enum ccmd ccmd, gchar *netid){
    int ctx1,ctx2;
    if (!b) return;
    
    dbg("net_grab (st=%s, cmd=%s, netid=%s)\n",strstates[b->ctrlstate],strccmds[ccmd], netid);
    ctx1=can_cq(b);
    switch(b->ctrlstate){
        /* RUN */
        case CTRL_RUN:
        case CTRL_REQR:
        case CTRL_GIVEN:
            switch(ccmd){
                case CCMD_REQ:
                    b->ctrlstate=CTRL_REQR;
                    zg_free0(b->ctrlsp);
                    b->ctrlsp=g_strdup(netid);
                    break;
                case CCMD_BACK:
                    b->ctrlstate=CTRL_RUN;
                    break;
                case CCMD_REJ: /* first "force run mode" */
                    b->ctrlstate=CTRL_SP;
                    break;
                default:
                    break;
            }
            break;

        /* S&P */            
        case CTRL_SP:
        case CTRL_REQS:
        case CTRL_RUNNING:
            switch(ccmd){
                case CCMD_ACC:
                    if (strcmp(netid,gnet->myid)) {
                        b->ctrlstate=CTRL_SP;       /* other S&P become control */
                    }else{
                        b->ctrlstate=CTRL_RUNNING;
                    }
                    break;
                case CCMD_REJ:
                    b->ctrlstate=CTRL_SP;
                    break;
                default:
                    break;
            }
            break;
    }
    ctx2=can_cq(b);
    if (ctx1 && !ctx2) rx();
    dbg("         (st=%s)\n", strstates[b->ctrlstate]);
    redraw_later();
}

void ctrl_back(struct band *b){
    int ctx1,ctx2;
    gchar *c;
    if (!b) return;

    ctx1=can_cq(b);
    
    switch(b->ctrlstate){
        /* S&P */            
        case CTRL_SP:
        case CTRL_REQS:
        case CTRL_RUNNING:
            /* see menu_grabband/CTRL_RUNNING */
            b->ctrlstate=CTRL_SP;
            c=g_strdup_printf("GR %s;%d;%s\n", b->pband, CCMD_BACK, gnet->myid);
            dbg("   send %s",c);
            rel_write_all(c);
            g_free(c);
            break;
        default:
            break;
    }
    ctx2=can_cq(b);
    if (ctx1 && !ctx2) rx();
}


void wkd_tmpqso(struct band *band, enum wt_type type, gchar *str){
    gchar *c;
    if (!ctest || !band || !str) return;
    
    c=g_strdup_printf("WT %s;%s;%d;%s\n", band->pband, gnet->myid, type, str);
    /*dbg("%s\n", c);*/
    rel_write_all(c);
    g_free(c);
}

void wkd_send_all(struct band *b){
	wkd_tmpqso(b, WT_CALLSIGN, b->tmpqsos[0].callsign);
	wkd_tmpqso(b, WT_RSTS, b->tmpqsos[0].rsts);
	wkd_tmpqso(b, WT_RSTR, b->tmpqsos[0].rstr);
	wkd_tmpqso(b, WT_QSONRS, b->tmpqsos[0].qsonrs);
	wkd_tmpqso(b, WT_QSONRR, b->tmpqsos[0].qsonrr);
	wkd_tmpqso(b, WT_EXC, b->tmpqsos[0].exc);
	wkd_tmpqso(b, WT_LOCATOR, b->tmpqsos[0].locator);
	if (b == aband) wkd_tmpqso(b, WT_BAND, b->pband);
	wkd_tmpqso(b, WT_OPERATOR, b->operator_);
	peer_tx(b, gses->last_cq_timer_id>0 ? 2 : gses->tx);
	send_inputline(b);
}

void peer_tx(struct band *band, int tx){
    gchar *c;
    if (!ctest || !band) return;
    
    c=g_strdup_printf("PT %s;%s;%d\n", band->pband, gnet->myid, tx);
    rel_write_all(c);
    g_free(c);
}

/*void menu_spy(void * cba){
    if (!ctest || !aband) return;

    aband->spymode++;
    if (aband->spymode>=SM_LAST) aband->spymode=SM_INPUTLINE;
    redraw_later();
} */

void do_endspy(void *arg, void *arg2){
    struct spypeer *sp;
    int i;
    char *filename;
    
    i = GPOINTER_TO_INT(arg);
    if (i<0 || i>=ctest->spypeers->len) return;

    sp=(struct spypeer *)g_ptr_array_index(ctest->spypeers, i);
    free_spypeer(sp);
    g_ptr_array_remove(ctest->spypeers, sp);
    
    filename = g_strdup_printf("%s/spy", ctest->directory);
    save_spypeers_to_file(filename); 
    g_free(filename);
    
    resize_terminal(NULL);
}

void menu_endspy(void *arg){
    int i;
    struct menu_item *mi = NULL;
    struct spypeer *sp;
    
    if (!ctest) return;
    if (!ctest->spypeers->len) return;
    
    if (!(mi = new_menu(3))) return;
    
    for (i=0; i<ctest->spypeers->len;i++){
        gchar *c;
        sp=(struct spypeer *)g_ptr_array_index(ctest->spypeers, i);
        c=g_strdup_printf("%-6s %c   %s", sp->operator_, sp->bandchar, sp->peerid);
        add_to_menu(&mi,g_strdup(c),"", "", do_endspy, GINT_TO_POINTER(i), 0);    
        g_free(c);
    }
    do_menu_selected(mi, NULL, 0);
}


void send_inputline(struct band *band){
    gchar *c;
    
    if (!band) return;

    c = g_strdup_printf("WI %s;%s;%s\n", 
            band->pband, 
            gnet->myid,
            band->il->cdata); 
    rel_write_all(c);
    g_free(c);
}

void free_spypeer(struct spypeer *sp){
    clear_spypeer(sp);
    zg_free0(sp->peerid);
    zg_free0(sp->operator_);
    zg_free0(sp->inputline);
    g_free(sp);
}

void free_spypeers(GPtrArray *sps){
    int i;
    
    if (!sps) return;
    
    for (i=0;i<sps->len;i++){
        struct spypeer *sp;
        sp=(struct spypeer *)g_ptr_array_index(sps, i);
        free_spypeer(sp);
    }
    g_ptr_array_free(sps,1);
}

 struct spypeer *init_spypeer(GPtrArray *sps, gchar *peerid, char bandchar){
    struct spypeer *sp;
    char *filename;

    sp=get_spypeer_by_peerid(sps, peerid, bandchar);
    if (sp){
        g_ptr_array_remove(sps, sp);
        free_spypeer(sp);
    }

    sp=g_new0(struct spypeer, 1);
    sp->peerid=g_strdup(peerid);
    sp->bandchar=bandchar;
    sp->peertx=-1;
    g_ptr_array_add(sps, sp);
    
    filename = g_strdup_printf("%s/spy", ctest->directory);
    save_spypeers_to_file(filename); 
    g_free(filename);
    
    resize_terminal(NULL);
    return sp;
}

struct spypeer *get_spypeer_by_peerid(GPtrArray *sps, gchar *peerid, char bandchar){
    int i;

    bandchar=toupper(bandchar);

    for (i=0;i<sps->len;i++){
        struct spypeer *sp;
        sp=(struct spypeer *)g_ptr_array_index(sps, i);
        if (strcmp(sp->peerid, peerid)) continue;
        if (sp->bandchar != bandchar && sp->bandchar != '*') continue;
        return sp;
    }
    return NULL;
}

void clear_spypeer(struct spypeer *sp){
    zg_free0(sp->callsign);
    zg_free0(sp->rsts);
    zg_free0(sp->rstr);
    zg_free0(sp->qsonrs);
    zg_free0(sp->qsonrr);
    zg_free0(sp->exc);
    zg_free0(sp->locator);
    zg_free0(sp->remark);
}

void send_spypeer_request(void *arg){
    char *peerid;
    gchar **items;
    char bandchar;
    int i, no;
    
    
    
    no = GPOINTER_TO_INT(arg);
    dbg("send_spypeer_request no='%d'\n", no);
    dbg("bpeers='%s'\n", gnet->bpeers);
    
    items = g_strsplit(gnet->bpeers,";",0);

    /*for (i=0; items[i]!=NULL;i++){
        if (i==no) goto found;
    } */
    for (i=0; 
         items[i]!=NULL && items[i+1]!=NULL && items[i+2]!=NULL;
         i+=3){
        dbg("i=%d\n", i);
        if (i==no*3) goto found;
    }
    dbg("not found\n");
    goto x;
found:    
    dbg("found i=%d, no=%d\n", i, no);
    peerid=items[i];
    bandchar=items[i+2][0];
    spypeer_add(peerid, bandchar, 1);
x:;    
    g_strfreev(items);
}


void spypeer_add(char *peerid, char bandchar, int send_request){
	struct spypeer *sp;
    
    //dbg("spypeer_add: peerid=%s bandchar=%c pband=%s\n", peerid, bandchar, b->pband);
	sp = init_spypeer(ctest->spypeers, peerid, bandchar);

	if (send_request) spypeer_send_request(sp, '\0');
	
}

void spypeer_send_request(struct spypeer *sp, char bandchar){

	if (bandchar == '\0') bandchar = sp->bandchar;

	gchar *c;
	if (bandchar == '*' && aband){
		c = g_strdup_printf("RT *;%s\n", sp->peerid);
	}else{
		struct band *b = find_band_by_bandchar(bandchar);
		if (!b){
			dbg("band %c not found\n", sp->bandchar);
			return;
		}
		c = g_strdup_printf("RT %s;%s\n", b->pband, sp->peerid);
	}
    rel_write_all(c);
    g_free(c);
}

void spypeer_send_requests(){
    int i;
    for (i=0;i<ctest->spypeers->len; i++){
        struct spypeer *sp;

        sp = (struct spypeer *)g_ptr_array_index(ctest->spypeers, i);
		spypeer_send_request(sp, '\0');
    }
}



int load_spypeers_from_file(char *filename){
    FILE *f;
    gchar *c;
    GString *gs;
    gchar **items, *peerid;
    char bandchar;
    
    f=fopen(filename,"rt");
    if (!f) return 1;

    gs = g_string_sized_new(100);
    while( (c=zfile_fgets(gs, f, 0)) != NULL){
        items = g_strsplit(c, ";", 3);
        if (!items) continue;
        if (!items[0] || !items[1] || !items[2]) {
            g_strfreev(items);
            continue;
        }
        peerid=items[0];
        bandchar=items[1][0];

        spypeer_add(peerid, bandchar, 0);
    }
    g_string_free(gs, 1);
    fclose(f);
    return 0;
}

int save_spypeers_to_file(char *filename){
    FILE *f;
    int i;

    f = fopen(filename, "wt");
    if (!f){
        log_addf(VTEXT(T_CANT_WRITE_S), filename);
        return errno;
    }
    
    for (i=0;i<ctest->spypeers->len; i++){
        struct spypeer *sp;

        sp = (struct spypeer *)g_ptr_array_index(ctest->spypeers, i);
        fprintf(f, "%s;%c;\n", sp->peerid, sp->bandchar);
    }

    fclose(f);
    return 0;
}

