#include "VBFHeader.h"

#include <vector>
#include "MyStringUtils.h"
#include "tracer.h"
#include <regex>

using namespace std;

VBFHeader::VBFHeader()
{

}

bool VBFHeader::ParseHeader(vector<unsigned char>& buffer)
{
	m_nEofHeader = FindEOFHeader(buffer);

	if (m_nEofHeader <= 0)
	{
		return false;
	}

	if (!getHeader(buffer))
	{
		return false;
	}

	if (!convertHeader())
	{
		std::string msg = "VBFHeader() - Couldnt convert header!";
		Tracer::info("", msg.c_str());
		return false;
	}

	return true;
}

int VBFHeader::getHeaderLength()
{
	if (m_nEofHeader < 0)
	{
		std::string msg = "VBFHeader() - EOFHeader not yet set!";
		Tracer::info("", msg.c_str());

	}
	return m_nEofHeader;
}

bool VBFHeader::convertHeader()
{
	m_strVBFVersion = getVBFVersion();
	//Tracer::info("VBFVersion", m_strVBFVersion.c_str());

	if (m_strVBFVersion != "2.6")
	{
		Tracer::warn("VBFVersion is NOT 2.6 but", m_strVBFVersion.c_str());
	}

	if (m_strHeader.find("description") != m_strHeader.npos)
	{
		m_strDescription = getPDescription();
	}

	m_strSWPartNumber = getPSWPartNumber();
	if (m_strHeader.find("sw_version") != m_strHeader.npos)
	{
		m_strSWVersion = getPSWPartVersion();
	}
	if (m_strHeader.find("sw_current_part_number") != m_strHeader.npos)
	{
		m_strSWCurrPartNo = getPSWPartNumberCurrent();
	}
	if (m_strHeader.find("sw_current_version") != m_strHeader.npos)
	{
		m_strSWCurrVersion = getPSWPartVersionCurrent();
	}
	m_strSWPartType = getPSWPartType();
	if (m_strHeader.find("data_format_identifier") != m_strHeader.npos)
	{
		m_strDataFormatIdentifier = getPDataFormatIdentifier();
	}
	m_strECUAddress = getPECUAddress();
	if (m_strHeader.find("erase") != m_strHeader.npos)
	{
		m_vecListErases = getPErase();
	}
	if (m_strHeader.find("call") != m_strHeader.npos)
	{
		m_strCall = getPCall();
	}
	m_strFileChecksum = getPFileChecksum();
	if (m_strHeader.find("verification_block_root_hash") != m_strHeader.npos)
	{
		m_strBlockRootHash = getPBlockRootHash();
	}
	if (m_strHeader.find("verification_block_start") != m_strHeader.npos)
	{
		m_strBlockStart = getPBlockStart();
	}
	if (m_strHeader.find("verification_block_length") != m_strHeader.npos)
	{
		m_strBlockLength = getPBlockLength();
	}
	if (m_strHeader.find("sw_signature_dev") != m_strHeader.npos)
	{
		m_strSWSigDev = getPSWSignatureDev();
	}
	if (m_strHeader.find("sw_signature") != m_strHeader.npos)
	{
		m_strSW_sig = getPSWSignature();
	}
	dumpVBFInfo();
	return true;
}

void VBFHeader::dumpVBFInfo()
{
	//Tracer::info("VBFVersion", m_strVBFVersion.c_str());
	//Tracer::info("sw_part_number", m_strSWPartNumber.c_str());
	//Tracer::info("sw_part_type", m_strSWPartType.c_str());
	//Tracer::info("sw_version", m_strSWVersion.c_str());
	//Tracer::info("file_checksum", m_strFileChecksum.c_str());
	//Tracer::info("ecu_address", m_strECUAddress.c_str());
}

std::string VBFHeader::getVersion()
{
	return m_strVBFVersion;
}

std::string VBFHeader::getSWPartNum()
{
	return m_strSWPartNumber;
}

std::string VBFHeader::getSWPartType()
{
	return m_strSWPartType;
}

std::string VBFHeader::getSWVersion()
{
	return m_strSWVersion;
}

std::string VBFHeader::getFileChecksum()
{
	return m_strFileChecksum;
}

std::string VBFHeader::getEcu_address()
{
	return m_strECUAddress;
}

