#ifndef __OTA_20190702__
#define __OTA_20190702__

#include "SerialPort.h"
#include "CurlClient.h"
#include "../cJson/cJSON.h"

#define BUFFER_LEN 10240
#pragma once

typedef struct __SIACP__
{
	std::string name; // 命令描述;
	std::string head; // 命令头;
	std::string code; // 命令码;
	std::string mark; // 特殊标记;
	bool bMulticode = false;	// 命令码是否多参数;
	int cmd_wait_time = 100;	// 两条串口指令间隔时间;
	int read_wait_time = 100;	// 写完串口后，等待多久读;
} _SIACP_;


// 包头码（包引导码）
enum PHeader {
	TV_Debug = 0xAA,
	TV_Return = 0xAB,
	TV_Panel_Debug = 0xAC,
	TV_Panel_Return = 0xAD,
	TV_Debug_Other = 0xAE,
	TV_Other_Return = 0xAF,
};

// 命令结果码;
enum RCode {
	RC_OK = 0x0A,      // 命令执行通过;
	RC_ERR = 0x0E,     // 命令错误或无法执行;
	RC_LOSE = 0x0F,    // 命令丢失（链路层出错）;
};

//////////////////////////////////////////////////////////////////////////
enum LOG_ENUM
{
	NORMAL_LOG = 0,
	ERROR_LOG,
	OK_LOG,
	INFO_LOG
};

extern std::string HexString2Bytes(std::string strHex, const int& len /* = 3 */);
extern std::string Bytes2HexString(const unsigned char* pbuffer, int nLen);
extern std::string Bytes2HexString(const unsigned char* pbuffer, int nLen, char chSpace);

class CSIACP
{
public:
	CSIACP(void);
	~CSIACP(void);

	void SetMainDlg(CDialogEx* p);
	void ShowMessage(LPCTSTR lpMsg, LOG_ENUM logtype = NORMAL_LOG);
protected:
	CSerialPort* m_pSerial;
	CDialogEx* m_pMainDlg;
	typedef struct __RTN__
	{
		int len = 0;		// 返回的数据长度;
		std::string data;	// 返回的数据内容;		
	}RTN, * pRTN;

	std::vector<RTN> m_vtdata;
	std::vector<_SIACP_> m_vtcommand;
	BOOL ExecSerialCommand(const _SIACP_& siacp, std::string command);
	BOOL ParserSerialData(std::vector<RTN>& vtdata, const _SIACP_& siacp, byte* pbuffer, DWORD dwlen);

	const _SIACP_* GetSiacp(std::string name);
	std::string GetSiacpCommand(const _SIACP_& siacp, std::string others, int othersLen);
	std::string GetSiacpCommand(std::string name, std::string others, int othersLen);

public:
	void LoadCommand();
	void SaveCommand(std::vector<_SIACP_> &vtSiacp, std::string path);
	BOOL OpenComm(LPCTSTR lpszCom, DWORD dwBaudrate);
	void CloseComm();
	BOOL IsOpen() {
		return m_pSerial && m_pSerial->IsOpen();
	}
	BOOL SendCommand(std::string cmd_name, const byte* pszOthers = NULL, DWORD dwOthersLen = 0);
	BOOL SendCommand2(std::string cmd_name, std::string data = "", size_t nlen = 0);
public:
	// 等待tv启动成功;
	BOOL SCBC_WaitTVBoot();
	BOOL SCBC_MTKInit();
	// 进入工厂模式;
	BOOL SCBC_EnterFactory();
	// 离开工厂模式;
	BOOL SCBC_LeaveFactory();
	// 初始化Wb;
	BOOL SCBC_WBInit();
	// 获取pid;
	BOOL SCBC_GetProjectId(int& pid);
	// 软件版本号;
	BOOL SCBC_GetSoftVersion(std::string& strVer);
	// 设备ID
	BOOL SCBC_GetDeviceId(std::string& strDid);
	// ClientType;
	BOOL SCBC_GetClientType(std::string& strClt);
	// MAC地址;
	BOOL SCBC_GetMAC(std::string& strMac);
	// HDCP Key;
	BOOL SCBC_GetHDCPKey(std::string& strHDCP);
	// HDCP Key2.2;
	BOOL SCBC_GetHDCPKey22(std::string& strHDCP22);
	// Widi;
	BOOL SCBC_GetWidi(std::string& strWidi);
	// Netflix ESN;
	BOOL SCBC_GetNetflixESN(std::string& strESN);
	// Widevine;
	BOOL SCBC_GetWidevine(std::string& strWidevine);
	// ci plus key;
	BOOL SCBC_GetCiKey(std::string& strCikey);
	// OSD Language;
	BOOL SCBC_GetOSDLanguage(std::string& strOSDLan);
	// Shop Language;
	BOOL SCBC_GetShopLanguage(std::string& strShopLan);
	BOOL SCBC_GetChannel(std::string& channel);

