#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <time.h>
//#ifdef __MACH__
//#include <mach/clock.h>
//#include <mach/mach.h>
//#endif
#if defined(__WIN32) || defined(_WIN64)
//#include "stdafx.h"
#include <Windows.h>
#endif

#include "cwg-shared.h"
#include "logutils.h"
#include "licor8xx-shared.h"
#include "iowfile.h"

#define OFILE_PATH_DFL "lgen.000"
#define SAMPLE_PERIOD_SEC 600
#define SAMPLES_PER_PERIOD 2
#define SAMPLES_PER_HOUR (SAMPLES_PER_PERIOD*3600UL/SAMPLE_PERIOD_SEC)
#define SAMPLES_PER_DAY (SAMPLES_PER_HOUR*24)
#define LOG_DAYS 1
#define MEAS_COUNT 6

//#if defined(__MACH__)
//// OSX clocks
//// CALENDAR_CLOCK, HIGHRES_CLOCK
//#define MTIME_DTIME_CLOCK CALENDAR_CLOCK
//#define MTIME_ETIME_CLOCK CALENDAR_CLOCK
//#elif defined(__QNX__)
//// QNX clocks
//// CLOCK_REALTIME
//#define MTIME_DTIME_CLOCK CLOCK_REALTIME
//#define MTIME_ETIME_CLOCK CLOCK_REALTIME
//#else
//// linux clocks
//// CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_MONOTONIC_RAW
//// CLOCK_PROCESS_CPUTIME_ID
//#define MTIME_DTIME_CLOCK CLOCK_MONOTONIC
//#define MTIME_ETIME_CLOCK CLOCK_REALTIME
//#endif

typedef struct app_cfg_s{
    char *opath;
    FILE_T *fp;
    int sample_period_sec;
    int samples_per_period;
    int samples_per_hour;
    int samples_per_day;
    int log_days;
    int meas_count;
}app_cfg_t;

/// @fn void s_termination_handler (int signum)
/// @brief termination signal handler.
/// @param[in] signum signal number
/// @return none
static void s_termination_handler (int signum)
{
    switch (signum) {
#if ! defined(__WIN32) && ! defined(__WIN64)
        case SIGHUP:
#endif
        case SIGINT:
        case SIGTERM:
            fprintf(stderr,"\nsig received[%d]\n",signum);
            g_logutils_interrupt=true;
            break;
        default:
            fprintf(stderr,"\ns_termination_handler: sig not handled[%d]\n",signum);
            break;
    }
}
// End function termination_handler

