#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <linux/wireless.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include <unistd.h>
#include <stdarg.h>
#include <stdio.h>      /*標準輸入輸出定義*/
#include <stdlib.h>     /*標準函數庫定義*/
#include <unistd.h>     /*Unix 標準函數定義*/
#include <fcntl.h>      /*檔控制定義*/
#include <termios.h>    /*PPSIX 終端控制定義*/
#include <errno.h>      /*錯誤號定義*/
#include <errno.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <ifaddrs.h>

#include "../Log/log.h"
#include "../ShareMemory/shmMem.h"
#include "../DataBase/DataBase.h"
#include "../Define/define.h"
#include "../Config.h"

//------------------------------------------------------------------------------
//struct SysConfigAndInfo         *ShmSysConfigAndInfo;
//struct StatusCodeData           *ShmStatusCodeData;
static struct SysConfigData *pSysConfig      = NULL;
static struct SysInfoData *pSysInfo          = NULL;
static struct WARNING_CODE_INFO *pSysWarning = NULL;
static struct AlarmCodeData *pAlarmCode      = NULL;
static struct InfoCodeData *pInfoCode        = NULL;
static struct FaultCodeData *pFaultCode      = NULL;

//sqlite3 *localDb; //DS60-120 add

//------------------------------------------------------------------------------
#define WRITE_FLASH_TIME                        (128)
#define DB_FILE             "/Storage/ChargeLog/localCgargingRecord.db" //DS60-120 add

//#define log_info(format, args...) StoreLogMsg("[%s:%d][%s][Info] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
//#define log_warn(format, args...) StoreLogMsg("[%s:%d][%s][Warn] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
//#define log_error(format, args...) StoreLogMsg("[%s:%d][%s][Error] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
#define event_info(format, args...) StoreEventLogMsg("[%s:%d][%s][Info] "format, (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)), __LINE__, __FUNCTION__, ##args) //DS60-120 add

/*
int StoreLogMsg(const char *fmt, ...)
{
    char Buf[4096 + 256];
    char buffer[4096];
    va_list args;
    struct timeb  SeqEndTime;
    struct tm *tm;

    va_start(args, fmt);
    int rc = vsnprintf(buffer, sizeof(buffer), fmt, args);
    va_end(args);

    memset(Buf, 0, sizeof(Buf));
    ftime(&SeqEndTime);
    SeqEndTime.time = time(NULL);
    tm = localtime(&SeqEndTime.time);

    if (ShmSysConfigAndInfo->SysConfig.SwitchDebugFlag == YES) {
        sprintf(Buf, "%02d:%02d:%02d:%03d - %s",
                tm->tm_hour, tm->tm_min, tm->tm_sec, SeqEndTime.millitm, buffer);
        printf("%s ", Buf);
    } else {
        sprintf(Buf, "echo \"%04d-%02d-%02d %02d:%02d:%02d:%03d - %s\" >> /Storage/SystemLog/[%04d.%02d]SystemLog",
                tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, SeqEndTime.millitm,
                buffer,
                tm->tm_year + 1900, tm->tm_mon + 1);
        system(Buf);
    }

    return rc;
}

int StoreEventLogMsg(const char *fmt, ...)
{
    char Buf[4096 + 256];
    char buffer[4096];
    time_t CurrentTime;
    struct tm *tm;
    struct timeval tv;
    va_list args;

    va_start(args, fmt);
    int rc = vsnprintf(buffer, sizeof(buffer), fmt, args);
    va_end(args);

    memset(Buf, 0, sizeof(Buf));
    CurrentTime = time(NULL);
    tm = localtime(&CurrentTime);
    gettimeofday(&tv, NULL); // get microseconds, 10^-6

    if ((ShmSysConfigAndInfo->SysConfig.ModelName != NULL) && (ShmSysConfigAndInfo->SysConfig.SerialNumber != NULL) && (strlen((char *)ShmSysConfigAndInfo->SysConfig.ModelName) >= 14)) {
        sprintf(Buf, "echo -n \"[%04d.%02d.%02d %02d:%02d:%02d.%06ld]%s\" >> /Storage/EventLog/[%04d.%02d]%s_%s_EventLog",
                tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec,
                buffer,
                tm->tm_year + 1900, tm->tm_mon + 1,
                ShmSysConfigAndInfo->SysConfig.ModelName,
                ShmSysConfigAndInfo->SysConfig.SerialNumber);
    } else {
        sprintf(Buf, "echo -n \"[%04d.%02d.%02d %02d:%02d:%02d.%06ld]%s\" >> /Storage/EventLog/[%04d.%02d]EventLog",
                tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec,
                buffer,
                tm->tm_year + 1900, tm->tm_mon + 1);
    }

#ifdef SystemLogMessage
    system(Buf);

#endif

#ifdef ConsloePrintLog
    printf("[%04d.%02d.%02d %02d:%02d:%02d.%06ld]%s", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec, buffer);
#endif

    return rc;
}

int DiffTimeb(struct timeb ST, struct timeb ET)
{
    //return milli-second
    unsigned int StartTime, StopTime;

    StartTime = (unsigned int)ST.time;
    StopTime = (unsigned int)ET.time;
    return (StopTime - StartTime) * 1000 + ET.millitm - ST.millitm;
}

//=================================
// Common routine
//=================================
char *getTimeString(void)
{
    char *result = malloc(21);
    time_t timep;
    struct tm *p;
    time(&timep);
    p = gmtime(&timep);

    sprintf(result, "[%04d-%02d-%02d %02d:%02d:%02d]", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, p->tm_hour, p->tm_hour, p->tm_sec);

    return result;
}

//==========================================
// Init all share memory
//==========================================
int InitShareMemory()
{
    int result = PASS;
    int MeterSMId;

    //creat ShmSysConfigAndInfo
    if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo),  0777)) < 0) {
        result = FAIL;
    } else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) - 1) {
        result = FAIL;
    }

    //creat ShmStatusCodeData
    if ((MeterSMId = shmget(ShmStatusCodeKey, sizeof(struct StatusCodeData),  0777)) < 0) {
        result = FAIL;
    } else if ((ShmStatusCodeData = shmat(MeterSMId, NULL, 0)) == (void *) - 1) {
        result = FAIL;
    }

    return result;
}
*/

