﻿#include "jidu.h"
#include "tracer.h"
#include "algorithm.h"
#include "MyStringUtils.h"

#include "ECUFlasherEventHandler.hpp"
#include "ParallelECUFlasher.hpp"
#include "taskpool/TaskPool.hpp"
#include "ECUFlashermanager.hpp"
#include "jidu_dataCenter.h"
#include "jidu_vehicleConfig.h"
#include "jidu_envConfig.h"
#include "otxproxy.h"
#include "jidu_client.h"
#include <thread>

typedef enum {
	Ecu_FotaStatus_Expect = 0,  //待刷写
	Ecu_FotaStatus_Executing = 1, //刷写中
	Ecu_FotaStatus_Fail = 2,    //刷写失败
	Ecu_FotaStatus_Success = 3,  //刷写成功
	Ecu_FotaStatus_ResetStart = 4,  //复位开始
	Ecu_FotaStatus_ResetEnd = 5  //复位结束
}EcuFotaStatus_t;

typedef enum {
	Ecu_FotaPackageType_Data = 0,
	Ecu_FotaPackageType_SBL = 1,
	Ecu_FotaPackageType_App = 2,
	Ecu_FotaPackageType_PBL = 3,
	cu_FotaPackageType_ESS = 4,
	cu_FotaPackageType_EXE = 5
}EcuFotaPackageType_t;

struct EcuFlasherTask {
	uint64_t remainder = 0;
	int progress = 0;
	int priority = 0;
	int status = Ecu_FotaStatus_Expect;
	uint64_t startTimeStamp = 0;
	uint64_t endTimeStamp = 0;
	uint64_t InstallTimeStamp = 0;
	string ecuName;
	uint16_t ecuId;
	string evName;
	string logicalLink;
};
map <uint16_t, EcuFlasherTask> mapEcuFlasherTask;

static int mEcurityAccessMode = 0;//刷写安全访问模式 0:普通刷写，优先使用pinCode; 1:换件刷写，优先刷写 FFFFFFFF
std::mutex mLock;
static otx::flash::ECUFlasherManager* manager = NULL;

class DefaultEventHandler : virtual public otx::flash::ECUFlasherEventHandler {
public:
	DefaultEventHandler() = default;
	DefaultEventHandler(const DefaultEventHandler& right) = default;
	DefaultEventHandler& operator=(const DefaultEventHandler& right) = default;

public:
	virtual ~DefaultEventHandler() = default;

private:
	std::mutex mItemLock;

public:
	virtual void onECUDownloadStart(otx::flash::ECUFlasherECUEventArg& arg) override {
		std::lock_guard<std::mutex> lock(mItemLock);
		uint16_t ecuId = MyStringUtils::toLong(arg.getEcu()->getId());
		if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
			mapEcuFlasherTask[ecuId].status = Ecu_FotaStatus_Executing;
			mapEcuFlasherTask[ecuId].startTimeStamp = get_currentTimeStamp() / 1000;
		}
	}
	virtual void onECUDownloadEnd(otx::flash::ECUFlasherECUEventArg& arg) override {
		std::lock_guard<std::mutex> lock(mItemLock);
		uint16_t ecuId = MyStringUtils::toLong(arg.getEcu()->getId());
		if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
			mapEcuFlasherTask[ecuId].endTimeStamp = get_currentTimeStamp() / 1000;
			char tempBuffer[32] = { 0 };

			if (arg.getStatus() == false) {
				mapEcuFlasherTask[ecuId].status = Ecu_FotaStatus_Fail;
				Tracer::error("ecuDownloadEnd fail: ", _itoa(ecuId, tempBuffer, 16));
			}
			else {
				mapEcuFlasherTask[ecuId].status = Ecu_FotaStatus_Success;

				Tracer::debug("ecuDownloadEnd ok: ", _itoa(ecuId, tempBuffer, 16));
			}
		}
	}

	virtual void onECUResetStart(otx::flash::ECUFlasherECUEventArg& arg) override {
		std::lock_guard<std::mutex> lock(mItemLock);
		uint16_t ecuId = MyStringUtils::toLong(arg.getEcu()->getId());
		if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
			mapEcuFlasherTask[ecuId].status = Ecu_FotaStatus_ResetStart;
		}
	}
	virtual void onECUResetEnd(otx::flash::ECUFlasherECUEventArg& arg) override {
		std::lock_guard<std::mutex> lock(mItemLock);
		uint16_t ecuId = MyStringUtils::toLong(arg.getEcu()->getId());
		if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
			mapEcuFlasherTask[ecuId].status = Ecu_FotaStatus_ResetEnd;
		}
	}
	virtual void onFileDownloadStart(otx::flash::ECUFlasherFileEventArg& arg) override {
		std::lock_guard<std::mutex> lock(mItemLock);
		uint16_t ecuId = MyStringUtils::toLong(arg.getEcu()->getId());
		if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
			mapEcuFlasherTask[ecuId].status = Ecu_FotaStatus_Executing;
		}

		string filepath = arg.getFile()->getPath();
		char tempBuffer[32] = { 0 };
		Tracer::debug(string("fileDownloadStart: ") + _itoa(ecuId, tempBuffer, 16), filepath);
	}
	virtual void onFileDownloadEnd(otx::flash::ECUFlasherFileDownloadEndEventArg& arg) override {
		std::lock_guard<std::mutex> lock(mItemLock);
		uint16_t ecuId = MyStringUtils::toLong(arg.getEcu()->getId());
		string filepath = arg.getFile()->getPath();
		char tempBuffer[32] = { 0 };
		Tracer::debug(string("fileDownloadEnd: ") + _itoa(ecuId, tempBuffer, 16), filepath);
	}
	virtual void onFileDownloadProgress(otx::flash::ECUFlasherFileDownloadProgressEventArg& arg) override {
		std::lock_guard<std::mutex> lock(mItemLock);
		uint16_t ecuId = MyStringUtils::toLong(arg.getEcu()->getId());
		if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
			mapEcuFlasherTask[ecuId].progress = arg.getProgress();
			otx::flash::ECUFlasher* sender = arg.getSender();
			if (sender)
			{
				//TODO 剩余刷写时间(秒级)

				mapEcuFlasherTask[ecuId].remainder = sender->getRemainTime(arg.getEcu()) / 1000000;
				if (sender->getRemainTime(arg.getEcu()) > static_cast<unsigned long long>(1000000 * 60) * 60) {

					char tempBuffer[32] = { 0 };
					Tracer::error(string("remainder: ") + _itoa(ecuId, tempBuffer, 16), to_string(mapEcuFlasherTask[ecuId].remainder));
				}
			}

			if (arg.getProgress() == 100) {
				mapEcuFlasherTask[ecuId].InstallTimeStamp = get_currentTimeStamp() / 1000;
			}
		}
	}
};
static DefaultEventHandler eventHandler;



