/*
    hf.c - functions (mostly statistics) for HF contests
    Copyright (C) 2010-2015 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 "dwdb.h"
#include "dxc.h"
#include "excdb.h"
#include "hf.h"
#include "kbdbind.h"
#include "menu.h"
#include "qsodb.h"
#include "tsdl.h"
#include "session.h"
#include "ssbd.h"
#include "stats.h"
#include "subwin.h"
#include "terminal.h"

#define QSOBOUND 6
#define LASTQSO 10
#define QSOH (LASTQSO-QSOBOUND)
#define RATEBOUND 45
#define LASTBOUND 71
#define BANDS 6
#define DXCWIDTH 23
#define DXCBOUND (LASTQSO+1)

int sw_hf_kbd_func(struct subwin *sw, struct event *ev, int fw){

    switch(kbd_action(KM_MAIN,ev)){
        case ACT_ESC:
            return 0;
            break;
        case ACT_DOWN:
            sw->cur++;
            sw_hf_check_bounds(sw);
            redraw_later();
            return 1;
        case ACT_UP:
            sw->cur--;
            sw_hf_check_bounds(sw);
            redraw_later();
            return 1;
        
        case ACT_HOME:
            sw->cur = 1;
            sw_hf_check_bounds(sw);
            redraw_later();
            return 1;
        case ACT_END:
            if (!aband) return 1;
            sw->cur = ctest->allqsos->len;
            sw_hf_check_bounds(sw);
            redraw_later();
            return 1;
        case ACT_ENTER:
            if (!aband) return 1;
            sw_hf_check_bounds(sw);
            if (aband->readonly) {
                errbox(VTEXT(T_BAND_RO), 0);
                return 1;
            }
            if (sw->cur==0) break;
            edit_qso(get_gqso(aband, sw, sw->cur-1));
            return 1;    
        case ACT_CALLINFO:
            if (sw->cur==0) break;
            call_info(get_gqso(aband, sw, sw->cur-1));
            return 1;

        case ACT_INSERT:
            if (sw->offset2 > 0) sw->offset2--;
            redraw_later();
            return 1;
        case ACT_DELETE:
            /*if (sw->offset2 < QSOBOUND - 1)*/  sw->offset2++; // TODO limit ?
            redraw_later();
            return 1;
        case ACT_PLAY_LAST:
#ifdef HAVE_SNDFILE
            ssbd_play_last_sample(gssbd, get_gqso(aband, sw, sw->cur-1));
#endif
            break;
    }
    return 0;
}

int sw_hf_mouse_func(struct subwin *sw, struct event *ev, int fw){
    return 0;
}

// uses aband
void sw_hf_notworked_dxcc(gpointer key, gpointer value, gpointer user_data)
{
	ZPtrArray *notworked_dxccs = (ZPtrArray *)user_data;
	char *dxcc = (char*)key;

	if (g_hash_table_lookup(aband->stats->dxcs, key) == NULL) z_ptr_array_add(notworked_dxccs, g_strdup(dxcc));
}


