/*
    Tucnak - VHF contest log
    Copyright (C) 2011-2022 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.

*/

#ifndef __QSODB_H
#define __QSODB_H

#include "header.h"
#include "rc.h"
#include "session.h"
#include "zstring.h"

#define STORE_HASH_STR(base, item) {\
    if (base->item) g_free((gpointer)base->item);\
    base->item = g_strdup((char *)g_hash_table_lookup(hash, #item)); \
}

#define STORE_HASH_INT(base, item) {\
    gchar *c; \
    c = (char*)g_hash_table_lookup(hash, #item); \
    if (c) base->item = atoi(c); \
    else base->item = 0; \
}

#define STORE_HASH_ENUM(base, item, type) {\
    gchar *c; \
    c = (char*)g_hash_table_lookup(hash, #item); \
    if (c) base->item = (type)atoi(c); \
    else base->item = (type)0; \
}

#define STORE_HASH_INT_DEF(base, item, def) {\
    gchar *c; \
    c = (char*)g_hash_table_lookup(hash, #item); \
    if (c) base->item = atoi(c); \
    else base->item = def; \
}

#define STORE_HASH_DOUBLE_DEF(base, item, def) {\
    gchar *c; \
    c = (char*)g_hash_table_lookup(hash, #item); \
    if (c) base->item = atof(c); \
	    else base->item = def; \
}

#define STORE_HASH_ENUM_DEF(base, item, type, def) {\
    gchar *c; \
    c = (char*)g_hash_table_lookup(hash, #item); \
    if (c) base->item = (type)atoi(c); \
    else base->item = def; \
}

#define STORE_HASH_CHR(base, item) {\
    gchar *c;\
    c=(char *)g_hash_table_lookup(hash, #item); \
    if (c) base->item = tolower(*c);\
    else c=NULL;\
}



#define NEW_EXC 1
#define NEW_WWL 2
#define NEW_DXC 4
#define NEW_PREF 8
#define NEW_MULT 16
#define NEW_PHASE 32


struct subwin;
struct wizz_item;
struct wizz_qsomult_item;

enum suspcall {
    SUSP_NONE,
    SUSP_QRB,
    SUSP_REM,
    SUSP_WARN,
    SUSP_ERR
};

struct qso{
    gchar *source; /* "192.168.0.1:1026" CONSTANT */
    gint  ser_id; /* 0..X in one source  CONSTANT */
    time_t stamp;  /* last modification  VARIABLE */
    
    gchar *operator_;
    
    gchar *date_str,*time_str; /* 20201101,1922 */
    gchar *callsign;
    gint  mode;
    gchar *rsts,*rstr;
    gchar *qsonrs,*qsonrr;
    gchar *exc, *locator;
    gchar *remark;
	gint phase;
    gint error;
    gdouble qrg;
   /* computed*/
    gint dupe,qsop,new_,qsl;
    gdouble qrb, qtfrad;
    gint qtf;
    gint susploc; /* 1=warn, 2=err */ 
    enum suspcall suspcall1; 
    gint unkcall;
    /* "foreign key", don't dealloc! */
    struct band *band;
    int kx,ky;
};

struct tmpqso{
    gchar *date_str,*time_str;
    gchar *callsign;
    gchar *rsts,*rstr;
    gchar *qsonrs,*qsonrr;
    gchar *exc, *locator;
    gchar *remark;
    gint dupe,qsl;
   /* computed*/
    gdouble qrb;
    gint qtf;
    gchar *name;
   /* ultimate values                     */
    gint ucallsign,udummy,ulocator,uexc;
    int uqrb,uqtf;
   /* suspicious */
    gint suspcallsign, susplocator, suspexc, unkcall;
};

#define ADD_TMPQSO_STRING(band,item,str,isu,uitem) {\
    int i; \
    if (band->tmpqsos[TMP_QSOS-1].item) { \
        g_free(band->tmpqsos[TMP_QSOS-1].item); \
        band->tmpqsos[TMP_QSOS-1].item = NULL; \
    }\
    for (i=TMP_QSOS-2;i>=0;i--) {\
        band->tmpqsos[i+1].item=band->tmpqsos[i].item; \
        band->tmpqsos[i+1].uitem=band->tmpqsos[i].uitem; \
    }\
    band->tmpqsos[0].item=g_strdup(str); \
    band->tmpqsos[0].uitem = isu; \
}