bool jd_ecuflash_hwpnCheck(const char* ecuName)
{
	string pkgName = CVehicleConfig::getInstance()->getEcuName_byOrderEcuName(ecuName);

	JD_ECU_CONFIG_t ecuConfig;
	if (!CVehicleConfig::getInstance()->getEcuConfig(pkgName, ecuConfig)) {
		Tracer::error("ecuflash: invalid ecuName in pkg", pkgName);
		return false;
	}
	else if (0 == ecuConfig.vecPreconditionList.size()) {
		return true;
	}

	for (int i = 0; i < ecuConfig.vecPreconditionList.size(); i++) {
		JD_FLASH_PRECONDITION_t onePrecondition = ecuConfig.vecPreconditionList.at(i);

		string otherEcuName = onePrecondition.strEcuName;
		uint16_t otherEcuId = onePrecondition.nEcuId;
		string ecuHwpn;
		//TODO 获取车辆的Ecu硬件版本
		if (DataCenter::m_vehicleInfo.mapEcuInfo.find(otherEcuId) != DataCenter::m_vehicleInfo.mapEcuInfo.end()) {
			ecuHwpn = DataCenter::m_vehicleInfo.mapEcuInfo.at(otherEcuId).ecuHwpn;
		}
		else {
			char orderEcuHwpn[32] = { 0 };
			if (get_jd_orderInfo_ecuHwpn_byEcuName(onePrecondition.strEcuName.c_str(), orderEcuHwpn, 32) < 0) {
				continue;
			}
			else {
				ecuHwpn = orderEcuHwpn;
			}
		}

		for (int j = 0; j < ecuConfig.vecPreconditionList.size(); j++) {
			std::string oneHwpn = onePrecondition.vecHwPn.at(j);

			if (oneHwpn.find(ecuHwpn) != string::npos) {
				return true;
			}
		}
	}

	return false;
}


bool jd_ecuflash_hwpnCheck_byEcuId(uint16_t ecuId)
{

	char tempBuffer[32] = { 0 };
	string strEcuId = _itoa(ecuId, tempBuffer, 16);

	JD_ECU_CONFIG_t ecuConfig;
	if (!CVehicleConfig::getInstance()->getEcuConfig(ecuId, ecuConfig)) {
		Tracer::error("ecuflash: invalid ecuId in pkg", strEcuId);
		return false;
	}
	else if (0 == ecuConfig.vecPreconditionList.size()) {
		return true;
	}

	for (int i = 0; i < ecuConfig.vecPreconditionList.size(); i++) {
		JD_FLASH_PRECONDITION_t onePrecondition = ecuConfig.vecPreconditionList.at(i);

		string otherEcuName = onePrecondition.strEcuName;
		uint16_t otherEcuId = onePrecondition.nEcuId;
		string ecuHwpn;
		//TODO 获取车辆的Ecu硬件版本
		if (DataCenter::m_vehicleInfo.mapEcuInfo.find(otherEcuId) != DataCenter::m_vehicleInfo.mapEcuInfo.end()) {
			ecuHwpn = DataCenter::m_vehicleInfo.mapEcuInfo.at(otherEcuId).ecuHwpn;
		}
		else {
			char orderEcuHwpn[32] = { 0 };
			if (get_jd_orderInfo_ecuHwpn_byEcuName(onePrecondition.strEcuName.c_str(), orderEcuHwpn, 32) < 0) {
				continue;
			}
			else {
				ecuHwpn = orderEcuHwpn;
			}
		}

		for (int j = 0; j < ecuConfig.vecPreconditionList.size(); j++) {
			std::string oneHwpn = onePrecondition.vecHwPn.at(j);

			if (oneHwpn.find(ecuHwpn) != string::npos) {
				return false;
			}
		}
	}

	return true;
}

bool jd_ecuflash_orderCheck(const char* ecuName)
{
	//TODO 查找订单中的ecuInfo;
	for (JD_ECU_INFO_t orderInfo : DataCenter::m_VehicleOrderInfo.vecListEcuNew) {
		if (orderInfo.strEcuName._Equal(ecuName)) {

			char ecuHwpn[32] = { 0 };
			get_jd_vehicleInfo_ecuHwpn_byEcuName(ecuName, ecuHwpn, 32);
			if (!orderInfo.strEcuHwpn._Equal(ecuHwpn)) {
				Tracer::error(string("hwpn mismatch: ") + ecuName, ecuHwpn + string("|") + orderInfo.strEcuHwpn);
				return false;
			}

			string pkgName = CVehicleConfig::getInstance()->getEcuName_byOrderEcuName(ecuName);
			vector<JD_VSP_FLASH_CONFIG_t> vecFlashInfo;
			if (CVehicleConfig::getInstance()->getEcuFileInfo(pkgName, ecuHwpn, vecFlashInfo)) {

				//if (vecFlashInfo.size() != orderInfo.vecEcuSwpnList.size()) {
				//	return false;
				//}

				for (int i = 0; i < vecFlashInfo.size(); i++) {
					JD_VSP_FLASH_CONFIG_t oneFlahsInfo = vecFlashInfo.at(i);
					MyStringUtils::toUpper(oneFlahsInfo.strFileType);
					for (JD_ECU_SWPN_INFO_t swpnInfo : orderInfo.vecEcuSwpnList) {
						if (swpnInfo.strPackageType._Equal(oneFlahsInfo.strFileType) && !swpnInfo.strEcuSwpn._Equal(oneFlahsInfo.strVersion)) {
							Tracer::error(string("swpn mismatch: ") + ecuName, swpnInfo.strEcuSwpn + string("|") + oneFlahsInfo.strVersion);
							return false;
						}
					}
				}
			}

			break;
		}
	}

	return true;
}