bool VBFHeader::hasDescription()
{
	return (m_strDescription == "") || (m_strDescription.length() > 0);
}

bool VBFHeader::hasCall()
{
	return (m_strCall == "") || (m_strCall.length() > 0);;
}

std::string VBFHeader::getCall()
{
	return m_strCall;
}

bool VBFHeader::hasErase()
{
	return (m_vecListErases.empty()) || (m_vecListErases.size() > 0);
}

vector<std::string> VBFHeader::getListOfErase()
{
	return m_vecListErases;
}

bool VBFHeader::hasDataFormatIdentifier()
{
	return (m_strDataFormatIdentifier == "") || (m_strDataFormatIdentifier.length() > 0);
}

std::string VBFHeader::getDataFormatIndetifier()
{
	return m_strDataFormatIdentifier;
}

bool VBFHeader::has_SWCurrVersion()
{
	return (m_strSWCurrVersion == "") || (m_strSWCurrVersion.length() > 0);
}

std::string VBFHeader::getSWCurrVersion()
{
	return m_strSWCurrVersion;
}

bool VBFHeader::has_SWCurrPartNo()
{
	return (m_strSWCurrPartNo == "") || (m_strSWCurrPartNo.length() > 0);
}

std::string VBFHeader::getSWCurrPartNo()
{
	return m_strSWCurrPartNo;
}

bool VBFHeader::has_VerifBlockRootHash()
{
	return (m_strBlockRootHash == "") || (m_strBlockRootHash.length() > 0);
}

std::string VBFHeader::getVerifBlockRootHash()
{
	return m_strBlockRootHash;
}

bool VBFHeader::has_VerifBlockStart()
{
	return (m_strBlockStart == "") || (m_strBlockStart.length() > 0);
}

std::string VBFHeader::getVerifBlockStart()
{
	return m_strBlockStart;
}

bool VBFHeader::has_VerifBlockLength()
{
	return  (m_strBlockLength == "") || (m_strBlockLength.length() > 0);
}

std::string VBFHeader::getVerifBlockLength()
{
	return m_strBlockLength;
}

bool VBFHeader::has_SWSignatureDev()
{
	return (m_strSWSigDev == "") || (m_strSWSigDev.length() > 0);
}

std::string VBFHeader::getSWSignatureDev()
{
	return m_strSWSigDev;
}

bool VBFHeader::has_SWSignature()
{
	return (this->m_strSW_sig == "") || (this->m_strSW_sig.length() > 0);
}

std::string VBFHeader::getSWSignature()
{
	return this->m_strSW_sig;
}

std::string VBFHeader::getheaderString()
{
	return m_strHeader;
}

int VBFHeader::FindEOFHeader(vector<unsigned char>& buffer)
{
	int bracketcount = 0;

	if (m_nMaxHeader > (int)buffer.size())
	{
		m_nMaxHeader = (int)buffer.size();
	}

	for (int i = 0; i < m_nMaxHeader; i++)
	{
		bracketcount = buffer[i] == '{' ? bracketcount + 1 : bracketcount;
		bracketcount = buffer[i] == '}' ? bracketcount - 1 : bracketcount;

		if (bracketcount == 0 && buffer[i] == '}')
		{
			return i;
		}
	}

	return -1;
}

bool VBFHeader::getHeader(vector<unsigned char>& buffer)
{
	if (m_nEofHeader < 0)
	{
		Tracer::error("getHeader","EOF Header not found!");
		return false;
	}

	m_strHeader.assign(buffer.begin(), buffer.begin() + m_nEofHeader);


	std::string replace_str = "\r\n";
	rsize_t pos = -1;
	while ((pos = m_strHeader.find(replace_str)) != m_strHeader.npos)
		m_strHeader = m_strHeader.replace(pos, replace_str.length(), "__LF__");
	replace_str = "\n";
	pos = -1;
	while ((pos = m_strHeader.find(replace_str)) != m_strHeader.npos)
		m_strHeader = m_strHeader.replace(pos, replace_str.length(), "__LF__");

	return true;
}

int VBFHeader::findNextTokenInfo(std::string in, std::string tok, int start)
{
	int ind1 = start;
	if ((tok != "") && (!tok.empty())) {
		ind1 = in.find(tok, start);
	}
	if (ind1 < 0) {
		return -1;
	}
	return ind1;
}