#define CLEAR_TMPQSO_STRING(band,item) {\
    if (band->tmpqsos[i].item) { \
        g_free(band->tmpqsos[i].item); \
        band->tmpqsos[i].item=NULL;\
    } \
}

#define CLEAR_TMPQSO_STRING_UU(band,item, uitem){ \
    int i; \
    for (i=0;i<TMP_QSOS;i++) {\
        if (!band->tmpqsos[i].uitem && band->tmpqsos[i].item) {\
            g_free(band->tmpqsos[i].item); \
            band->tmpqsos[i].item=NULL;\
        }\
    }\
}
    
#define ADD_TMPQSO_GINT(band,item,num,isu,uitem) {\
    int i; \
    for (i=TMP_QSOS-2;i>=0;i--) {\
        band->tmpqsos[i+1].item=band->tmpqsos[i].item; \
        band->tmpqsos[i+1].uitem=band->tmpqsos[i].uitem; \
    }\
    band->tmpqsos[0].item=num; \
    band->tmpqsos[0].uitem = isu; \
}

#define ADD_TMPQSO_GDOUBLE(band,item,num,isu,uitem) {\
    int i; \
    for (i=TMP_QSOS-2;i>=0;i--) {\
        band->tmpqsos[i+1].item=band->tmpqsos[i].item; \
        band->tmpqsos[i+1].uitem=band->tmpqsos[i].uitem; \
    }\
    band->tmpqsos[0].item=num; \
    band->tmpqsos[0].uitem = isu; \
}

#define CLEAR_TMPQSO_GINT(band,item) \
        band->tmpqsos[i].item=0

/*#define CLEAR_TMPQSO_GINT_UU(band,item, uitem) {\
    int i; \
    for (i=0;i<TMP_QSOS;i++) {\
        if (!band->tmpqsos[i].uitem) {\
            band->tmpqsos[i].item=0;\
        }\
    }\
} */
    
#define CLEAR_TMPQSO_GDOUBLE_UU(band,item, uitem) {\
    int i; \
    for (i=0;i<TMP_QSOS;i++) {\
        if (!band->tmpqsos[i].uitem) {\
            band->tmpqsos[i].item=0;\
        }\
    }\
}
    
#define CLEAR_TMPQSO_QTF(band) \
        band->tmpqsos[i].qtf=-1

#define CLEAR_TMPQSO_QTF_UU(band) {\
    int i; \
    for (i=0;i<TMP_QSOS;i++) {\
        if (!band->tmpqsos[i].uqtf) {\
            band->tmpqsos[i].qtf=-1;\
        }\
    }\
}
    
#define INPUTLN(b) (ctest && b ? b->il : gses->il)

void add_tmpqso_locator(struct band *b,gchar *c,int isu, int isshort); 
void add_tmpqso_exc(struct band *b,gchar *exc,int isu);

    
enum last_items{
    LI_NONE = 0,
    LI_CALL,
    LI_WWL
};

enum ctrlstates{
    CTRL_RUN = 0,       /* RUN, TX    */
    CTRL_SP = 1,        /* S&P, no TX */
    CTRL_REQR = 2,      /* RUN, TX    */
    CTRL_REQS = 3,      /* S&P, no TX */
    CTRL_RUNNING = 4,   /* S&P, TX    */
    CTRL_GIVEN = 5      /* RUN, no TX */
};

enum ccmd{
    CCMD_REQ = 0,       /* S&P->RUN */
    CCMD_ACC,           /* RUN->S&P */
    CCMD_REJ,           /* RUN->S&P */
    CCMD_BACK           /* S&P->RUN */
};

enum exctype {
    EXC_FREE = 1,
    EXC_VERIFIED = 2,
    EXC_WAZ = 3,
    EXC_ITU = 4,
    EXC_MULTIPLIED = 5
};

enum tttype{
    TT_NONE = 0,
    TT_RSTS = 1,
    TT_RSTR = 2,
    TT_QSONRR = 3,
    TT_EXC = 4
};


struct spypeer;

struct band{
    gchar bandchar;         /* 'C', 'E', 'G',  ...*/
    int bi;                 /* bandchar - 'A' */
    gchar *pband;           /* 144 MHz */ 
	gchar *bandname;        /* 2m,70cm,23cm... */  
    