bool jd_ecuflash_orderCheck_byEcuId(uint16_t ecuId)
{
	//TODO 查找订单中的ecuInfo;
	for (JD_ECU_INFO_t orderInfo : DataCenter::m_VehicleOrderInfo.vecListEcuNew) {
		if (orderInfo.nEcuId == ecuId) {

			char strEcuId[32] = { 0 };
			itoa(ecuId, strEcuId, 16);

			char ecuHwpn[32] = { 0 };
			get_jd_vehicleInfo_ecuHwpn_byEcuId(ecuId, ecuHwpn, 32);
			if (!orderInfo.strEcuHwpn._Equal(ecuHwpn)) {
				Tracer::error(string("hwpn mismatch: 0x") + strEcuId, ecuHwpn + string("|") + orderInfo.strEcuHwpn);
				return false;
			}

			vector<JD_VSP_FLASH_CONFIG_t> vecFlashInfo;
			if (CVehicleConfig::getInstance()->getEcuFileInfo(ecuId, ecuHwpn, vecFlashInfo)) {

				//if (vecFlashInfo.size() != orderInfo.vecEcuSwpnList.size()) {
				//	return false;
				//}

				for (int i = 0; i < vecFlashInfo.size(); i++) {
					JD_VSP_FLASH_CONFIG_t oneFlahsInfo = vecFlashInfo.at(i);
					MyStringUtils::toUpper(oneFlahsInfo.strFileType);
					for (JD_ECU_SWPN_INFO_t swpnInfo : orderInfo.vecEcuSwpnList) {
						if (swpnInfo.strPackageType._Equal(oneFlahsInfo.strFileType) && !swpnInfo.strEcuSwpn._Equal(oneFlahsInfo.strVersion)) {
							Tracer::error(string("swpn mismatch: 0x") + strEcuId, swpnInfo.strEcuSwpn + string("|") + oneFlahsInfo.strVersion);
							return false;
						}
					}
				}
			}

			break;
		}
	}

	return true;
}


bool jd_ecuflash_addEcu(const char* ecuName, const char* evName, const char* logicalLinkName, int priority)
{
	std::lock_guard<std::mutex> lock(mLock);
	string newName = CVehicleConfig::getInstance()->getEcuName_byOrderEcuName(ecuName);

	vector<JD_ECU_CONFIG_t> vecEcuConfig = CVehicleConfig::getInstance()->m_vehicleConfig.vecListEcu;
	for (int i = 0; i < vecEcuConfig.size(); i++) {
		if (vecEcuConfig.at(i).strEcuName._Equal(newName)) {
			uint16_t ecuId = vecEcuConfig.at(i).nEcuId;
			EcuFlasherTask tempTask;
			tempTask.priority = priority;
			tempTask.logicalLink = logicalLinkName;
			tempTask.evName = evName;
			tempTask.ecuId = ecuId;
			tempTask.ecuName = ecuName;
			mapEcuFlasherTask[ecuId] = tempTask;
			return true;
		}
	}

	Tracer::error("invalid ecu add falsh", ecuName);
	return false;
}

int jd_ecuflash_getProgress(const char* ecuName)
{
	std::lock_guard<std::mutex> lock(mLock);
	uint16_t ecuId = get_jd_orderInfo_ecuId_byEcuName(ecuName);

	if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
		return mapEcuFlasherTask[ecuId].progress;
	}

	return -1;
}

int jd_ecuflash_getStatus(const char* ecuName)
{
	std::lock_guard<std::mutex> lock(mLock);
	uint16_t ecuId = get_jd_orderInfo_ecuId_byEcuName(ecuName);

	if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {

		return mapEcuFlasherTask[ecuId].status;
	}

	return Ecu_FotaStatus_Fail;
}

int jd_ecuflash_ecuCount(int status)
{
	int result = 0;
	for (auto it = mapEcuFlasherTask.begin(); it != mapEcuFlasherTask.end(); it++)
	{
		if (status == it->second.status) {

			result++;
		}
	}

	return result;
}

uint64_t jd_ecuflash_getRemainder(const char* ecuName)
{
	std::lock_guard<std::mutex> lock(mLock);
	uint16_t ecuId = get_jd_orderInfo_ecuId_byEcuName(ecuName);

	if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {

		return mapEcuFlasherTask[ecuId].remainder;
	}

	return -1;
}

uint64_t jd_ecuflash_getInstallRemainder(const char* ecuName, int expectedTime)
{
	std::lock_guard<std::mutex> lock(mLock);
	uint16_t ecuId = get_jd_orderInfo_ecuId_byEcuName(ecuName);

	if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
		int timeNow = get_currentTimeStamp() / 1000;
		int realTime = timeNow - mapEcuFlasherTask[ecuId].InstallTimeStamp;//TODO 当前安装已用时
		if (realTime >= expectedTime) {
			return 1;
		}
		else {
			return expectedTime - realTime;
		}
	}

	return -1;
}

uint64_t jd_ecuflash_getStartTimestamp(const char* ecuName)
{
	uint16_t ecuId = get_jd_orderInfo_ecuId_byEcuName(ecuName);
	return jd_ecuflash_getStartTimestamp_byEcuId(ecuId);
}

uint64_t jd_ecuflash_getEndTimestamp(const char* ecuName)
{
	uint16_t ecuId = get_jd_orderInfo_ecuId_byEcuName(ecuName);
	return jd_ecuflash_getEndTimestamp_byEcuId(ecuId);
}