//================================================
// Main process
//================================================
void AddFaultCodeToBuf(uint8_t *Code)
{
    if (pSysWarning->WarningCount < 10) {
        memcpy(&pSysWarning->WarningCode[pSysWarning->WarningCount][0], Code, 7);
        pSysWarning->WarningCount++;
    }
}

void RemoveFaultCodeToBuf(uint8_t *Code)
{
    uint8_t find = 0x01;
    char _code[7];
    sprintf(_code, "%s", Code);

    // 把相關的錯誤碼一次移除,避免重複顯示
    while (find) {
        find = 0x00;
        for (uint8_t i = 0; i < pSysWarning->WarningCount; i++) {
            if (find == 0x00) {
                if (memcmp(&pSysWarning->WarningCode[i][0], _code, 7) == 0) {
                    find = 0x01;
                }
            } else {
                memcpy(&pSysWarning->WarningCode[i - 1][0],
                       &pSysWarning->WarningCode[i][0], 7);
            }
        }

        if (find) {
            pSysWarning->WarningCount--;
        }
    }
}

#if 0
//==========================================
// SQLite routne
//==========================================
int DB_Open(sqlite3 *db) //DS60-120 add
{
    int result = PASS;
    char *errMsg = NULL;
    char *createRecordSql = "CREATE TABLE IF NOT EXISTS event_record("
                            "idx integer primary key AUTOINCREMENT, "
                            "occurDatetime text NOT NULL, "
                            "statusCode text NOT NULL"
                            ");";

    if (sqlite3_open(DB_FILE, &db)) {
        result = FAIL;
        log_error( "Can't open database: %s", sqlite3_errmsg(db));
        sqlite3_close(db);
    } else {
        log_info( "Local event record database open successfully.");

        if (sqlite3_exec(db, createRecordSql, 0, 0, &errMsg) != SQLITE_OK) {
            result = FAIL;
            log_error( "Create local event record table error message: %s", errMsg);
        } else {
            log_info( "Opened local event record table successfully");
        }

        sqlite3_close(db);
    }

    return result;
}