std::string VBFHeader::getTokenInfo(const std::string& in, const std::string& tok, int start)
{
	int nStartPos = start;
	if ((tok != "") && (!tok.empty())) {
		nStartPos = in.find(tok, start);
	}
	if (nStartPos < 0)
	{
		Tracer::error("getTokenInfo", "PartNum Info not found!");
		return "";
	}
	int nEndPos = in.find(";", nStartPos);
	if (nEndPos < 0)
	{
		Tracer::error("getTokenInfo", "PartNum Info (End) not found!");
		return "";
	}
	std::string strInfo = in.substr(nStartPos, nEndPos - nStartPos);
	strInfo = MyStringUtils::trim(strInfo);

	vector<std::string> vecResult;
	MyStringUtils::SplitStringByRegExp(strInfo, vecResult, "\\s*=\\s*");
	//SplitString(tmp, spl, "=", true);
	//SplitStringReg(tmp, spl, "\s*=\s*");
	//	String[] spl = tmp.trim().split("\\s*=\\s*");

	if (vecResult.size() != 2)
	{
		Tracer::error("getTokenInfo", "Version Info not a Tuple!");
		return "";
	}
	std::string strTemp = vecResult[1];
	MyStringUtils::trim(strTemp);
	return strTemp;
}

std::string VBFHeader::getTokenInfo(const std::string& in, const std::string& tok)
{
	return getTokenInfo(in, tok, 0);
}

std::string VBFHeader::getVBFVersion()
{
	std::string strTemp = getTokenInfo(m_strHeader, "vbf_version");
	MyStringUtils::toUpper(strTemp);
	return strTemp;
}

std::string VBFHeader::formatDesc(std::string in)
{

	//String[] srs = in.trim().split("\\{|\\}|\"|,|__LF__");
	vector<string> srs;
	in = MyStringUtils::trim(in);
	MyStringUtils::SplitStringByRegExp(in, srs, "\\{|\\}|\"|,|__LF__");
	/*StringBuffer buf = new StringBuffer();*/
	std::string buf = "";
	for (unsigned int i = 0; i < srs.size(); i++)
	{
		std::string get = srs[i];
		std::regex regexStr("\\s+");
		std::smatch matchResult;
		if ((!get.empty()) && (!std::regex_match(get, matchResult, regexStr)))
		{
			buf += get;
			buf += "__LF__";
		}
	}
	return buf;
}

std::string VBFHeader::getPDescription()
{
	if (findNextTokenInfo(m_strHeader, "description", 0) < 0) {
		return "";
	}
	int pos = 0;
	bool finished = false;
	//StringBuffer buf = new StringBuffer();
	std::string buf = "";
	;	while (!finished)
	{
		int npos = findNextTokenInfo(m_strHeader, "description", pos);
		if (npos < 0) {
			return buf;
		}
		std::string tmp = getTokenInfo(m_strHeader, "description", pos);
		buf.append(formatDesc(tmp));

		buf.append("__LF__");
		pos = npos + 1;
	}
	return "";
}

std::string VBFHeader::getPSWPartNumber()
{
	std::string strTemp = getTokenInfo(m_strHeader, "sw_part_number");
	MyStringUtils::replace(strTemp, "\"", "");
	MyStringUtils::toUpper(strTemp);
	return strTemp;
}

std::string VBFHeader::getPSWPartNumberCurrent()
{
	std::string strTemp = getTokenInfo(m_strHeader, "sw_current_part_number");
	MyStringUtils::replace(strTemp, "\"", "");
	MyStringUtils::toUpper(strTemp);
	return strTemp;
}

std::string VBFHeader::getPSWPartVersion()
{
	std::string strTemp = getTokenInfo(m_strHeader, "sw_version");
	MyStringUtils::replace(strTemp, "\"", "");
	MyStringUtils::toUpper(strTemp);
	return strTemp;
}

std::string VBFHeader::getPSWPartVersionCurrent()
{
	std::string strTemp = getTokenInfo(m_strHeader, "sw_current_version");
	MyStringUtils::replace(strTemp, "\"", "");
	MyStringUtils::toUpper(strTemp);
	return strTemp;
}