void sw_hf_redraw(struct subwin *sw, struct band *band, int flags){
    int i,j,x,y=0,col,idx, x0, y0;
    int bi;
    struct band *bands[BANDS];
    char s[256], t[256];
    char *c;
    char *hf_modes[] = {"???", "SSB", " CW", "MIX", "MIX", " AM", "FM", "RTY", "STV", "ATV"}; 
    int nqsos=0, nqsop=0;//, nmult=0;
    int ntotal = 0;
    struct spotband *sband;
    
    // frames
    for (i=0; i<=LASTQSO;i++) {
        clip_char(sw, RATEBOUND, i, ATTR_FRAME|COL_NORM|179);
        clip_char(sw, LASTBOUND, i, ATTR_FRAME|COL_NORM|179);
    }
    for (i=0; i<RATEBOUND;i++)   clip_char(sw, i, QSOBOUND, ATTR_FRAME|COL_NORM|196);
    if (QSOBOUND < sw->h) set_char(sw->x-1, sw->y + QSOBOUND, ATTR_FRAME|COL_NORM|195);
    clip_char(sw, RATEBOUND, QSOBOUND, ATTR_FRAME|COL_NORM|180);

    // excs multiplier
    if (aband && excdb){
        int l, maxl = 0;
        x = 0;
        y = - sw->offset2;
        for (i=0; i<excdb->vexcia->len; i++){
            c = (gchar *)z_ptr_array_index(excdb->vexcia, i);
            l = strlen(c);
            if (l > maxl) maxl = l;
        }
        for (i=0; i<excdb->vexcia->len; i++){
            c = (gchar *)z_ptr_array_index(excdb->vexcia, i);
            if (x + maxl > RATEBOUND) {
                x = 0;
                y++;
                if (y==QSOBOUND) break;
            }  
            if (g_hash_table_lookup_extended(aband->stats->excs, c, NULL, NULL) == FALSE){
                clip_printf(sw, x, y, COL_NORM, c);
            }
            x += maxl + 1;

        }
    }
	// dxcc multiplier
	if (aband && ctest->dxcmult){
		ZPtrArray *notworked_dxccs = z_ptr_array_new();
		g_hash_table_foreach(dw->dw, sw_hf_notworked_dxcc, notworked_dxccs);
		z_ptr_array_qsort(notworked_dxccs, z_compare_string);
		for (i = 0; i < notworked_dxccs->len; i++){
			c = (gchar *)z_ptr_array_index(notworked_dxccs, i);
            if (x + strlen(c) > RATEBOUND) {
                x = 0;
                y++;
                if (y==QSOBOUND) break;
            }  
            clip_printf(sw, x, y, COL_NORM, c);
            x += strlen(c) + 1;
		}
		z_ptr_array_free_all(notworked_dxccs);
	}


    // bands prepare
    i = 0;
    memset(bands, 0, sizeof(bands));
    if (ctest){
        for (bi = ctest->bands->len - 1; bi >= 0; bi--){
            struct band *b = (struct band *)g_ptr_array_index(ctest->bands, bi);
            bands[i++] = b;
            if (i==BANDS) break;
        }
    }
    
    // bands stats
    if (ctest) 
        clip_printf(sw, RATEBOUND+3, 0 , COL_NORM, VTEXT(T_HF_RATE), ctest->qso_per_10 * 6, ctest->qso_per_60);
    else
        clip_printf(sw, RATEBOUND+3, 0 , COL_NORM, VTEXT(T_HF_RATE), 0, 0);
    clip_printf(sw, RATEBOUND+1, 1 , COL_NORM, VTEXT(T_HF_BAND));

    for (i=0; i<6;i++){
        struct band *b = bands[i];
        if (!b) continue;
        safe_strncpy0(s, b->bandname, sizeof(s));
        c = strchr(s, ' ');
        if (c != NULL) *c='\0';
        j = strlen(s);
        if (j > 0 && toupper(s[j-1]) == 'M') s[j-1] = '\0'; 
        clip_printf(sw, RATEBOUND+4-strlen(s), i+2, COL_NORM, s);
        nqsos += b->stats->nqsos;
        nqsop += b->stats->nqsop;
        clip_printf(sw, RATEBOUND+6, i+2, COL_NORM, "%4d %5d %4d", b->stats->nqsos, b->stats->nqsop, b->stats->nmult);
    }
    clip_printf(sw, RATEBOUND+1, i+2, COL_NORM, VTEXT(T_HF_SUM));
    clip_printf(sw, RATEBOUND+6, i+2, COL_NORM, "%4d %5d %4d", nqsos, nqsop, ctest?ctest->allb_nmult:0);
    clip_printf(sw, RATEBOUND+1, i+3, COL_NORM, VTEXT(T_HF_SCORE));
    /*t ntotal = st->ntotal;
    if (ctest->qsoglob)*/ 
    if (ctest) ntotal = ctest->allb_ntotal;
    if (ntotal >= 1000000)
        sprintf(s, "%d %03d %03d", ntotal / 1000000, (ntotal % 1000000) / 1000, ntotal % 1000);
    else if (ntotal >= 1000)
        sprintf(s, "%d %d", ntotal / 1000, ntotal % 1000);
    else
        sprintf(s, "%d", ntotal);
    clip_printf(sw, LASTBOUND - 1 - strlen(s), i+3, COL_NORM, s);




    // qsos
    if (ctest){
//        y0 = 0;
/*        if (ctest->allqsos->len+1 <= QSOH) 
            y0 = LASTQSO - (ctest->allqsos->len+1) + 1;
  */


        for (i=0;i<QSOH;i++){
			struct qso *q;
            y = QSOBOUND + 1 + i;
            idx = ctest->allqsos->len + 0 - QSOH + i - sw->offset;
            if (idx < 0 || idx >= ctest->allqsos->len){
                clip_printf(sw, 1, y, COL_NORM, "~");
                continue;
            }
            col = /*idx == sw->cur - 1? COL_INV :*/ COL_NORM;
        
            //clip_printf(sw, LASTBOUND+2, y, COL_NORM, "i=%d y=%d idx=%d cur=%d", i, y, idx, sw->cur);

            q = (struct qso *)g_ptr_array_index(ctest->allqsos, idx);
            if (y<=QSOBOUND) continue;
            safe_strncpy0(s, q->band->bandname, sizeof(s));
            c = strchr(s, ' ');
            if (c != NULL) *c='\0';
            j = strlen(s);
            if (j > 0 && toupper(s[j-1]) == 'M') s[j-1] = '\0'; 
            clip_printf(sw, 4-strlen(s), y, col, s);
            clip_printf(sw, 5, y, col, hf_modes[q->mode%10]);
            s[0]=q->time_str[0];
            s[1]=q->time_str[1];
            s[2]=':';
            s[3]=q->time_str[2];
            s[4]=q->time_str[3];
            s[5]='\0';
            clip_printf(sw, 9, y, col, s);

            if (q->error)
                safe_strncpy0(s, "ERROR", 20);
            else
                safe_strncpy0(s, q->callsign, 20);
            clip_printf(sw, 15, y, col, s);

            strcpy(t, "");
            if (ctest->qsoused > 0) {
                strcat(t, " ");
                strcat(t, q->qsonrr);
            }
            if (*q->exc) {
                strcat(t, " ");
                strcat(t, q->exc);
            }
            if (*q->locator) {
                strcat(t, " ");
                strcat(t, q->locator);
            }
            
            g_strlcpy(s, t, 11);
            clip_printf(sw, 33-strlen(s), y, col, s);

            sprintf(t, "%d", q->qsop);
            g_strlcpy(s, t, 2);
            clip_printf(sw, 39-strlen(s), y, col, s);
            if (q->new_ & NEW_MULT) clip_printf(sw, 41, y, col, "*");

            if (i==ctest->allqsos->len - 1){ // last QSO
                s[0]=q->time_str[0]; s[1]=q->time_str[1]; s[2]=':';
                s[3]=q->time_str[2]; s[4]=q->time_str[3]; s[5]='\0';
                strcpy(t, "(n/a)");
                if (ctest->lastmultqso){
                    t[0]=ctest->lastmultqso->time_str[0]; t[1]=ctest->lastmultqso->time_str[1]; t[2]=':';
                    t[3]=ctest->lastmultqso->time_str[2]; t[4]=ctest->lastmultqso->time_str[3]; t[5]='\0';
                }
                clip_printf(sw, LASTBOUND+2, 0, COL_NORM, VTEXT(T_HF_LAST), s, t);
            }
            if (idx == sw->cur -1) {
                for (j = 0; j < RATEBOUND; j++) clip_color(sw, j, y, COL_INV);
            }
        }
    }

    //DXCC
    if (gses->adwi){
        clip_printf(sw, LASTBOUND+2, 1, COL_NORM, "%02d %s %s", gses->adwi->waz, gses->adxc, gses->adwi->dxcname);
    }

    if (gses->qs_master && *gses->qs_master) clip_printf(sw, 0,  LASTQSO+1, COL_NORM, "%s", gses->qs_master);
   // else                  clip_printf(sw, 1, LASTQSO+2, COL_NORM, "empty");

    
//  clip_char(sw, LASTBOUND+5, 8, FRAME|COL_NORM|179);
    if (gses->asunriseset){
        clip_printf(sw, LASTBOUND+2, 8, COL_NORM, "%11s", gses->asunriseset);
	}
    clip_char(sw, LASTBOUND+14, 8, ATTR_FRAME|COL_NORM|179);
	if (spotdb && spotdb->sfi > 0){
        clip_printf(sw, LASTBOUND+16, 8, COL_NORM, "SFI=%d", spotdb->sfi);
	}

    if (gses->adwi){
        sprintf(s, "%d km, %d", gses->aqrb, gses->aqtf);
        clip_printf(sw, LASTBOUND+2, 9, COL_NORM, s);
#if defined(Z_HAVE_SDL) && !defined(Z_ANDROID)     
        if (sdl){
            int xx = sw->x + LASTBOUND+2+strlen(s);
            if (xx < sw->x + sw->w) print_text(xx, sw->y + 9, -1, "\xb0", COL_NORM); 
        }
        else
#endif            
        {
            clip_printf(sw, LASTBOUND + 2 + strlen(s), 9, COL_NORM, " deg");
        }
    }

    // dxc
	sband = get_actual_spotband();
    if (sband && sw->h >= DXCBOUND && sband->freq->len > 0){
        struct spot *spot;
		time_t now;
        int idx;

        if (!sband) return;
        idx = sband->current;
		now = time(NULL);

        x0 = ((sw->w / DXCWIDTH) / 2 ) * DXCWIDTH;
        y0 = DXCBOUND + (sw->h - DXCBOUND) / 2;

        x = x0;
        y = y0;
		if (idx >= 0 && idx < sband->freq->len){ 
            spot = (struct spot *)z_ptr_array_index(sband->freq, idx);
            sw_hf_draw_spot(sw, x, y, spot, now, COL_INV);
        }
        y--;
        idx++;
        while (x < sw->w && idx < sband->freq->len){
            if (y == DXCBOUND){
                y = sw->h - 1;
                x += DXCWIDTH;
            }
            spot = (struct spot *)z_ptr_array_index(sband->freq, idx);
            sw_hf_draw_spot(sw, x, y, spot, now, COL_NORM);
            y--;
            idx++;
        }

        x = x0;
        y = y0 + 1;
        idx = sband->current - 1;

        while (x >= 0 && idx >= 0){
            if (y == sw->h){
                y = DXCBOUND + 1;
                x -= DXCWIDTH;
            }
            spot = (struct spot *)z_ptr_array_index(sband->freq, idx);
            sw_hf_draw_spot(sw, x, y, spot, now, COL_NORM);
            y++;
            idx--;
        }

        
#if 0
        x = x0;
        y = y0;
        sw_hf_draw_spot(sw, x, y, spotdb->cur[aband->bi], COL_INV);
        y--;

        if (spotdb->cur[aband->bi]) spot=spotdb->cur[aband->bi]->prev;
        else                 spot=NULL;

        while (x >= 0){
            if (!spot) break;
            if (y==DXCBOUND){
                y = sw->h - 1;
                x -= DXCWIDTH;
            } 
            if (get_qso_by_callsign(aband, spot->callsign)==NULL)
                sw_hf_draw_spot(sw, x, y, spot, COL_NORM);
            spot=spot->prev;
            y--;
        }
        
        if (spotdb->cur[aband->bi]) spot=spotdb->cur[aband->bi]->next;
        else                 spot=NULL;

        x = x0;
        y = y0 + 1;

        while (x < sw->w){
            if (!spot) break;
            if (y == sw->h){
                y = DXCBOUND + 1;
                x += DXCWIDTH;
            }
            if (get_qso_by_callsign(aband, spot->callsign)==NULL)
                sw_hf_draw_spot(sw, x, y, spot, COL_NORM);
            spot=spot->next;
            y++;
        }
#endif
    }
}