static int s_log_gen(app_cfg_t *cfg)
{
    int retval=-1;

    if(iow_fopen(&cfg->fp, cfg->opath, IOW_WRITE|IOW_CREATE_ALWAYS)==0){
        uint32_t i=0;

        UINT zrec_sz = LI_ZREC_SIZEN(MEAS_COUNT);
        byte zrec_mem[zrec_sz];
        licor_zrecord_t *zrec=(licor_zrecord_t *)zrec_mem;
        mdata_Z_t *mdata=LI_ZREC_PMDATA(zrec);

        // init time stamp with current time

//        struct timespec ts;
//        memset(&ts,0,sizeof(struct timespec));
//
//#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
//        clock_serv_t cclock;
//        mach_timespec_t mts;
//        host_get_clock_service(mach_host_self(), MTIME_ETIME_CLOCK, &cclock);
//        clock_get_time(cclock, &mts);
//        mach_port_deallocate(mach_task_self(), cclock);
//        ts.tv_sec = mts.tv_sec;
//        ts.tv_nsec = mts.tv_nsec;
//#else
//        clock_gettime(MTIME_ETIME_CLOCK, &ts);
//#endif

//        time_t tt_now = ts.tv_sec;
        time_t tt_now=time(NULL);
        struct tm *tm_now=gmtime(&tt_now);
        tt_now = mktime(tm_now);
        uint64_t tems=1000LLU*tt_now;

        int var_meas_count=MEAS_COUNT;

        uint32_t record_count=cfg->samples_per_day*cfg->log_days;
        OUT_CTTY("writing %"FMT_U32" records...(q to quit)\r\n",record_count);
        for(i=0;i<record_count;i++){
            ZERO_MEM(zrec,zrec_sz);

            // BUG FIX: multiply by i overflows struct tm year
            //               tems+=(uint64_t)(1000LLU*i*SAMPLE_PERIOD_SEC/SAMPLES_PER_PERIOD);
            tems+=(uint64_t)(1000LLU*cfg->sample_period_sec/cfg->samples_per_period);
            zrec->hdr.timestamp=tems;
            zrec->hdr.meas_id=i%RMID_COUNT;
            zrec->hdr.type_id=RTID_ZRECv0;
            zrec->hdr.seq_n=i;
            zrec->hdr.sync=LI_ZREC_SYNC;
            var_meas_count++;
            if((var_meas_count%MEAS_COUNT)==0){
                var_meas_count++;
            }else{
                var_meas_count=(var_meas_count%MEAS_COUNT);
            }
            int mcount =( (cfg->meas_count>0) ? cfg->meas_count : var_meas_count);
            zrec->hdr.len=mcount*LI_ZREC_MDATA_LEN;
            zrec->hdr.meas_count=mcount;
            int j=0;
            size_t btw=0;
            size_t bw=0;
            for(j=0;j<mcount;j++){
                btw=LI_ZREC_SIZEN(mcount);//LI_ZREC_MDATA_LEN;
                bw=0;
                int k=0;
                for(k=0;k<ZID_FIELD_COUNT;k++){
                    mdata[j].min[k]=1.;
                    mdata[j].max[k]=2.;
                    mdata[j].M[k]=3.;
                    mdata[j].S[k]=4.;
                }
                for(k=0;k<ZID_EXTRA_COUNT;k++){
                    mdata[j].X[k]=10.*k;
                }
//                memset(&mdata[j],('A'+j),LI_ZREC_MDATA_LEN);

                mdata[j].meas_id=1+i%MMID_COUNT;
                mdata[j].period=0.5;
                mdata[j].stat_n=5+i%10;
                mdata[j].timestamps[0]=tems-20000LLU;
                mdata[j].timestamps[1]=tems;
            }
            btw=zrec_sz;
            bw=0;
            if( (bw=iow_fwrite(cfg->fp,zrec,btw))==btw ){
                if( i!=0 && (i%100) == 0){
                    OUT_CTTY("\b\b\b\b\b\b%6d",i);
                }
            }else{
                OUT_CTTY("\r\nwrite error fp[%"FMT_U32"] btw[%"FMT_SZ"] bw[%"FMT_SZ"] fr[%d]\r\n",iow_ftell(cfg->fp),btw,bw,iow_errno);
                break;
            }
            byte ctrl=iow_get_char(false);
            if(ctrl=='q' || ctrl=='Q')break;
        }// end for

        iow_fclose(cfg->fp);
        cfg->fp=NULL;

        OUT_CTTY("\r\ndone - wrote %d records\r\n",i);
    }// else open error

    return retval;
}

int main(int argc, char **argv)
{
    int retval=-1;
    
#if defined(__WIN32) || defined(__WIN64)
    signal(SIGINT,s_termination_handler);
#else
    // configure signal handling
    // for main thread
    struct sigaction saStruct;

    sigemptyset(&saStruct.sa_mask);
    saStruct.sa_flags = 0;
    saStruct.sa_handler = s_termination_handler;
    sigaction(SIGINT, &saStruct, NULL);
#endif

    app_cfg_t cfg_s={
        strdup(OFILE_PATH_DFL),
        NULL,
        SAMPLE_PERIOD_SEC,
        SAMPLES_PER_PERIOD,
        SAMPLES_PER_HOUR,
        SAMPLES_PER_DAY,
        LOG_DAYS,
        MEAS_COUNT
    };
    app_cfg_t *cfg=&cfg_s;

    int i=0;
    while(i<argc){
        OUT_CONS("argc[%d] argv[%d] [%s]\r\n",argc,i,argv[i]);

        if(sscanf(argv[i],"p%d",&cfg->sample_period_sec)==1){
            OUT_CONS("%15s  [%d]\r\n","sample_period_sec",cfg->sample_period_sec);
        }else if(sscanf(argv[i],"s%d",&cfg->samples_per_period)==1){
            OUT_CONS("%15s  [%d]\r\n","samples_per_period",cfg->samples_per_period);
        }else if(sscanf(argv[i],"d%d",&cfg->log_days)==1){
            OUT_CONS("%15s  [%d]\r\n","samples_per_period",cfg->log_days);
        }else if(sscanf(argv[i],"m%d",&cfg->meas_count)==1){
            OUT_CONS("%15s  [%d]\r\n","meas_count",cfg->meas_count);
        }else if(strstr(argv[i],"f:")!=NULL){
            if(NULL!=cfg->opath)free(cfg->opath);
            cfg->opath=strdup( (argv[i]+2) );
            OUT_CONS("%15s  [%s]\r\n","opath",cfg->opath);
        }
        i++;
    }

    cfg->samples_per_hour = cfg->samples_per_period*3600/cfg->sample_period_sec;
    cfg->samples_per_day = cfg->samples_per_hour*24;

    retval=s_log_gen(cfg);

    if(NULL!=cfg->opath)free(cfg->opath);
    if(NULL!=cfg->fp){
        iow_fclose(cfg->fp);
        cfg->fp=NULL;
    }

    return retval;
}// end main
