#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/can.h>
#include 	<linux/can/raw.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	"../../define.h"
#include 	"Config.h"

#define Debug
#define ARRAY_SIZE(A)		(sizeof(A) / sizeof(A[0]))
#define PASS				1
#define FAIL				-1
#define OUTPUT_FLASH		0x01
#define OUTPUT_FILE			0x02

struct SysConfigData 			SysConfig;
struct SysConfigAndInfo         *ShmSysConfigAndInfo;

int StoreLogMsg(const char *fmt, ...);

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);

	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 runShellCmd(const char *cmd)
{
    int result = FAIL;
    char buf[256];
    FILE *fp;

    fp = popen(cmd, "r");
    if(fp != NULL)
    {
        while(fgets(buf, sizeof(buf), fp) != NULL)
        {
            StoreLogMsg("%s\n", buf);
        }

        result = PASS;
    }
    pclose(fp);

    return result;
}

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

    //creat ShmSysConfigAndInfo
    if((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo),  0777)) < 0)
    {
        StoreLogMsg("shmget ShmSysConfigAndInfo NG\n");

        result = FAIL;
    }
    else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
        StoreLogMsg("shmat ShmSysConfigAndInfo NG\n");

        result = FAIL;
     }
    else
    {

    }

    return result;
}

void helpOutput(void)
{
    printf("Usage: Module_FactoryConfig [OPTION]...\r\n\r\n");
    printf("Generate factory default configuration value\r\n\r\n");
    printf("OPTION:\r\n");
    printf("    -a Write to file(/mnt) & flash\r\n");
    printf("    -f Write to file(/mnt)\r\n");
    printf("    -m Write to flash\r\n");
}