void sw_hf_draw_spot(struct subwin *sw, int x, int y, struct spot *spot, time_t now, int acolor){
	char raw[20];
    int col;

    if (!spot){
        clip_printf(sw, x, y, acolor, "%-*s", DXCWIDTH, "~");
        return;
    }
    
    col = COL_NORM;
    if (now < spot->endbold) col = COL_WHITE;
    if (acolor == COL_INV){
        if (col == COL_NORM) col = COL_INV;
        else col |= COL_INV;
    }

    clip_printf(sw, x, y, col, "%10.1f", spot->qrg);

    z_get_raw_call(raw, spot->callsign);
    col = sw_dxc_color(raw);					// color from raw call but print whole call
    if (acolor == COL_INV) {
        if (col == COL_NORM) col = COL_INV;
        else col |= COL_INV;
    }
    clip_printf(sw, x + 10, y, col, " %-10s", spot->callsign);

	if (dxc_new_mult(spot->callsign)){
		clip_printf(sw, x + 10, y, col, "!"); 
	}
} 

void sw_hf_check_bounds(struct subwin *sw){
    int len;

    if (!aband) return;
    
    /*dbg("sw_qsos_check_bounds cur=%d, offset=%d ", sw->cur, sw->offset);*/
    
    len = ctest->allqsos->len;
    if (sw->cur < 1 )   sw->cur = 1;
    if (sw->cur > len) sw->cur = len;

    
    if (sw->cur > len - sw->offset -1 ){
        sw->offset = len - sw->cur;
    }
    if (sw->cur < len - QSOH + 1 - sw->offset){
        sw->offset = len - QSOH - sw->cur + 1;
    }
    if (sw->offset < 0) sw->offset=0;
}

