﻿#include "ECUFlasherImpl.hpp"
#include <vector>
#include "TimeUtils.h"
#include <thread>
#include "MCDFileDownloader.hpp"
#include "BinFileDownloader.hpp"
#include "VbfFileDownloader.hpp"
namespace otx {
	namespace flash {

#define FLASHER_USE_MCD_METHOD 1

		ECUFlasherImpl::ECUFlasherImpl() {
			this->mDownloadedSize = 0;
			this->mStartTime = 0;
			this->mTotalSize = 0;
		}

		void ECUFlasherImpl::addEventHandler(ECUFlasherEventHandler* eventListener) {
			this->mEventHandlers.push_back(eventListener);
		}
		void ECUFlasherImpl::clearEventHandlers() {
			this->mEventHandlers.clear();
		}

		unsigned long long ECUFlasherImpl::getRemainTime(ECU *ecu) {

			std::lock_guard<std::mutex> lock(this->mFieldLock);
		
			if (ecu->getDownloadedSize() >= ecu->getTotalSize()) {
				return 0;
			}
			unsigned long long now = getTimeStamp();
			size_t remainSize = ecu->getTotalSize() - ecu->getDownloadedSize();
			double speed = (double)ecu->getDownloadedSize() / (double)(now - this->mStartTime); // bytes/usec
			return (unsigned long long)((double)remainSize / speed); // usec
		}

		void ECUFlasherImpl::postECUDownloadStart(ECUFlasherECUEventArg& arg) {
			size_t size = this->mEventHandlers.size();
			for (int i = 0; i < size; i++) {
				ECUFlasherEventHandler* item = this->mEventHandlers[i];
				if (item) {
					item->onECUDownloadStart(arg);
				}
			}
		}
		void ECUFlasherImpl::postECUDownloadEnd(ECUFlasherECUEventArg& arg) {
			size_t size = this->mEventHandlers.size();
			for (int i = 0; i < size; i++) {
				ECUFlasherEventHandler* item = this->mEventHandlers[i];
				if (item) {
					item->onECUDownloadEnd(arg);
				}
			}
		}
		void ECUFlasherImpl::postECUResetStart(ECUFlasherECUEventArg& arg)
		{
			size_t size = this->mEventHandlers.size();
			for (int i = 0; i < size; i++) {
				ECUFlasherEventHandler* item = this->mEventHandlers[i];
				if (item) {
					item->onECUResetStart(arg);
				}
			}
		}
		void ECUFlasherImpl::postECUResetEnd(ECUFlasherECUEventArg& arg)
		{
			size_t size = this->mEventHandlers.size();
			for (int i = 0; i < size; i++) {
				ECUFlasherEventHandler* item = this->mEventHandlers[i];
				if (item) {
					item->onECUResetStart(arg);
				}
			}
		}
		void ECUFlasherImpl::postFileDownloadStart(ECUFlasherFileEventArg& arg) {
			size_t size = this->mEventHandlers.size();
			for (int i = 0; i < size; i++) {
				ECUFlasherEventHandler* item = this->mEventHandlers[i];
				if (item) {
					item->onFileDownloadStart(arg);
				}
			}
		}
		void ECUFlasherImpl::postFileDownloadEnd(ECUFlasherFileDownloadEndEventArg& arg) {
			size_t size = this->mEventHandlers.size();
			for (int i = 0; i < size; i++) {
				ECUFlasherEventHandler* item = this->mEventHandlers[i];
				if (item) {
					item->onFileDownloadEnd(arg);
				}
			}
		}
		void ECUFlasherImpl::postFileDownloadProgress(ECUFlasherFileDownloadProgressEventArg& arg) {
			size_t size = this->mEventHandlers.size();
			for (int i = 0; i < size; i++) {
				ECUFlasherEventHandler* item = this->mEventHandlers[i];
				if (item) {
					item->onFileDownloadProgress(arg);
				}
			}
		}

#if defined(FLASHER_USE_MCD_METHOD) && FLASHER_USE_MCD_METHOD > 0

		bool ECUFlasherImpl::downloadFile(ECU* ecu, File* ecuFile) {
			bool retFlag = false;

			otx::flash::ECUFlasherFileEventArg fdsarg(this, ecu, ecuFile);
			this->postFileDownloadStart(fdsarg);

			//TODO 域控不是VBF格式 "TCAM", "BGM", "CDC", "ACU"
			string ecuName = ecu->getName();
			if (string::npos != ecuName.find("TCAM") || string::npos != ecuName.find("BGM") || string::npos != ecuName.find("CDC") || string::npos != ecuName.find("ACU")) {
				BinFileDownloader downloader;
				downloader.setFlasher(this);
				retFlag = downloader.downloadFile(ecu, ecuFile);

				otx::flash::ECUFlasherFileDownloadEndEventArg fdearg(this, ecu, ecuFile, downloader.getErrorCode(), downloader.getMessage());
				this->postFileDownloadEnd(fdearg);
			}
			else {
				VbfFileDownloader downloader;
				downloader.setFlasher(this);
				retFlag = downloader.downloadFile(ecu, ecuFile);
				otx::flash::ECUFlasherFileDownloadEndEventArg fdearg(this, ecu, ecuFile, downloader.getErrorCode(), downloader.getMessage());
				this->postFileDownloadEnd(fdearg);

			}

			return retFlag;
		}
#else

		void ECUFlasherImpl::downloadFile(ECU* ecu, File* ecuFile) {
			otx::flash::ECUFlasherFileEventArg fdsarg(this, ecu, ecuFile);
			this->postFileDownloadStart(fdsarg);
			while (1) {
				{ // zone of lock.
					std::lock_guard<std::mutex> lock(this->mFieldLock);
					size_t increase = (double)ecuFile->getSize() * (double)0.1;
					this->mDownloadedSize += increase;
					ecuFile->increaseDownloadedSize(increase);// 会设置最近一次下载大小。
				}
				size_t progress = 100 * (double)ecuFile->getDownloadedSize() / (double)ecuFile->getSize();
				otx::flash::ECUFlasherFileDownloadProgressEventArg pearg(this, ecu, ecuFile, progress);
				this->postFileDownloadProgress(pearg);
				if (ecuFile->getSize() == ecuFile->getDownloadedSize()) {
					break;
				}
				else {
					std::this_thread::sleep_for(std::chrono::milliseconds(200));
				}
			}
			otx::flash::ECUFlasherFileDownloadEndEventArg fdearg(this, ecu, ecuFile, 0, "OKAY");
			this->postFileDownloadEnd(fdearg);
		}

#endif

	} // namespace flash
} // namespace otx