bool jd_ecuflash_addEcu_byEcuId(uint16_t ecuId, const char* evName, const char* logicalLinkName, int priority)
{
	std::lock_guard<std::mutex> lock(mLock);
	vector<JD_ECU_CONFIG_t> vecEcuConfig = CVehicleConfig::getInstance()->m_vehicleConfig.vecListEcu;
	for (int i = 0; i < vecEcuConfig.size(); i++) {
		//if (vecEcuConfig.at(i).nEcuId == ecuId) {
		if ((ecuId & 0xFFF0) == (vecEcuConfig.at(i).nEcuId & 0xFFF0)) {
			string ecuName = vecEcuConfig.at(i).strEcuName;
			EcuFlasherTask tempTask;
			tempTask.priority = priority;
			tempTask.logicalLink = logicalLinkName;
			tempTask.evName = evName;
			tempTask.ecuName = ecuName;
			tempTask.ecuId = ecuId;
			mapEcuFlasherTask[ecuId] = tempTask;
			return true;
		}
	}

	Tracer::error("invalid ecu add falsh", to_string(ecuId));
	return false;
}

int jd_ecuflash_getProgress_byEcuId(uint16_t ecuId)
{
	std::lock_guard<std::mutex> lock(mLock);
	if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
		EcuFlasherTask tempTask = mapEcuFlasherTask.at(ecuId);
		return tempTask.progress;
	}

	return -1;
}

int jd_ecuflash_getStatus_byEcuId(uint16_t ecuId)
{
	std::lock_guard<std::mutex> lock(mLock);
	if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
		EcuFlasherTask tempTask = mapEcuFlasherTask.at(ecuId);
		return tempTask.status;
	}

	return Ecu_FotaStatus_Fail;
}

uint64_t jd_ecuflash_getRemainder_byEcuId(uint16_t ecuId)
{
	std::lock_guard<std::mutex> lock(mLock);

	if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
		EcuFlasherTask tempTask = mapEcuFlasherTask.at(ecuId);
		return tempTask.remainder;
	}

	return -1;
}

uint64_t jd_ecuflash_getInstallRemainder_byEcuId(uint16_t ecuId, int expectedTime)
{
	std::lock_guard<std::mutex> lock(mLock);

	if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
		EcuFlasherTask tempTask = mapEcuFlasherTask.at(ecuId);

		int timeNow = get_currentTimeStamp() / 1000;
		int realTime = timeNow - mapEcuFlasherTask.at(ecuId).InstallTimeStamp;//TODO 当前安装已用时
		if (realTime >= expectedTime) {
			return 1;
		}
		else {
			return expectedTime - realTime;
		}
	}

	return -1;
}

uint64_t jd_ecuflash_getStartTimestamp_byEcuId(uint16_t ecuId)
{
	std::lock_guard<std::mutex> lock(mLock);

	if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
		EcuFlasherTask tempTask = mapEcuFlasherTask.at(ecuId);
		return tempTask.startTimeStamp;
	}

	return -1;
}

uint64_t jd_ecuflash_getEndTimestamp_byEcuId(uint16_t ecuId)
{
	std::lock_guard<std::mutex> lock(mLock);

	if (mapEcuFlasherTask.find(ecuId) != mapEcuFlasherTask.end()) {
		EcuFlasherTask tempTask = mapEcuFlasherTask.at(ecuId);
		return tempTask.endTimeStamp;
	}

	return -1;
}

bool jd_ecuflash_setSecurityAccessMode(int mode)
{
	mEcurityAccessMode = mode;
	return bool();
}

void errHandler(uint16_t ecuId, string errMsg) {
	mapEcuFlasherTask[ecuId].status = Ecu_FotaStatus_Fail;
}