    GPtrArray *qsos;
	GHashTable *rawqsoshash; // hash of raw QSOs. Value = qso
    struct inputln *il;
    struct tmpqso tmpqsos[TMP_QSOS];
    gchar  *unres, *qrv_str, *wkd_str;
    struct qso *dupe_qso;
    gint dirty_save, dirty_stats, dirty_statsf;
    gint readonly;
    gchar *call_played; // call played in run mode
    gint agcall;        // call was sent in autogive mode. RST follows
    gint iscall;        // currently played text is call
//    enum modes mode;  
//    gint bandmulti;
    gchar *operator_;

    gint psect;					// 0=multi, 1=single, 2=check, 3=other
	gchar *opsect;              // other psect
    gchar *stxeq,*spowe;        /* TM-255 + gi7b, 300 */ 
    gchar *srxeq,*sante,*santh; /* TM-255, GW4PTS, 60;800 */
    gchar *mope1,*mope2;    /* OK1XDF, OK1MZM, OK1ZIA */
    gchar *remarks;

    struct stats *stats;
    struct stats *tmpstats;
    GThread *stats_thread;
    MUTEX_DEFINE(stats);
//    GMutex *stats_mutex;
//#ifdef LEAK_DEBUG_LIST    
//    char *stats_file;
 //   int stats_line;    
//#endif
    int stats_break;
    
    /* file */
    FILE *swap;
    gint saveid,ignoreswap;

    struct fifo *swapfifo, *unfi, *statsfifo1;
    GPtrArray *qs, *oqs;
    enum last_items last_item;
    gchar *skedqrg;
    enum ctrlstates ctrlstate;
    gchar *ctrlsp;
/*    enum spymodes spymode;*/
    struct qso tmplocqso;
    GPtrArray *skeds;
    gint qrg_min,qrg_max;      /* kHz */
    int band_sw;
    struct config_band *cbr_confb; // local for cabrillo, not filled elsewhere!
    struct config_band *stf_confb; // local for stf, not filled elsewhere!
    double qrg;
	int qsomultb;
	double ac_k;	 // F1 band correction
	char *edifile;   // valid only after export
	char *mapfile, *chartfile; // valid only after export
    int wwlradius;
};


struct contest {
      /* EDI & contest properties */
    gchar *pcall;           /* DL/OK1KRQ/P */
    gchar *tname;           /* A1 Contest - MMC */
    gchar *tdate;           /* 130812;20130812 */
    gchar *pclub;           /* OK1KRQ */
    gchar *pwwlo;           /* JN69HN */
    gchar *pexch;  
    gchar *default_rs,*default_rst;


      /* EDI only properties */
    gchar *padr1,*padr2;    /* Lite */
    gchar *rname;           /* Roman Staif */
    gchar *rcall;           /* OK1XST */
    gchar *radr1,*radr2;  /* Pod svabinami  */ 
    gchar *rpoco,*rcity,*rcoun;  /* 30100, Plzen, CZECHIA */
    gchar *rphon,*rhbbs;    /* 0603123456 , OK0POK */ 
    
      /* contest properties */
    gint  rstused;          /* no,used, optional */
    gint  defrstr;          
    gint  qsoused;          /* no,used, optional */
    gint  wwlused;          /* no,used, optional */
    gint  wwltype;          /* short,normal,extended */
    gint  wwlcfm;
    gint  excused;          /* no,used, optional */
    enum exctype exctype;  
    gchar *excname;         /* database name f.e. OKRES */
    gint  exccfm;
    enum tttype  tttype;
    int qsoglob;            /* qsonr is global in contest */
    gint prefglob;          /* prefix is global in contest */
    gint expmode;           /* epedition mode */
	gint phase;             /* contest phase 1..N */
    
    
      /* points calculation */
    gint qsomult;
    gint wwlbonu,wwlmult;
    gint prefmult;
    gint dxcbonu,dxcmult;  
    gint excbonu,excmult;
    gint qsop_method;            /* 1..12 */
    gint total_method;       /* 1..2 */
    
    GPtrArray *bands;
    GHashTable *bystamp;  /* key=source, val=ZPtrArray */
                          /* ZPtrArrays are NOT sorted by ser_id but only by stamp */
    ZPtrArray *allqsos;
    gint exclen;
    