int DB_Insert_Record(sqlite3 *db, uint8_t *statusCode) //DS60-120 add
{
    int result = PASS;
    char *errMsg = NULL;
    char sqlStr[1024];

    sprintf(sqlStr, "insert into event_record(occurDatetime, statusCode) values(CURRENT_TIMESTAMP, '%s');", statusCode);

    if (sqlite3_open(DB_FILE, &db)) {
        result = FAIL;
        log_info( "Can't open database: %s", sqlite3_errmsg(db));
        sqlite3_close(db);
    } else {
        log_info( "Local event record database open successfully.");
        if (sqlite3_exec(db, sqlStr, 0, 0, &errMsg) != SQLITE_OK) {
            result = FAIL;
            log_info( "Insert local event record error message: %s", errMsg);
        } else {
            log_info( "Insert local event record successfully");
        }

        sprintf(sqlStr, "delete from event_record where idx < (select idx from event_record order by idx desc limit 1)-2000;");
        if (sqlite3_exec(db, sqlStr, 0, 0, &errMsg) != SQLITE_OK) {
            result = FAIL;
            log_info( "delete local event_record error message: %s", errMsg);
        } else {
            log_info( "delete local event record successfully");
        }

        sqlite3_close(db);
    }

    return result;
}
#endif //0