void pthread_download() {

	static bool isRunning = false;

	if (isRunning) {
		Tracer::error("downloading", "前次刷写任务未结束");
		return;
	}
	else {
		isRunning = true;
	}

	manager->addEventHandler(&eventHandler);

	string projectPath = "jidu";
	manager->getProjectPath(projectPath);
	Tracer::warn("storePath", projectPath);

	for (auto it = mapEcuFlasherTask.begin(); it != mapEcuFlasherTask.end(); it++) {
		uint16_t ecuId = it->first;
		EcuFlasherTask tempTask = it->second;
		string ecuName = tempTask.ecuName;

		string pkiName = ecuName;
		for (auto itEcu = DataCenter::m_vehicleInfo.mapEcuInfo.begin(); itEcu != DataCenter::m_vehicleInfo.mapEcuInfo.end(); itEcu++) {
			uint16_t tempEcuId = itEcu->first;
			if ((tempEcuId & 0xFFF0) == (ecuId & 0xFFF0)) {
				pkiName = itEcu->second.pkiName;
				if (pkiName.empty()) {
					pkiName = ecuName;
				}
				break;
			}
		}

		JD_ECU_SAFETY_CONSTANT_t safetyConstant;
		if (pkiName._Equal("BGM") || pkiName._Equal("CDC") || pkiName._Equal("ACU")) {
			pkiName += "_SOC";
		}
		if (true != DataCenter::getInstance()->getEcuSafetyConstant(pkiName, safetyConstant)) {
			Tracer::error(pkiName, "invalid EcuSafetyConstant");
			mapEcuFlasherTask[ecuId].status = Ecu_FotaStatus_Fail;
			continue;
		}
		string pinCode = safetyConstant.keySwdl;

		if (tempTask.status != Ecu_FotaStatus_Expect) {
			continue;
		}

		//TODO 域控不是VBF格式 "TCAM", "BGM", "CDC", "ACU"
		if (ecuName._Equal("TCAM") || ecuName._Equal("BGM") || ecuName._Equal("CDC") || ecuName._Equal("ACU")) {
			EcuFlasherTask tempTask = it->second;

			char ecuHwpn[32] = { 0 };
			get_jd_vehicleInfo_ecuHwpn_byEcuId(ecuId, ecuHwpn, 32);

			string pkgName = CVehicleConfig::getInstance()->getEcuName_byOrderEcuName(ecuName);
			vector<JD_VSP_FLASH_CONFIG_t> vecFlashInfo;
			if (CVehicleConfig::getInstance()->getEcuFileInfo(ecuId, ecuHwpn, vecFlashInfo)) {
				manager->addECU(tempTask.evName, to_string(ecuId), tempTask.logicalLink, tempTask.priority, mEcurityAccessMode);

				for (int i = 0; i < vecFlashInfo.size(); i++) {
					JD_VSP_FLASH_CONFIG_t oneFlahsInfo = vecFlashInfo.at(i);
					MyStringUtils::toUpper(oneFlahsInfo.strFileType);
					int fileType = Ecu_FotaPackageType_Data;    //TODO 0:Data;  1:SBL;  2:App   3:PBL
					if (oneFlahsInfo.strFileType._Equal("SBL")) {
						fileType = Ecu_FotaPackageType_SBL;
					}
					else if (oneFlahsInfo.strFileType._Equal("APP")) {
						fileType = Ecu_FotaPackageType_App;
					}
					else if (0 == strnicmp(oneFlahsInfo.strFileType.c_str(), "DATA", 4)) {
						fileType = Ecu_FotaPackageType_Data;
					}
					else if (oneFlahsInfo.strFileType._Equal("PBL")) {
						string tempString = DataCenter::m_vehicleInfo.mapEcuInfo[ecuId].ecuSwpn;
						if (tempString.find(oneFlahsInfo.strVersion) != string::npos) {
							Tracer::warn("skip PBL", oneFlahsInfo.strVersion);
							continue;
						}
						fileType = Ecu_FotaPackageType_PBL;
					}
					else if (0 == strnicmp(oneFlahsInfo.strFileType.c_str(), "ESS", 3)) {
						fileType = cu_FotaPackageType_ESS;
					}
					else if (0 == strnicmp(oneFlahsInfo.strFileType.c_str(), "EXE", 3)) {
						fileType = cu_FotaPackageType_EXE;
					}
					else {
						Tracer::error("invalid pkgType", oneFlahsInfo.strFileType);
						continue;
					}

					//TODO Bin文件
					uint64_t fileSize = oneFlahsInfo.nFlashFileSize;
					string filepath = CVehicleConfig::getInstance()->getFlashFileDir().append("\\").append(oneFlahsInfo.strFileName);
					manager->addECUFile(tempTask.evName, filepath, fileType, fileSize, pinCode, oneFlahsInfo.strKeyInfo);
				}
			}
			else {
				Tracer::error("invalid ecuFlashFile", ecuName);
				mapEcuFlasherTask[ecuId].status = Ecu_FotaStatus_Fail;
				continue;
			}
		}
		else {
			EcuFlasherTask tempTask = it->second;

			char ecuHwpn[32] = { 0 };
			get_jd_vehicleInfo_ecuHwpn_byEcuId(ecuId, ecuHwpn, 32);
			string pkgName = CVehicleConfig::getInstance()->getEcuName_byOrderEcuName(ecuName);
			vector<JD_VSP_FLASH_CONFIG_t> vecFlashInfo;
			if (CVehicleConfig::getInstance()->getEcuFileInfo(ecuId, ecuHwpn, vecFlashInfo))
			{
				manager->addECU(tempTask.evName, to_string(ecuId), tempTask.logicalLink, tempTask.priority, mEcurityAccessMode);

				for (int i = 0; i < vecFlashInfo.size(); i++) {
					JD_VSP_FLASH_CONFIG_t oneFlahsInfo = vecFlashInfo.at(i);
					VBFParserSmall* parser = oneFlahsInfo.pVBFParser;
					MyStringUtils::toUpper(oneFlahsInfo.strFileType);

					int fileType = Ecu_FotaPackageType_Data;    //TODO 0:Data;  1:SBL;  2:App   3:PBL
					if (oneFlahsInfo.strFileType._Equal("SBL")) {
						fileType = Ecu_FotaPackageType_SBL;
					}
					else if (oneFlahsInfo.strFileType._Equal("APP")) {
						fileType = Ecu_FotaPackageType_App;
					}
					else if (0 == strnicmp(oneFlahsInfo.strFileType.c_str(), "DATA", 4)) {
						fileType = Ecu_FotaPackageType_Data;

						//TODO POT 高配车不用12开头的数据包;低配车不刷13开头的数据包
						if (ecuName._Equal("POT"))
						{
							if (DataCenter::m_vehicleInfo.empennage == 0x02 && MyStringUtils::startWith(oneFlahsInfo.strFileName, "12")) {
								delete parser;
								continue;
							}
							else if (DataCenter::m_vehicleInfo.empennage == 0x01 && MyStringUtils::startWith(oneFlahsInfo.strFileName, "13")) {
								delete parser;
								continue;
							}
						}
					}
					else if (0 == strnicmp(oneFlahsInfo.strFileType.c_str(), "ESS", 3)) {
						fileType = cu_FotaPackageType_ESS;
					}
					else if (0 == strnicmp(oneFlahsInfo.strFileType.c_str(), "EXE", 3)) {
						fileType = cu_FotaPackageType_EXE;
					}
					else {
						Tracer::error("invalid pkgType", oneFlahsInfo.strFileType);
						delete parser;
						continue;
					}

#if true
					//TODO 临时文件
					int fileSize = oneFlahsInfo.pVBFParser->GetVBFData().size();
					std::string activeSBLAddress = oneFlahsInfo.pVBFParser->getHeader().getCall();
					string filename = tempTask.evName + "-" + oneFlahsInfo.strFileType + "-" + to_string(fileSize) + "-" + pinCode + "-" + tempTask.logicalLink + "-" + oneFlahsInfo.strFileName;
					string filepath = string("projects\\") + projectPath + "\\flashdata\\" + filename;

					FILE* fp = fopen(filepath.c_str(), "wb");
					if (fp != NULL) {
						fwrite(oneFlahsInfo.pVBFParser->GetVBFData().data(), 1, fileSize, fp);
						fclose(fp);
					}
					else {
						Tracer::warn("write vbf", filepath);
					}
#endif
					manager->addECUFile(tempTask.evName, fileType, pinCode, oneFlahsInfo.strSignature, parser);
					Tracer::debug("addECUFile", string("evName: ") + tempTask.evName + "; pinCode: " + pinCode + "; fileName: " + oneFlahsInfo.strFileName);

					delete parser;
				}
			}
			else {
				mapEcuFlasherTask[ecuId].status = Ecu_FotaStatus_Fail;
			}
		}
	}

	//TODO 有刷写任务
	for (auto it = mapEcuFlasherTask.begin(); it != mapEcuFlasherTask.end(); it++) {
		EcuFlasherTask tempTask = it->second;
		if (tempTask.status == Ecu_FotaStatus_Expect) {
			manager->download();
			break;
		}
	}

	isRunning = false;
}