     /* disk */
    FILE *lockfile;     /* ~/tucnak/.../desc.lock */ 
    FILE *logfile;      /* ~/tucnak/.../log */ 
    gchar *directory;   /* /home/ok1zia/tucnak/20021113.2 */
    gchar *cdate;       /* 20021113 without .X */ 
     /* autosave */
    int as_disk_qsonr, as_disk_time, as_floppy_qsonr, as_floppy_time;
    
    
    int qrv;             /* bit array of used bands */
    int oldcontest;      /* date of contest is too old, not recording */

	int minute_timer_id; /* for statistics */
    int hf;              /* HF contest */
    GPtrArray *spypeers; /* of struct spypeer */

    int allb_nqsos;
    int allb_nqsop;
    int allb_nwwlp;
    int allb_nprefp;
    int allb_ndxcp;
    int allb_nexcp;
    int allb_ntotal;
    int allb_nmult;
    GHashTable *allb_prefs;
    int runmode;
    int qso_per_10, qso_per_60;
    struct qso *lastmultqso;
};


extern struct contest *ctest;
extern struct band *aband;
struct conn;
extern char *mode_msg[];
enum modes;

int init_ctest(void);
int new_ctest(char *tdate); /* called after filling data members by refresh_... */
void free_ctest(void);
struct band *init_band(struct config_band *, GHashTable *opt_band, struct zstring *zs, struct wizz_qsomult_item *wqi);
void free_band(struct band *b);
void free_qso(struct qso *qso);
struct band *find_band_by_pband(char *pband);
struct band *find_band_by_bandchar(char bandchar);
struct band *find_band_by_qrg(double freq);
struct band *init_qrv_bands(struct wizz_item *wi);
int write_qso_to_swap(struct band *b, struct qso *q);
void add_qso(struct band *b, struct qso *q);
struct qso *get_qso(struct band *b, gint i);
struct qso *get_qso_by_callsign(struct band *b, gchar *callsign);
struct qso *get_gqso(struct band *b, struct subwin *sw, gint i);
//int get_qso_index_by_callsign(struct band *b, gchar *callsign);
struct qso *get_qso_by_id(struct band *b, gchar *source, gint ser_id);
struct qso *get_qso_by_qsonr(struct band *b, int qsonr);
void add_error(struct band *b, gchar *remark);
void activate_band(struct band *b);
int add_tmpxchg(struct band *band, gchar *xchg);
int add_swap(struct band *band, gchar *s);
void clear_tmpqsos(struct band *b, int set_defaults);
void default_rst_to_tmpqsos(struct band *b);

int export_all_bands_report(void);
int export_all_bands_titlpage(void);
struct config_band *get_config_band_by_bandchar(char bandchar);
struct config_band *get_config_band_by_pband(char *pband);
struct config_band *get_config_band_by_qrg(int qrg); /* kHz */
void foreach_source_recalc_ser_id(gpointer key, gpointer value, gpointer data);
void foreach_source_qsort_by_stamp(gpointer key, gpointer value, gpointer data);
void foreach_source_print(gpointer key, gpointer value, gpointer data);

void add_qso_to_index(struct qso *q, int qsort_if_needed);
void remove_qso_from_index(struct qso *q);
gchar *get_latests_str(void);
int compare_stamp(const void *a, const void *b);
void compute_qrbqtf(struct qso *q);
GPtrArray *get_band_qs(struct band *band, gchar *str);
GPtrArray *get_oband_qs(struct band *band, gchar *str);
gchar *find_wwl_by_oband(struct band *oband, gchar *call);
gchar *find_exc_by_oband(struct band *oband, gchar *call);
int load_ctest_from_mem(struct contest *ctest, gchar *datedir, GHashTable *hash);
void qso_mark_as_error(struct band *b, gint i);
int get_psect_int(char *psect);
void dump_qso(struct qso *q, char *desc);
void invalidate_tmpqso(struct band *b, struct qso *q);
void dirty_band(struct band *band);
struct zstring *contest_format(struct contest *ctest);
void ctest_parse(struct zstring *zstr, struct contest *ctest);
struct zstring *band_format(struct band *b);
struct band *band_parse(struct zstring *zstr, struct band *b);
int compare_date_time_qsonrs(const void *a, const void *b);
void set_mode(enum modes mode);
enum modes get_mode(void);
int worked_on_all_rw(char *call); // worked on all read-write band
int worked_on_aband(char *call);

void dump_rw(void *a, void *b);
int add_qsos_from_swap(struct band *b, FILE *f);
void free_bystamp_value(gpointer value);

#endif