int main(void)
{
    int ByteCounter, BitCounter;
    uint8_t tmp, EventCodeTmp[7] = {0};

    //if (InitShareMemory() == FAIL) {
    //    log_error("InitShareMemory NG");
    //    if (ShmStatusCodeData != NULL) {
    //        pAlarmCode->AlarmEvents.bits.FailToCreateShareMemory = 1;
    //    }
    //    sleep(5);
    //    return 0;
    //}
    if (CreateAllCsuShareMemory() == FAIL) {
        log_error("create share memory error");
        return FAIL;
    }

    MappingGunChargingInfo("EventLog Task");

    pSysConfig = (struct SysConfigData *)GetShmSysConfigData();
    pSysInfo = (struct SysInfoData *)GetShmSysInfoData();
    pSysWarning = (struct WARNING_CODE_INFO *)GetShmSysWarningInfo();

    pAlarmCode = (struct AlarmCodeData *)GetShmAlarmCodeData();
    pInfoCode = (struct InfoCodeData *)GetShmInfoCodeData();
    pFaultCode = (struct FaultCodeData *)GetShmFaultCodeData();


    for (;;) {
        //check Fault Status
        for (ByteCounter = 0; ByteCounter < sizeof(pFaultCode->PreviousFaultVal); ByteCounter++) {
            usleep(WRITE_FLASH_TIME);
            if (pFaultCode->FaultEvents.FaultVal[ByteCounter] == pFaultCode->PreviousFaultVal[ByteCounter]) {
                continue;
            }

            tmp = pFaultCode->FaultEvents.FaultVal[ByteCounter]; //prevent be modified during following process
            for (BitCounter = 0; BitCounter < 8; BitCounter++) {
                usleep(WRITE_FLASH_TIME);
                if (((tmp >> BitCounter) & 0x01) == ((pFaultCode->PreviousFaultVal[ByteCounter] >> BitCounter) & 0x01)) {
                    continue;
                }

                memset(EventCodeTmp, 0, sizeof(EventCodeTmp));
                memcpy(EventCodeTmp, GetFaultStatusCode(ByteCounter * 8 + BitCounter), sizeof(EventCodeTmp) - 1);
                if (((tmp >> BitCounter) & 0x01) == 0) { //Recovered
                    //EventCodeTmp[0]=1;
                    log_info("Recovery Fault Code = %s", EventCodeTmp);
                    pFaultCode->PreviousFaultVal[ByteCounter] &= ~(1 << BitCounter);
                    RemoveFaultCodeToBuf(EventCodeTmp);
                    EventCodeTmp[0] = '1';//DS60-120 add
                } else {
                    log_info("Fault Code = %s", EventCodeTmp);
                    pFaultCode->PreviousFaultVal[ByteCounter] |= (1 << BitCounter);
                    AddFaultCodeToBuf(EventCodeTmp);
                }
                event_info("%s", EventCodeTmp); //DS60-120 add
                InsertEventRecord(EventCodeTmp); //DS60-120 add
            }
        }

        //check Alarm Status
        for (ByteCounter = 0; ByteCounter < sizeof(pAlarmCode->PreviousAlarmVal); ByteCounter++) {
            usleep(WRITE_FLASH_TIME);
            if (pAlarmCode->AlarmEvents.AlarmVal[ByteCounter] == pAlarmCode->PreviousAlarmVal[ByteCounter]) {
                continue;
            }

            tmp = pAlarmCode->AlarmEvents.AlarmVal[ByteCounter]; //prevent be modified during following process
            for (BitCounter = 0; BitCounter < 8; BitCounter++) {
                usleep(WRITE_FLASH_TIME);
                if (((tmp >> BitCounter) & 0x01) == ((pAlarmCode->PreviousAlarmVal[ByteCounter] >> BitCounter) & 0x01)) {
                    continue;
                }

                memset(EventCodeTmp, 0, sizeof(EventCodeTmp));
                memcpy(EventCodeTmp, GetAlarmStatusCode(ByteCounter * 8 + BitCounter), sizeof(EventCodeTmp) - 1);
                if (((tmp >> BitCounter) & 0x01) == 0) { //Recovered
                    //EventCodeTmp[0]=1;
                    log_info("Recovery Alarm Code = %s", EventCodeTmp);
                    pAlarmCode->PreviousAlarmVal[ByteCounter] &= ~(1 << BitCounter);
                    RemoveFaultCodeToBuf(EventCodeTmp);
                    EventCodeTmp[0] = '1';//DS60-120 add
                } else {
                    log_info("Alarm Code = %s", EventCodeTmp);
                    pAlarmCode->PreviousAlarmVal[ByteCounter] |= (1 << BitCounter);
                    AddFaultCodeToBuf(EventCodeTmp);
                }
                event_info("%s", EventCodeTmp); //DS60-120 add
                InsertEventRecord(EventCodeTmp); //DS60-120 add
            }
        }

        //check Info Status
        for (ByteCounter = 0; ByteCounter < sizeof(pInfoCode->PreviousInfoVal); ByteCounter++) {
            usleep(WRITE_FLASH_TIME);
            if (pInfoCode->InfoEvents.InfoVal[ByteCounter] == pInfoCode->PreviousInfoVal[ByteCounter]) {
                continue;
            }

            tmp = pInfoCode->InfoEvents.InfoVal[ByteCounter]; //prevent be modified during following process
            for (BitCounter = 0; BitCounter < 8; BitCounter++) {
                usleep(WRITE_FLASH_TIME);
                if (((tmp >> BitCounter) & 0x01) == ((pInfoCode->PreviousInfoVal[ByteCounter] >> BitCounter) & 0x01)) {
                    continue;
                }

                memset(EventCodeTmp, 0, sizeof(EventCodeTmp));
                memcpy(EventCodeTmp, GetInfoStatusCode(ByteCounter * 8 + BitCounter), sizeof(EventCodeTmp) - 1);
                if (((tmp >> BitCounter) & 0x01) == 0) { //Recovered
                    //EventCodeTmp[0]=1;
                    log_info("Recovery Info Code = %s", EventCodeTmp);
                    pInfoCode->PreviousInfoVal[ByteCounter] &= ~(1 << BitCounter);
                    RemoveFaultCodeToBuf(EventCodeTmp);
                    EventCodeTmp[0] = '1';//DS60-120 add
                } else {
                    log_info("Info Code = %s", EventCodeTmp);
                    pInfoCode->PreviousInfoVal[ByteCounter] |= (1 << BitCounter);
                    AddFaultCodeToBuf(EventCodeTmp);
                }
                event_info("%s", EventCodeTmp); //DS60-120 add
                InsertEventRecord(EventCodeTmp); //DS60-120 add
            }
        }
        usleep(500000);
    }

    return FAIL;
}