void pthread_download2(string& ecuName, string& filepath, string& pinCode, string& keyInfo, int signatureMode, int securityAccess, int installVerify) {
	static bool isRunning = false;

	if (isRunning) {
		Tracer::error("err", "downloading");
		return;
	}
	else {
		isRunning = true;
	}

	if (pinCode._Equal("FFFFFFFFFF") || pinCode._Equal("ffffffffff")) {
		JD_ECU_SAFETY_CONSTANT_t safetyConstant;
		if (DataCenter::getInstance()->getEcuSafetyConstant(ecuName, safetyConstant)) {
			pinCode = safetyConstant.keySwdl;
		}
	}

	manager->addEventHandler(&eventHandler);
	uint16_t ecuId = get_jd_orderInfo_ecuId_byEcuName(ecuName.c_str());
	if (ecuId == 0) {
		isRunning = false;
		return;
	}

	string projectPath = "jidu";
	manager->getProjectPath(projectPath);
	Tracer::warn("storePath", projectPath);
	if (mapEcuFlasherTask.find(ecuId) == mapEcuFlasherTask.end())
	{
		Tracer::error("err", "mapEcuFlasherTask Is Empty");
		isRunning = false;
		return;
	}
	EcuFlasherTask tempTask = mapEcuFlasherTask.at(ecuId);
	//TODO 域控不是VBF格式 "TCAM", "BGM", "CDC", "ACU"(域控只刷写SOC)
	if (ecuName._Equal("TCAM") || MyStringUtils::endWith(ecuName, "_SOC")) {
		manager->addECU(tempTask.evName, to_string(ecuId), tempTask.logicalLink, tempTask.priority, mEcurityAccessMode);

		//TODO Bin文件
		FILE* fp = fopen(filepath.c_str(), "r");
		if (fp == NULL) {
			tempTask.status = Ecu_FotaStatus_Fail;
			mapEcuFlasherTask[ecuId] = tempTask;
			Tracer::error("invalid filepath", filepath);
		}
		else {
			_fseeki64(fp, 0, SEEK_END);
			uint64_t fileSize = _ftelli64(fp);
			fclose(fp);
			//TODO 通过文件大小判定文件类型： 小于1M则认定为PBL
			int	fileType = (fileSize < 0x400000) ? Ecu_FotaPackageType_PBL : Ecu_FotaPackageType_App;
			manager->addECUFile(tempTask.evName, filepath, fileType, fileSize, pinCode, keyInfo);
			manager->download();
		}
	}
	else if (MyStringUtils::startWith(ecuName, "ACU") || MyStringUtils::startWith(ecuName, "BGM") || MyStringUtils::startWith(ecuName, "CDC"))
	{
		tempTask.status = Ecu_FotaStatus_Fail;
		mapEcuFlasherTask[ecuId] = tempTask;
	}
	else {
		VBFParserSmall* parser = new VBFParserSmall();
		if (parser->ParseVBFFile(filepath, CVehicleConfig::getInstance()->getCertFilepath(), keyInfo))
		{
			string swPartType = parser->getHeader().getSWPartType();

			int fileType = Ecu_FotaPackageType_Data;
			if (swPartType._Equal("SBL")) {
				fileType = Ecu_FotaPackageType_SBL;
			}
			else if (swPartType._Equal("APP")) {
				fileType = Ecu_FotaPackageType_App;
			}
			else if (0 == strnicmp(swPartType.c_str(), "DATA", 4)) {
				fileType = Ecu_FotaPackageType_Data;
			}
			else if (0 == strnicmp(swPartType.c_str(), "ESS", 3)) {
				fileType = cu_FotaPackageType_ESS;
			}
			else {
				Tracer::error("invalid pkgType", swPartType);
			}

			manager->addECU(tempTask.evName, to_string(ecuId), tempTask.logicalLink, tempTask.priority, mEcurityAccessMode, signatureMode, securityAccess, installVerify);
#if true
			//TODO 临时文件
			int fileSize = parser->GetVBFData().size();
			std::string activeSBLAddress = parser->getHeader().getCall();
			string filename = tempTask.evName + "-" + swPartType + "-" + to_string(fileSize) + "-" + pinCode + "-" + tempTask.logicalLink + ".vbf";
			string filepath = string("projects\\") + projectPath + "\\flashdata\\" + filename;

			FILE* fp = fopen(filepath.c_str(), "wb");
			if (fp != NULL) {
				fwrite(parser->GetVBFData().data(), 1, fileSize, fp);
				fclose(fp);
			}
			else {
				Tracer::warn("write vbf", filepath);
			}
#endif
			manager->addECUFile(tempTask.evName, fileType, pinCode, keyInfo, parser);


			delete parser;
			manager->download();
		}
		else {
			tempTask.status = Ecu_FotaStatus_Fail;
			mapEcuFlasherTask[ecuId] = tempTask;
			Tracer::error("invalid vbf file", filepath);
		}
	}

	isRunning = false;
}


