#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	"define.h"

#define DEBUG_INFO(format, args...) StoreLogMsg("[%s:%d][%s][Info] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
#define DEBUG_WARN(format, args...) StoreLogMsg("[%s:%d][%s][Warn] "format, __FILE__, __LINE__, __FUNCTION__, ##args)
#define DEBUG_ERROR(format, args...) StoreLogMsg("[%s:%d][%s][Error] "format, __FILE__, __LINE__, __FUNCTION__, ##args)

#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;
struct StatusCodeData 			*ShmStatusCodeData;
struct FanModuleData			*ShmFanModuleData;
void trim(char *s);
int mystrcmp(char *p1,char *p2);
void substr(char *dest, const char* src, unsigned int start, unsigned int cnt);
void split(char **arr, char *str, const char *del);



int StoreLogMsg(const char *fmt, ...)
{
	char Buf[4096+256];
	char buffer[4096];
	time_t CurrentTime;
	struct tm *tm;
	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);
	sprintf(Buf,"echo \"[%04d.%02d.%02d %02d:%02d:%02d] - %s\" >> /Storage/SystemLog/%04d-%02d_%s_%s_SystemLog",
			tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,
			buffer,
			tm->tm_year+1900,tm->tm_mon+1,
			SysConfig.ModelName,
			SysConfig.SerialNumber);
#ifdef SystemLogMessage
	system(Buf);
#endif

	printf("[%04d.%02d.%02d %02d:%02d:%02d] - %s", tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec, buffer);

	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
//=================================
void trim(char *s)
{
    int i=0, j, k, l=0;

    while((s[i]==' ')||(s[i]=='\t')||(s[i]=='\n'))
        i++;

    j = strlen(s)-1;
    while((s[j]==' ')||(s[j]=='\t')||(s[j]=='\n'))
        j--;

    if(i==0 && j==strlen(s)-1) { }
    else if(i==0) s[j+1] = '\0';
    else {
        for(k=i; k<=j; k++) s[l++] = s[k];
        s[l] = '\0';
    }
}

int mystrcmp(char *p1,char *p2)
{
    while(*p1==*p2)
    {
        if(*p1=='\0' || *p2=='\0')
            break;
        p1++;
        p2++;
    }
    if(*p1=='\0' && *p2=='\0')
        return(PASS);
    else
        return(FAIL);
}

void substr(char *dest, const char* src, unsigned int start, unsigned int cnt)
{
	strncpy(dest, src + start, cnt);
	dest[cnt] = 0;
}

void split(char **arr, char *str, const char *del)
{
	char *s = strtok(str, del);

	while(s != NULL)
	{
		*arr++ = s;
		s = strtok(NULL, del);
	}
}


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

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

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

    	result = FAIL;
   	 }
    else
    {}

   	 //creat ShmStatusCodeData
   	 if ((MeterSMId = shmget(ShmStatusCodeKey, sizeof(struct StatusCodeData),  0777)) < 0)
    {
   		DEBUG_ERROR("shmget ShmStatusCodeData NG\n");

   		result = FAIL;
	}
    else if ((ShmStatusCodeData = shmat(MeterSMId, NULL, 0)) == (void *) -1)
    {
    	DEBUG_ERROR("shmat ShmStatusCodeData 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");
}