/**************************************************************************************/
/************This task will create Factory default confgiuration file *****************/
/***********and store it into mtdblock 10,11,12                        ****************/
/**************************************************************************************/
int main(int argc,char *argv[])
{
	unsigned char outType=0;
	unsigned int i,Chk, MtdBlockSize=0x300000;
	unsigned char *ptr;
	int fd,wrd;

	ptr=malloc(MtdBlockSize);
	if(ptr==NULL)
	{
		#ifdef SystemLogMessage
		StoreLogMsg("[FactoryConfig]main: malloc for SysConfigData NG");
		#endif
		return 0;
	}
	memset(ptr, 0, MtdBlockSize);
	memset(&SysConfig, 0, sizeof(struct SysConfigData));

	/*
	 * TODO: Set factory default configuration
	*/
	//********** System **********// udhcpc -i eth1 -s ./dhcp_script/eth1.script
	//
    time_t t = time(NULL);
    struct tm tm = *localtime(&t);

    // Initial Share Memory
    if(InitShareMemory() == FAIL)
    {
        StoreLogMsg("InitShareMemory NG\n");

        //strcpy((char*)SysConfig.ModelName, "");
        //strcpy((char*)SysConfig.SerialNumber, "");
        strcpy((char *)SysConfig.ModelName, "DOYC362000D2PH");
        strcpy((char *)SysConfig.SerialNumber, "NeedSetupSN");
        sleep(5);
    }
    else
    {
        memcpy((char*)SysConfig.ModelName, ShmSysConfigAndInfo->SysConfig.ModelName, ARRAY_SIZE(ShmSysConfigAndInfo->SysConfig.ModelName));
        memcpy((char*)SysConfig.SerialNumber, ShmSysConfigAndInfo->SysConfig.SerialNumber, ARRAY_SIZE(ShmSysConfigAndInfo->SysConfig.SerialNumber));

        StoreLogMsg("InitShareMemory OK.\n");
    }

    sprintf((char*)SysConfig.SystemId, "%s%s", SysConfig.ModelName, SysConfig.SerialNumber);
    sprintf((char*)SysConfig.SystemDateTime, "%d-%d-%d %d:%d:%d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
	SysConfig.AuthorisationMode = AUTH_MODE_ENABLE;
	SysConfig.DefaultLanguage = 0;
	SysConfig.RfidCardNumEndian = 0;
	SysConfig.AcPlugInTimes = 0;
	SysConfig.GbPlugInTimes = 0;
	SysConfig.Ccs1PlugInTime = 0;
	SysConfig.Ccs2PlugInTimes = 0;
	SysConfig.ChademoPlugInTimes = 0;
	SysConfig.BillingData.isBilling = 0;
	SysConfig.BillingData.Currency = 50;
	SysConfig.isAPP = 1;
	SysConfig.isQRCode = 1;
	SysConfig.isRFID = 1;
	//********** Charging **********//
	SysConfig.MaxChargingEnergy = 0;
	SysConfig.MaxChargingCurrent = 0;		// 最大可輸出電流 (整樁)
	SysConfig.MaxChargingDuration = 0;
	SysConfig.AcMaxChargingCurrent = 0;
	SysConfig.PhaseLossPolicy = 0;
	for(unsigned char i = 0; i < 10; i++)
		strcpy((char *)SysConfig.LocalWhiteCard, "");

	strcpy((char *)SysConfig.UserId, "");
	//********** Network **********//
	strcpy((char *)SysConfig.FtpServer, "");
	SysConfig.Eth0Interface.EthDhcpClient = 0;
	strcpy((char *) SysConfig.Eth0Interface.EthIpAddress, "192.168.1.10");
	strcpy((char *) SysConfig.Eth0Interface.EthSubmaskAddress, "255.255.255.0");
	strcpy((char *) SysConfig.Eth0Interface.EthGatewayAddress, "192.168.1.254");
	SysConfig.Eth1Interface.EthDhcpClient = 0;
#if ENABLE_PCBA_TEST == 0
	strcpy((char *) SysConfig.Eth1Interface.EthIpAddress, "192.168.100.1");
#else
	strcpy((char *) SysConfig.Eth1Interface.EthIpAddress, "192.168.0.10");
#endif
	strcpy((char *) SysConfig.Eth1Interface.EthSubmaskAddress, "255.255.255.0");
	strcpy((char *) SysConfig.Eth1Interface.EthGatewayAddress, "192.168.100.254");
	SysConfig.AthInterface.WifiMode = 0;
	SysConfig.TelecomInterface.TelcomEnabled = 0;
	strcpy((char *) SysConfig.AthInterface.WifiSsid, "");
	strcpy((char *) SysConfig.AthInterface.WifiPassword, "");
	SysConfig.AthInterface.WifiRssi = 0;
	SysConfig.AthInterface.WifiDhcpServer = 0;
	SysConfig.AthInterface.WifiDhcpClient = 0;
	strcpy((char *) SysConfig.AthInterface.WifiMacAddress, "");
	strcpy((char *) SysConfig.AthInterface.WifiIpAddress, "");
	strcpy((char *) SysConfig.AthInterface.WifiSubmaskAddress, "");
	strcpy((char *) SysConfig.AthInterface.WifiGatewayAddress, "");
	SysConfig.AthInterface.WifiNetworkConn = 0;
	strcpy((char *) SysConfig.TelecomInterface.TelcomModelName, "");
	strcpy((char *) SysConfig.TelecomInterface.TelcomSoftwareVer, "");
	//strcpy((char *) SysConfig.TelecomInterface.TelcomApn, "Internet");
	strcpy((char *) SysConfig.TelecomInterface.TelcomApn, "");
	SysConfig.TelecomInterface.TelcomRssi = 0;
	strcpy((char *) SysConfig.TelecomInterface.TelcomChapPapId, " ");
	strcpy((char *) SysConfig.TelecomInterface.TelcomChapPapPwd, " ");
	strcpy((char *) SysConfig.TelecomInterface.TelcomModemImei, "");
	strcpy((char *) SysConfig.TelecomInterface.TelcomSimImsi, "");
	strcpy((char *) SysConfig.TelecomInterface.TelcomSimIccid, "");
	SysConfig.TelecomInterface.TelcomSimStatus = 0;
	SysConfig.TelecomInterface.TelcomModemMode = 0;
	strcpy((char *) SysConfig.TelecomInterface.TelcomIpAddress, "");
	SysConfig.TelecomInterface.TelcomNetworkConn = 0;
	strcpy((char *)SysConfig.chargePointVendor, "Phihong Technology");
	//********** Backend **********//
	SysConfig.BackendConnTimeout = 300; //300 seconds
	SysConfig.OfflinePolicy = 2;
	SysConfig.OfflineMaxChargeEnergy = 0;
	SysConfig.OfflineMaxChargeDuration = 0;
	strcpy((char *) SysConfig.OcppServerURL, "");
	strcpy((char *) SysConfig.ChargeBoxId, "");

	//if(SysConfig.ModelName[12] == 'P' && SysConfig.ModelName[13] == 'H')
	//{
	//    strcpy((char *) SysConfig.MaintainServerURL, "wss://ocpp.phihong.com.tw:2013/");
	//}
	//else
	//{
	    strcpy((char *) SysConfig.MaintainServerURL, "");
	//}

	SysConfig.LedInfo.Intensity = 2;

	// clean power cabinet wiring info
	memset((char *)&SysConfig.WiringInfo, 0x00, sizeof(WiringInfoData));

	//copy default configuration to pointer
	memcpy(ptr,&SysConfig,sizeof(struct SysConfigData));

	//calculate CRC
    Chk = 0;
    for(i = ARRAY_SIZE(SysConfig.CsuBootLoadFwRev); i < (MtdBlockSize - 4); i++)
    {
        Chk += *(ptr + i);
    }
    memcpy(ptr + MtdBlockSize - 4, &Chk, 4);

	/*
	* Parameter process
	*/
	if (argc > 1)
	{
		char *arg = argv[1];
		switch (arg[0])
		{
		case '-':
			switch (arg[1])
			{
				case 'a':
					outType |= OUTPUT_FILE;
					outType |= OUTPUT_FLASH;
					break;
				case 'f':
					outType |= OUTPUT_FILE;
					break;
				case 'm':
					outType |= OUTPUT_FLASH;
					break;
				default:
					helpOutput();
					break;
			}
				break;
			default:
				helpOutput();
				break;
		}
	}
	else
	{
		helpOutput();
	}

	/*
	 * Configuration bin file generate
	*/
    fd = open("/mnt/FactoryDefaultConfig.bin", O_RDWR | O_CREAT | O_TRUNC);
    if(fd < 0)
    {
        StoreLogMsg("[FactoryConfig]main: open /mnt/FactoryDefaultConfig.bin NG");
        free(ptr);
        return 0;
    }
    wrd = write(fd, ptr, MtdBlockSize);
    close(fd);
    if(wrd < MtdBlockSize)
    {
        StoreLogMsg("write /mnt/FactoryDefaultConfig.bin NG\r\n");
        free(ptr);
        return 0;
    }
    StoreLogMsg("FactoryConfig write to file in /mnt OK.\r\n");

	/*
	* Flash memory write
	*/
	if((outType & OUTPUT_FLASH) > 0)
	{
        // Save factory default setting value to flash setting block
        StoreLogMsg("Erase /dev/mtd10.\n");
        runShellCmd("flash_erase /dev/mtd10 0 0");
        StoreLogMsg("Write /dev/mtd10.\n");
        runShellCmd("nandwrite -p /dev/mtd10 /mnt/FactoryDefaultConfig.bin");

        // Save factory default setting value to flash backup setting block
        StoreLogMsg("Erase /dev/mtd11.\n");
        runShellCmd("flash_erase /dev/mtd11 0 0");
        StoreLogMsg("Write /dev/mtd11.\n");
        runShellCmd("nandwrite -p /dev/mtd11 /mnt/FactoryDefaultConfig.bin");

        // Save factory default setting value to flash factory default setting block
        StoreLogMsg("Erase /dev/mtd12.\n");
        runShellCmd("flash_erase /dev/mtd12 0 0");
        StoreLogMsg("Write /dev/mtd12.\n");
        runShellCmd("nandwrite -p /dev/mtd12 /mnt/FactoryDefaultConfig.bin");

        system("rm -f /mnt/FactoryDefaultConfig.bin");

        StoreLogMsg("FactoryConfig write to flash OK\r\n");
	}

	free(ptr);

	return FAIL;
}