void sw_hf_raise(struct subwin *sw){
}

void get_hf_dxc(char *str){
    struct dw_item *dwi;
    static char dxcc[25];
    double myh, myw, qrb, qtf;

	dwi = get_dw_item_by_call(dw, str);
    if (!dwi) return;

    gses->adwi = dwi;
    
	get_dxcc(dw, dxcc, str);
    gses->adxc = dxcc;
    zg_free0(gses->asunriseset);
	gses->asunriseset = zsun_strdup_riseset(time(NULL), dwi->latitude, dwi->longitude);
    
    if (ctest){
        myh=qth(ctest->pwwlo, 0);
        myw=qth(ctest->pwwlo, 1);
    }else{
        myh=qth(cfg->pwwlo, 0);
        myw=qth(cfg->pwwlo, 1);
    }
    hw2qrbqtf(myh, myw, dwi->longitude*M_PI/180.0, dwi->latitude*M_PI/180.0, &qrb, &qtf);
    //g_addf("%s  %f %f   %f %f   %f %f", cfg->pwwlo, myh, myw, dwi->longitude*MY_PI/180.0, dwi->latitude*MY_PI/180.0, &qrb, &qtf);
    gses->aqrb = (int)qrb;
    gses->aqtf = (int)((qtf*180.0)/M_PI);

}