//================================================
// Main process
//================================================
int main(int argc, char *argv[])
{
	unsigned char outType=0;
	unsigned int i,Chk,MtdBlockSize=0x600000;
	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 configuration
	time_t t = time(NULL);
	struct tm tm = *localtime(&t);
	
	// Initial Share Memory
	if(InitShareMemory() == FAIL)
	{
		DEBUG_ERROR("InitShareMemory NG\n");

		strcpy((char*)SysConfig.ModelName,"");
		strcpy((char*)SysConfig.SerialNumber,"");
		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));

		DEBUG_INFO("InitShareMemory OK.\r\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 = 0;	// 0: enable, 1: disable
	SysConfig.DefaultLanguage  = 0;		// 0:English	1:Big5				2: GB			3: JN		4: Français 	5: Italiano		6: Español		7: Deutsch		8: Nederland	9: Norsk	10: Suomalainen		11: Svenska		12: Pусский		13: ไทย
	SysConfig.RfidCardNumEndian = 0;	// 0: Little endian		1: Big endian

	// Charging configuration
	SysConfig.MaxChargingEnergy = 0;	// 0: No limit	Other: 1~65536 KWH
	SysConfig.MaxChargingPower = 0;		// 0: No limit	Other: 1~65536 KW
	SysConfig.MaxChargingCurrent = 0;	// 0: Rating value	Other: 1~Rating A
	SysConfig.MaxChargingDuration = 0;	// 0: No limit	Other: 1~65536 Minute
	SysConfig.PhaseLossPolicy = 0;		// 0: Charging	1: Stop charging
	SysConfig.AcPhaseCount = 1;			// 1: One phase	3: Three phase

	// Network configuration
	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;
	strcpy((char*)SysConfig.Eth1Interface.EthIpAddress, "192.168.0.10");
	strcpy((char*)SysConfig.Eth1Interface.EthSubmaskAddress, "255.255.255.0");
	strcpy((char*)SysConfig.Eth1Interface.EthGatewayAddress, "192.168.0.254");

	SysConfig.AthInterface.WifiMode = 2;		// 0: Disable	1: Infrastructure client	2: Infrastructure server	3: Ad-Hoc
	SysConfig.AthInterface.WifiRssi = 0;		// Wifi rssi value
	SysConfig.AthInterface.WifiDhcpServer = 0;	// 0: Enable	1: Disable
	SysConfig.AthInterface.WifiDhcpClient = 0;	// 0: Enable	1: Disable

	strcpy((char*)SysConfig.TelecomInterface.TelcomApn, "");
	SysConfig.TelecomInterface.TelcomSimStatus = 0;	// SIM card status
	SysConfig.TelecomInterface.TelcomModemMode = 0;	//0: No services	1: CDMA		2: GSM/GPRS	3: WCDMA	4: GSM/WCDMA	5: TD_SCDMA		6: Unknown

	// Backend configuration
	SysConfig.BackendConnTimeout=300; 		// 300 seconds
	SysConfig.OfflinePolicy = 2;			// 0: local list, 1: Phihong RFID tag, 2: free charging, 3: no charging
	SysConfig.OfflineMaxChargeEnergy = 0;	// 0: Same as MaxChargeEnergy	Other: 1~65535KWH
	SysConfig.OfflineMaxChargeDuration = 0; // 0: Same as MaxChargeDuration Other: 1~65535 minutes
	strcpy((char*)SysConfig.OcppServerURL, "");
	sprintf((char*)SysConfig.ChargeBoxId, "%s%s", SysConfig.ModelName, SysConfig.SerialNumber);


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

	// Calculate CRC
	Chk=0;
	for(i=0;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
	 */
	if((outType&OUTPUT_FILE)>0)
	{
		// Save factory default setting value to file
		fd = open("/mnt/FactoryDefaultConfig.bin", O_RDWR|O_CREAT);
		if (fd < 0)
		{

			DEBUG_ERROR("open /mnt/FactoryDefaultConfig.bin NG\r\n");

			free(ptr);
			return 0;
		}
		wrd=write(fd, ptr, MtdBlockSize);
		close(fd);
		if(wrd<MtdBlockSize)
		{
			DEBUG_ERROR("write /mnt/FactoryDefaultConfig.bin NG\r\n");

			free(ptr);
			return 0;
		}

		DEBUG_INFO("FactoryConfig write to file in /mnt OK.\r\n");
	}

	/*
	 * Flash memory write
	 */
	if((outType&OUTPUT_FLASH)>0)
	{
		// Save factory default setting value to flash factory default setting block
		fd = open("/dev/mtdblock12", O_RDWR);
		if (fd < 0)
		{

			DEBUG_ERROR("open /dev/mtdblock12 NG\r\n");

			free(ptr);
			return 0;
		}
		wrd=write(fd, ptr, MtdBlockSize);
		close(fd);
		if(wrd<MtdBlockSize)
		{
			DEBUG_ERROR("write /dev/mtdblock12 NG\r\n");

			free(ptr);
			return 0;
		}

		// Save factory default setting value to flash backup setting block
		fd = open("/dev/mtdblock11", O_RDWR);
		if (fd < 0)
		{
			DEBUG_ERROR("open /dev/mtdblock11 NG\r\n");

			free(ptr);
			return 0;
		}
		wrd=write(fd, ptr, MtdBlockSize);
		close(fd);
		if(wrd<MtdBlockSize)
		{
			DEBUG_ERROR("write /dev/mtdblock11 NG\r\n");

			free(ptr);
			return 0;
		}

		// Save factory default setting value to flash setting block
		fd = open("/dev/mtdblock10", O_RDWR);
		if (fd < 0)
		{
			DEBUG_ERROR("open /dev/mtdblock10 NG\r\n");

			free(ptr);
			return 0;
		}
		wrd=write(fd, ptr, MtdBlockSize);
		close(fd);
		if(wrd<MtdBlockSize)
		{
			DEBUG_ERROR("write /dev/mtdblock10 NG\r\n");

			free(ptr);
			return 0;
		}

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

	free(ptr);

	return FAIL;
}