	BOOL SCBC_SetProjectId(const int& pid);
	BOOL SCBC_SetProjectId(std::string pid);
	BOOL SCBC_SetProjectId(const byte* pBuffer, const int& nLen);
	BOOL SCBC_SetDeviceId(std::string strDeviceId);
	BOOL SCBC_SetDeviceId(const byte* pBuffer, const int &nLen);
	BOOL SCBC_SetMAC(std::string strMac);
	BOOL SCBC_SetMAC(const byte* pBuffer, const int& nLen);
	BOOL SCBC_SetHDCPKey(std::string strHDCP, BOOL bHasSpace = FALSE);
	BOOL SCBC_SetHDCPKey(const byte* pBuffer, const int& nLen);
	BOOL SCBC_SetHDCPKey22(std::string strHDCP22, BOOL bHasSpace = FALSE);
	BOOL SCBC_SetHDCPKey22(const byte* pBuffer, const int& nLen);
	BOOL SCBC_SetNetflixESN(std::string strESN, BOOL bHasSpace = FALSE);
	BOOL SCBC_SetNetflixESN(const byte* pBuffer, const int& nLen);
	BOOL SCBC_SetWidi(std::string strWidi, BOOL bHasSpace = FALSE);
	BOOL SCBC_SetWidi(const byte* pBuffer, const int& nLen);
	BOOL SCBC_SetWidevine(std::string strWidevine, BOOL bHasSpace = FALSE);
	BOOL SCBC_SetWidevine(const byte* pBuffer, const int& nLen);
	BOOL SCBC_SetCiKey(std::string strCiKey, BOOL bHasSpace = FALSE);
	BOOL SCBC_SetCiKey(const byte* pBuffer, const int& nLen);
	BOOL SCBC_SetOSDLanguage(std::string lan, BOOL bHasSpace = TRUE);
	BOOL SCBC_SetOSDLanguage(const byte* pBuffer, const int& nLen);
	BOOL SCBC_SetShopLanguage(std::string lan, BOOL bHasSpace = TRUE);
	BOOL SCBC_SetShopLanguage(const byte* pBuffer, const int& nLen);
	BOOL SCBC_SetChannel(std::string channel, BOOL bHasSpace = TRUE);
	BOOL SCBC_SetChannel(const byte* pBuffer, const int& nLen);
	BOOL SCBC_SetWBNormal(std::string data);
	BOOL SCBC_SetWBNormal(const byte* pBuffer, const int& nLen);
	BOOL SCBC_SetWBCool(std::string data);
	BOOL SCBC_SetWBCool(const byte* pBuffer, const int& nLen);
	BOOL SCBC_SetWBWarm(std::string data);
	BOOL SCBC_SetWBWarm(const byte* pBuffer, const int& nLen);

	BOOL SCBC_CheckDeviceId();
	BOOL SCBC_CheckMAC();
	BOOL SCBC_CheckHDCP();
	BOOL SCBC_CheckHDCP22();
	BOOL SCBC_CheckNetflixESN();
	BOOL SCBC_CheckWidi();
	BOOL SCBC_CheckWidevine();
	BOOL SCBC_CheckCikey();

	BOOL SCBC_StarWarmUpMode();
	BOOL SCBC_StopWarmUpMode();
};

// 数据类型;
enum DATATYPE
{
	DATA_JSON = 0,		// json数据;
	DATA_FORM = 1		// 表单类型;
};

typedef struct __MIDKEY__ {
	std::string name;
	std::string type;
}MidKeyInfo;

typedef struct __MID__ {
	std::string message;
	std::string code;
	std::string factoryname;
	std::string factoryip;
	std::string factoryNum;
	std::string version;
	std::string projectid;
	std::string clienttype;
	std::string host;
	std::map<std::string, std::string> obj;
}MIDInfo;


typedef struct TREPORTDATA {
	std::string report_type;
	std::map<std::string, std::string> report_data;
}TReportData, * pTReportData;

class COTA
{
	CCurlClient m_curl;
public:
	COTA();
	~COTA();

	void SetMainDlg(CDialogEx* p);
	void ShowMessage(LPCTSTR lpMsg, LOG_ENUM logtype = NORMAL_LOG);
private:
	CDialogEx* m_pMainDlg;
	BOOL HttpGet(std::string host, std::string context, std::string& result, DATATYPE dt = DATA_FORM);
	BOOL HttpPost(std::string host, std::string context, std::string& result, DATATYPE dt = DATA_FORM);

public:
	MIDInfo m_midInfo;
	BOOL GetMIDInfo(MIDInfo& mid, std::string bid, std::string strMacs, std::string iptvid = "", std::string version = "");
	BOOL GetKeyInfo(std::string host, std::string context, std::string keyname, std::string valuename, std::string& value);
	std::string GetMidKey(const MIDInfo& mid, std::string name)
	{
		std::string key;
		std::map<std::string, std::string>::const_iterator it = mid.obj.find(name);
		if (it != mid.obj.end())
			key = it->second;

		if (_tcsicmp(name.c_str(), "DeviceID") == 0)
		{
			if ( _tcsicmp(it->first.c_str(), _T("SCBC")) == 0 || _tcsicmp(it->first.c_str(), _T("新用户系统")) == 0)
				key = "tcl_unknown_model";
		}

		return key;
	}
	void UpgradeCheck(std::string factoryNum);
	void ReportUpgrade(BOOL bUpgrade, std::string ver, std::string num);
	BOOL DownloadFile(std::string url, std::string savePath);
	BOOL ReportLog(TReportData &repdata);
	BOOL GetVCode(std::string mac, std::string &vcode);
};

class AutoTiming
{
public:
	AutoTiming(std::string des) {
		_start = clock();
		_des = des;
	}

	~AutoTiming(){
		_end = clock();
		LOG4C((LOG_NOTICE, "%s，请求耗时：%ld ms", _des.c_str(), _end - _start));
	}

private:
	clock_t _start;
	clock_t _end;
	std::string _des;
};

#ifndef AUTOTIMING
#define AUTOTIMING AutoTiming at(__FUNCTION__)
#endif

extern std::string HexString2Bytes(std::string strHex, const int& len = 3);
#endif