void pthread_download3(uint16_t ecuId, uint16_t bridgeId) {
	static bool isRunning = false;

	if (isRunning) {
		Tracer::error("err", "downloading");
		return;
	}
	else {
		isRunning = true;
		Tracer::debug(__FUNCTION__, to_string(ecuId));
	}

	string projectPath = "jidu";
	manager->getProjectPath(projectPath);
	Tracer::warn("storePath", projectPath);
	if (mapEcuFlasherTask.find(ecuId) == mapEcuFlasherTask.end())
	{
		Tracer::error("err", "mapEcuFlasherTask Is Empty");
	}

	string ecuName = CVehicleConfig::getInstance()->getBridgeEcuName(bridgeId);
	string pkiName = ecuName;
	for (auto itEcu = DataCenter::m_vehicleInfo.mapEcuInfo.begin(); itEcu != DataCenter::m_vehicleInfo.mapEcuInfo.end(); itEcu++) {
		uint16_t tempEcuId = itEcu->first;
		if ((tempEcuId & 0xFFF0) == (ecuId & 0xFFF0)) {
			pkiName = itEcu->second.pkiName;
			if (pkiName.empty()) {
				pkiName = ecuName;
			}
			break;
		}
	}

	JD_ECU_SAFETY_CONSTANT_t safetyConstant;
	if (true != DataCenter::getInstance()->getEcuSafetyConstant(pkiName, safetyConstant)) {
		Tracer::error(pkiName, "invalid EcuSafetyConstant");
		mapEcuFlasherTask[ecuId].status = Ecu_FotaStatus_Fail;
		isRunning = false;
		return;
	}
	string pinCode = safetyConstant.keySwdl;

	char ecuHwpn[32] = { 0 };
	get_jd_vehicleInfo_ecuHwpn_byEcuId(ecuId, ecuHwpn, 32);

	EcuFlasherTask tempTask = mapEcuFlasherTask.at(ecuId);
	//TODO 域控不是VBF格式 "TCAM", "BGM", "CDC", "ACU"(域控只刷写SOC)
	if (ecuId == 0x6011 || ecuId == 0x3011 || ecuId == 0x2011 || ecuId == 0x1011) {
		manager->addECU(tempTask.evName, to_string(ecuId), tempTask.logicalLink, tempTask.priority, mEcurityAccessMode);

		vector<JD_VSP_FLASH_CONFIG_t> vecFlashInfo;
		if (CVehicleConfig::getInstance()->getBridgeEcuFileInfo(bridgeId, ecuHwpn, vecFlashInfo)) {
			for (int i = 0; i < vecFlashInfo.size(); i++) {
				JD_VSP_FLASH_CONFIG_t oneFlahsInfo = vecFlashInfo.at(i);
				MyStringUtils::toUpper(oneFlahsInfo.strFileType);
				int fileType = Ecu_FotaPackageType_Data;    //TODO 0:Data;  1:SBL;  2:App   3:PBL
				if (oneFlahsInfo.strFileType._Equal("SBL")) {
					fileType = Ecu_FotaPackageType_SBL;
				}
				else if (oneFlahsInfo.strFileType._Equal("APP")) {
					fileType = Ecu_FotaPackageType_App;
				}
				else if (0 == strnicmp(oneFlahsInfo.strFileType.c_str(), "DATA", 4)) {
					fileType = Ecu_FotaPackageType_Data;
				}
				else if (oneFlahsInfo.strFileType._Equal("PBL")) {
					string tempString = DataCenter::m_vehicleInfo.mapEcuInfo[ecuId].ecuSwpn;
					if (tempString.find(oneFlahsInfo.strVersion) != string::npos) {
						Tracer::warn("skip PBL", oneFlahsInfo.strVersion);
						continue;
					}
					fileType = Ecu_FotaPackageType_PBL;
				}
				else if (0 == strnicmp(oneFlahsInfo.strFileType.c_str(), "ESS", 3)) {
					fileType = cu_FotaPackageType_ESS;
				}
				else if (0 == strnicmp(oneFlahsInfo.strFileType.c_str(), "EXE", 3)) {
					fileType = cu_FotaPackageType_EXE;
				}
				else {
					Tracer::error("invalid pkgType", oneFlahsInfo.strFileType);
					continue;
				}

				//TODO Bin文件
				uint64_t fileSize = oneFlahsInfo.nFlashFileSize;
				string filepath = CVehicleConfig::getInstance()->getBridgeFileDir(bridgeId).append("\\").append(oneFlahsInfo.strFileName);
				manager->addECUFile(tempTask.evName, filepath, fileType, fileSize, pinCode, oneFlahsInfo.strKeyInfo);
				manager->download();
			}
		}
		else {
			Tracer::error("invalid ecuFlashFile", ecuName);
			mapEcuFlasherTask[ecuId].status = Ecu_FotaStatus_Fail;
		}
	}
	else {
		char ecuHwpn[32] = { 0 };
		get_jd_vehicleInfo_ecuHwpn_byEcuId(ecuId, ecuHwpn, 32);
		string pkgName = CVehicleConfig::getInstance()->getEcuName_byOrderEcuName(ecuName);
		vector<JD_VSP_FLASH_CONFIG_t> vecFlashInfo;
		if (CVehicleConfig::getInstance()->getBridgeEcuFileInfo(bridgeId, ecuHwpn, vecFlashInfo)) {
			manager->addECU(tempTask.evName, to_string(ecuId), tempTask.logicalLink, tempTask.priority, mEcurityAccessMode);

			for (int i = 0; i < vecFlashInfo.size(); i++) {
				JD_VSP_FLASH_CONFIG_t oneFlahsInfo = vecFlashInfo.at(i);
				VBFParserSmall* parser = oneFlahsInfo.pVBFParser;
				MyStringUtils::toUpper(oneFlahsInfo.strFileType);

				int fileType = Ecu_FotaPackageType_Data;    //TODO 0:Data;  1:SBL;  2:App   3:PBL
				if (oneFlahsInfo.strFileType._Equal("SBL")) {
					fileType = Ecu_FotaPackageType_SBL;
				}
				else if (oneFlahsInfo.strFileType._Equal("APP")) {
					fileType = Ecu_FotaPackageType_App;
				}
				else if (0 == strnicmp(oneFlahsInfo.strFileType.c_str(), "DATA", 4)) {
					fileType = Ecu_FotaPackageType_Data;

					//TODO POT 高配车不用12开头的数据包;低配车不刷13开头的数据包
					if (ecuName._Equal("POT"))
					{
						if (DataCenter::m_vehicleInfo.empennage == 0x02 && MyStringUtils::startWith(oneFlahsInfo.strFileName, "12")) {
							delete parser;
							continue;
						}
						else if (DataCenter::m_vehicleInfo.empennage == 0x01 && MyStringUtils::startWith(oneFlahsInfo.strFileName, "13")) {
							delete parser;
							continue;
						}
					}
				}
				else if (0 == strnicmp(oneFlahsInfo.strFileType.c_str(), "ESS", 3)) {
					fileType = cu_FotaPackageType_ESS;
				}
				else if (0 == strnicmp(oneFlahsInfo.strFileType.c_str(), "EXE", 3)) {
					fileType = cu_FotaPackageType_EXE;
				}
				else {
					Tracer::error("invalid pkgType", oneFlahsInfo.strFileType);
					delete parser;
					continue;
				}

#if true
				//TODO 临时文件
				int fileSize = oneFlahsInfo.pVBFParser->GetVBFData().size();
				std::string activeSBLAddress = oneFlahsInfo.pVBFParser->getHeader().getCall();
				string filename = tempTask.evName + "-" + oneFlahsInfo.strFileType + "-" + to_string(fileSize) + "-" + pinCode + "-" + tempTask.logicalLink + "-" + oneFlahsInfo.strFileName;
				string filepath = string("projects\\") + projectPath + "\\flashdata\\" + filename;

				FILE* fp = fopen(filepath.c_str(), "wb");
				if (fp != NULL) {
					fwrite(oneFlahsInfo.pVBFParser->GetVBFData().data(), 1, fileSize, fp);
					fclose(fp);
				}
				else {
					Tracer::error("write vbf", filepath);
				}
#endif
				manager->addECUFile(tempTask.evName, fileType, pinCode, oneFlahsInfo.strSignature, parser);
				Tracer::debug("addECUFile", string("evName: ") + tempTask.evName + "; pinCode: " + pinCode + "; fileName: " + oneFlahsInfo.strFileName);

				delete parser;
			}
		}
		else {
			mapEcuFlasherTask[ecuId].status = Ecu_FotaStatus_Fail;
		}
	}

	isRunning = false;
}