std::string VBFHeader::getPSWPartType()
{
	return getTokenInfo(m_strHeader, "sw_part_type");
}

std::string VBFHeader::getPDataFormatIdentifier()
{
	if (findNextTokenInfo(m_strHeader, "data_format_identifier", 0) < 0) {
		return "00";
	}
	std::string tmp = getTokenInfo(m_strHeader, "data_format_identifier");
	return getHexNumberString(tmp);
}

std::string VBFHeader::getHexNumberString(std::string in)
{
	if (in.find("0x") == 0) {
		in = in.substr(2);
		in = MyStringUtils::trim(in);
		return in;
	}

	char tempBuffer[32] = {0};
	itoa(stoi(in, nullptr, 10), tempBuffer, 16);
	return tempBuffer;
}

std::string VBFHeader::getPECUAddress()
{
	std::string strTemp = getTokenInfo(m_strHeader, "ecu_address");
	return strTemp;
}

std::string VBFHeader::getPBlockRootHash()
{
	std::string strTemp = getTokenInfo(m_strHeader, "verification_block_root_hash");
	MyStringUtils::toUpper(strTemp);
	return strTemp;
}

std::string VBFHeader::getPBlockStart()
{
	std::string tmp = getTokenInfo(m_strHeader, "verification_block_start");
	return tmp;
}

std::string VBFHeader::getPBlockLength()
{
	std::string strTemp = getTokenInfo(m_strHeader, "verification_block_length");
	MyStringUtils::toUpper(strTemp);
	return strTemp;
}

std::string VBFHeader::getPSWSignatureDev()
{
	std::string strTemp = getTokenInfo(m_strHeader, "sw_signature_dev");
	MyStringUtils::toUpper(strTemp);
	return strTemp;
}

std::string VBFHeader::getPSWSignature()
{
	int startdev = m_strHeader.find("sw_signature_dev");
	int start = m_strHeader.find("sw_signature");
	std::string xtmp = m_strHeader;
	if (startdev > 0) {
		if (start == startdev) {
			start = m_strHeader.find("sw_signature", start + 1);
		}
	}
	if (startdev < start) {
		xtmp = m_strHeader.substr(startdev + std::string("sw_signature_dev").length());
	}
	if (start < 0) {
		return "";
	}
	std::string tmp = getTokenInfo(xtmp, "sw_signature");
	return tmp;
}

vector<std::string> VBFHeader::formatErase(std::string in)
{
	//	String[] srs = in.trim().split("\\{|\\}|\"|,|__LF__");

	in = MyStringUtils::trim(in);
	vector<std::string> srs;
	MyStringUtils::SplitStringByRegExp(in, srs, "\\{|\\}|\"|,|__LF__");

	//ArrayList<String> list = new ArrayList();
	vector<std::string> list;
	for (unsigned int i = 0; i < srs.size() - 1; i++)
	{
		//std::string get = srs[i].replaceAll("0[xX]", ""); 
		std::string get = MyStringUtils::replace(srs[i], "0x", "");
		get = MyStringUtils::replace(get, "0X", "");

		std::regex regexStr("\\s+");
		std::smatch matchResult;
		if ((!get.empty()) && (!std::regex_match(get, matchResult, regexStr)))

			//if ((!get.empty()) && (!get.matches("\\s+")))
		{
			;
			std::string getl = MyStringUtils::replace(MyStringUtils::trim(srs[(i + 1)]), "0x", "");
			getl = MyStringUtils::replace(getl, "0X", "");
			getl = MyStringUtils::trim(getl);
			list.push_back(get + "," + getl);
			i++;
		}
	}
	return list;
}

vector<std::string> VBFHeader::getPErase()
{
	if (findNextTokenInfo(m_strHeader, "erase", 0) < 0) {
		return vector<std::string>();
	}
	int pos = 0;
	bool finished = false;
	std::string tmp = getTokenInfo(m_strHeader, "erase", pos);
	return formatErase(tmp);
}

std::string VBFHeader::getPCall()
{
	return getTokenInfo(m_strHeader, "call");
}

std::string VBFHeader::getPFileChecksum()
{
	std::string strTemp = getTokenInfo(m_strHeader, "file_checksum");
	MyStringUtils::trim(strTemp);
	return strTemp;
}