int jd_ecuflash_getCmd(const char* ecuName, char* outBuffer, int outBufferSize)
{
	memset(outBuffer, 0, outBufferSize);

	string evEcuName = ecuName;
	if (!MyStringUtils::startWith(evEcuName, "EV_")) {
		evEcuName = "EV_" + string(ecuName);
	}

	vector<string> mVec;
	string tempString;
	if (manager->getcmd(evEcuName, mVec))
	{
		for (int i = 0; i < mVec.size(); i++) {
			string cmd = mVec.at(i);
			tempString.append(cmd);
			if (i < mVec.size() - 1) {
				tempString.append("\r\n");
			}
		}
	}
	else {
		Tracer::error("getcmd", "invalid ecuName: " + evEcuName);
		return -1;
	}

	if (outBufferSize > tempString.size()) {
		memcpy(outBuffer, tempString.c_str(), tempString.length());
		return tempString.length();
	}

	return -1;
}



bool jd_ecuflash_start()
{
	if (manager != NULL) {
		delete manager;
	}
	manager = new otx::flash::ECUFlasherManager();
	manager->addEventHandler(&eventHandler);
	std::thread dThread(pthread_download);
	dThread.detach();
	return true;
}

bool jd_ecuFlash_start2(const char* ecuName, const char* evName, const char* logicalLinkName, const char* pinCode, const char* filepath, const char* keyInfo, int signatureMode, int securityAccess, int installVerify)
{
	std::lock_guard<std::mutex> lock(mLock);

	if (manager != NULL) {
		delete manager;
	}
	manager = new otx::flash::ECUFlasherManager();
	manager->addEventHandler(&eventHandler);
	mapEcuFlasherTask.clear();
	Tracer::warn("jd_ecuFlash_start2", ecuName);

	uint16_t eucId = get_jd_orderInfo_ecuId_byEcuName(ecuName);

	EcuFlasherTask tempTask;
	tempTask.priority = 0;
	tempTask.logicalLink = logicalLinkName;
	tempTask.evName = evName;
	tempTask.ecuId = eucId;
	tempTask.ecuName = ecuName;
	mapEcuFlasherTask[eucId] = tempTask;

	std::thread dThread(pthread_download2, string(ecuName), string(filepath), string(pinCode), string(keyInfo), signatureMode, securityAccess, installVerify);
	dThread.detach();

	return true;
}

bool jd_ecuFlash_start3(uint16_t ecuId, const char* evName, const char* logicalLinkName, uint16_t bridgeId)
{
	std::lock_guard<std::mutex> lock(mLock);

	if (manager != NULL) {
		delete manager;
	}
	manager = new otx::flash::ECUFlasherManager();
	manager->addEventHandler(&eventHandler);
	mapEcuFlasherTask.clear();

	EcuFlasherTask tempTask;
	tempTask.priority = 0;
	tempTask.logicalLink = logicalLinkName;
	tempTask.evName = evName;
	tempTask.ecuId = ecuId;
	tempTask.ecuName = evName;
	tempTask.status = Ecu_FotaStatus_Expect;
	mapEcuFlasherTask[ecuId] = tempTask;

	std::thread dThread(pthread_download3, ecuId, bridgeId);
	dThread.detach();

	return true;
}

bool jd_ecuflash_stop()
{
	//mapEcuFlasherTask.clear();
	return bool();
}
