// namebin.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "namebin.h"
#include "../../include/ar168.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//BOOL RunProcess(CString strCmdLine);
void RenameBinary(CString strFileName, CString strVer, CString strCall, CString strRes, CString strOem);
void CommandLineDefault(int argc, TCHAR* argv[], CString & strFileName, CString & strVer, CString & strCall, CString & strRes, CString & strOem);
void _SetFlag(char * p, CString & strVal, int iMax);
BOOL _MergeFile(CString strCurDir, CString strSrcName, CString strDstName, CString strVer, CString strCall, CString strRes, CString strOem, CString strVersion);
void _SetFile(char * p, CString strVer, CString strCall, CString strRes, CString strOem, CString strVersion);

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std;

void PrintHelp()
{
	printf("%s\n", "namebin srcFile hardware [protocol] [country] [oem]");
	printf("%s\n", "srcFile\t\tSpecifies the source files");
	printf("%s\n", "hardware\tphone's hardware");
	printf("%s\n", "[protocol]\tPhone's protocol");
	printf("%s\n", "[country]\tPhone's language");
	printf("%s\n", "[oem]\t\tOEM");
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	// initialize MFC and print and error on failure
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: change error code to suit your needs
		cerr << _T("Fatal Error: MFC initialization failed") << endl;
		nRetCode = 1;
	}
	else
	{
		if (argc < 2)
		{
			PrintHelp();
		}
		else
		{
			CString strFileName, strVer, strCall, strRes, strOem;
			
			CommandLineDefault(argc, argv, strFileName, strVer, strCall, strRes, strOem);
			RenameBinary(strFileName, strVer, strCall, strRes, strOem);
		}
	}

	return nRetCode;
}

CString _GetVersion(CString strCurDir)
{
	CString strVersion = "Unknown";
	CStdioFile in;
	CString strIn;
	CString str;
	BOOL bStart;

	if (!in.Open(strCurDir.Left(strCurDir.GetLength() - 4) + "include\\version.h", CFile::modeRead|CFile::typeText))
	{
		goto End;
	}

	strVersion = "";
	bStart = FALSE;
	while (in.ReadString(strIn))
	{
		if (strIn.Left(10) == "/*########")
		{
			bStart = TRUE;
			continue;
		}
		if (!bStart) continue;

		if (strIn.Left(7) == "#define")
		{
			str = strIn.Right(strIn.GetLength() - 7);
			str.TrimLeft();
			if (str.Left(13) == "SOFT_VER_HIGH")
			{
				str = str.Right(str.GetLength() - 13);
				str.TrimLeft();
				strVersion += str;
			}
			else if (str.Left(12) == "SOFT_VER_LOW")
			{
				str = str.Right(str.GetLength() - 12);
				str.TrimLeft();
				strVersion += str;
			}
			else if (str.Left(14) == "SOFT_VER_BUILD")
			{
				str = str.Right(str.GetLength() - 14);
				str.TrimLeft();
				strVersion += str;
			}
			else if (str.Left(14) == "ENG_BUILD_HIGH")
			{
				str = str.Right(str.GetLength() - 14);
				str.TrimLeft();
				strVersion += str;
			}
			else if (str.Left(13) == "ENG_BUILD_MID")
			{
				str = str.Right(str.GetLength() - 13);
				str.TrimLeft();
				strVersion += str;
			}
			else if (str.Left(13) == "ENG_BUILD_LOW")
			{
				str = str.Right(str.GetLength() - 13);
				str.TrimLeft();
				strVersion += str;
			}
		}
	}

	in.Close();

End:
	return strVersion;
}

void _SetFlag(char * p, CString & strVal, int iMax)
{
	int iLen;

	iLen = strVal.GetLength();
	memcpy((char *)p, strVal, iLen);
	memset((char *)p+iLen, 0, iMax-iLen);
}

void _SetStr(char * p, CString strVal, int iMax)
{
	int iLen;

	iLen = strVal.GetLength();
	memcpy((char *)p, strVal, iLen);
	memset((char *)p+iLen, 0, iMax-iLen);
}

void _SetFile(char * p, CString strVer, CString strCall, CString strRes, CString strOem, CString strVersion)
{
	int iLen;

	iLen = 0;
	_SetStr((char *)(p+iLen), strVer, MAX_FLAG_PRODUCT_LEN);
	iLen += MAX_FLAG_PRODUCT_LEN;
	_SetStr((char *)(p+iLen), strCall, MAX_FLAG_PROTOCOL);
	iLen += MAX_FLAG_PROTOCOL;
	_SetStr((char *)(p+iLen), strRes, MAX_FLAG_COUNTRY);
	iLen += MAX_FLAG_COUNTRY;
	if (strOem != "Unknown")
	{
		_SetStr((char *)(p+iLen), strOem, MAX_FLAG_OEM_LEN);
	}
	else
	{
		memset((char *)(p+iLen), 0, MAX_FLAG_OEM_LEN);
	}
	iLen += MAX_FLAG_OEM_LEN;
	_SetStr((char *)(p+iLen), strVersion, MAX_FLAG_VERSION);
}

BOOL _WriteHttpPage(char * p, CStringList & listSrcName)
{
	CFile in;
	CString strSrcName;
	POSITION pos;
	int iIndex, iAddr, iLen;

	iIndex = 0;
	iAddr = 64;
	for (pos = listSrcName.GetHeadPosition(); pos != NULL;)
	{
		strSrcName = listSrcName.GetNext(pos);
		if (!in.Open(strSrcName, CFile::modeRead))
		{
			return FALSE;
		}
		iLen = (int)in.GetLength();
		p[iIndex] = (BYTE)(iAddr>>8);
		p[iIndex+1] = (BYTE)iAddr;
		p[iIndex+2] = (BYTE)(iLen >> 8);
		p[iIndex+3] = (BYTE)iLen;

		in.Read((char *)(p + iAddr), iLen);
		iAddr += iLen;
		iIndex += 4;
		in.Close();
	}

	return TRUE;

}

#define DSP_FILE_NUM	12
const char * _cDspFiles[DSP_FILE_NUM] = 
{"g711.dat", "gsm.dat", "g729.dat", "ilbc.dat", "speex.dat", 
 "spx_tab4k.dat", "spx_tab6k.dat", "spx_tab8k.dat", "spx_tab11k.dat", "spx_tab15k.dat",
 "spx_tab18k.dat" ,"spx_tab25k.dat"
};

BOOL _MergeFile(CString strCurDir, CString strSrcName, CString strDstName, CString strVer, CString strCall, CString strRes, CString strOem, CString strVersion)
{
	CFile out;
	CFile in;
	CStringList listSrcName;
	CString strResDir;
	CString strFileName;
	int i, iLength, iWriteLen;
	unsigned int iOffset = 0xffd0;
	char * p;
	char * pCur;
	CString strTempFile;
	CString strTempVer;
	CFileStatus status;
	
	if (!in.Open(strSrcName, CFile::modeRead))
	{
		printf("\nUnable to open %s", strSrcName);
		return FALSE;
	}
	if (!out.Open(strDstName, CFile::modeCreate|CFile::modeWrite))
	{
		printf("\nUnable to create %s", strDstName);
		in.Close();
		return FALSE;
	}

	iLength = (int)in.GetLength();
	p = (char *)malloc(iLength);
	in.Read(p, iLength);
	in.Close();

	for (i = 0; i < iLength; i += FILE_FULL_PAGE_SIZE)
	{
		_SetFile((char *)(p + iOffset), strVer, strCall, strRes, strOem, strVersion);
		iOffset += 0x010000;
	}

	out.Write(p, iLength);

	if (iLength > FILE_FULL_PAGE_SIZE)
	{	
		// add http data for main upgrade binary file
		strResDir = strCurDir + "res\\";
		strTempVer = strVer;
		strTempVer.MakeLower();
		if (strOem == "bt2008" || strTempVer == "bt2008" || strTempVer == "bt2008n")
		{
			strResDir += "bt2008\\";
		}
		else if (strOem == "innomedia")
		{
			strResDir += "innomedia\\";
		}
		else if (strOem == "ip20")
		{
			strResDir += "ip20\\";
		}
		strResDir += strRes + "\\";

		strTempFile = strResDir + "login.htm"; 
		if (!CFile::GetStatus(strTempFile, status))
		{	// use us http page if speical language not found
			strResDir = strCurDir + "res\\us\\";
		}

		listSrcName.AddTail(strResDir + "login.htm");
		if (strCall == "sip")
		{
			listSrcName.AddTail(strResDir + "settings_sip.htm");
		}
		else
		{
			listSrcName.AddTail(strResDir + "settings_iax2.htm");
		}
		listSrcName.AddTail(strResDir + "phonebook_head.htm");
		listSrcName.AddTail(strResDir + "phonebook_tail.htm");
		listSrcName.AddTail(strResDir + "upgrade.htm");
		listSrcName.AddTail(strResDir + "success.htm");
		listSrcName.AddTail(strResDir + "failure.htm");
		listSrcName.AddTail(strResDir + "abort.htm");
		listSrcName.AddTail(strResDir + "image.jpg");
		listSrcName.AddTail(strResDir + "digitmap_head.htm");
		listSrcName.AddTail(strResDir + "digitmap_tail.htm");

		memset(p, 0, FILE_FULL_PAGE_SIZE);
		if (!_WriteHttpPage(p, listSrcName))
		{
			free(p);
			out.Close();
			CFile::Remove(strDstName);
			return FALSE;
		}
		_SetFile((char *)(p + FILE_FLAG_PAGE_SIZE), strVer, strCall, strRes, strOem, strVersion);
		out.Write(p, FILE_FULL_PAGE_SIZE);

		// add all dsp data for main upgrade binary file
		free(p);
		p = (char *)malloc(FILE_FULL_PAGE_SIZE * SYSTEM_DSP_PAGE_NUM);
		memset(p, 0, FILE_FULL_PAGE_SIZE * SYSTEM_DSP_PAGE_NUM);
		pCur = p;
		iOffset = 0;
		for (i = 0; i < DSP_FILE_NUM; i ++)
		{
			strFileName = strCurDir + "\\res\\" + _cDspFiles[i];
			if (!in.Open(strFileName, CFile::modeRead))
			{
				free(p);
				out.Close();
				CFile::Remove(strDstName);
				return FALSE;
			}
			iLength = (int)in.GetLength();
			while (iLength)
			{
				if ((iLength + iOffset) < FILE_FLAG_PAGE_SIZE)
				{
					in.Read(pCur, iLength);
					iOffset += iLength;
					pCur += iLength;
					iLength = 0;
				}
				else
				{
					iWriteLen = FILE_FLAG_PAGE_SIZE - iOffset;
					in.Read(pCur, iWriteLen);
					iLength -= iWriteLen;
					pCur += iWriteLen + (FILE_FULL_PAGE_SIZE - FILE_FLAG_PAGE_SIZE);
					iOffset = 0;
				}
			}
			in.Close();
		}
	
		pCur = p;

		for (i = 0; i < SYSTEM_DSP_PAGE_NUM; i ++)
		{
			_SetFile((char *)(pCur + FILE_FLAG_PAGE_SIZE), strVer, strCall, strRes, strOem, strVersion);
			pCur += FILE_FULL_PAGE_SIZE;
		}
		out.Write(p, FILE_FULL_PAGE_SIZE * SYSTEM_DSP_PAGE_NUM);
	}

	free(p);
	out.Close();
	return TRUE;
}

BOOLEAN _WriteFile(CFile& out, CString strFileName, int iLength)
{
	char * p;
	CFile in;

	p = (char *)malloc(iLength);
	memset(p, 0, iLength);
	if (!in.Open(strFileName, CFile::modeRead))
	{
		printf("Unable to open %s\n", strFileName);
		return FALSE;
	}
	in.Read(p, iLength);
	in.Close();
	out.Write(p, iLength);
	free(p);
	return TRUE;
}

void RenameBinary(CString strFileName, CString strVer, CString strCall, CString strRes, CString strOem)
{
	CString strDstName, strCurDir, strSrcName;
	CString strAllName, strSettingName, strDigitmapName, strPhonebookName, strPage0Name, strVersion, strRingtoneName, strHoldmusicName, strFontName, strUpgradeName;
	CFileStatus status;
	CFile out;
	CFile in;
	int iLength;
	char * p;
	char szCurDir[128];
	CString strCmdLine, strSettingsFile, strDigitmapFile;

	GetCurrentDirectory(128, szCurDir);
	strSrcName.Format("%s\\%s", szCurDir, strFileName);
	strCurDir.Format("%s\\", szCurDir);

	strDstName = strCurDir + strVer + "_" + strCall + "_" + strRes + "_";
	if (strOem != "Unknown")
	{
		strDstName += strOem + "_";
	}
	strVersion = _GetVersion(strCurDir);
	strDstName += strVersion;
	strAllName = strDstName;
	strAllName += "_all.bin";
	strDstName += ".bin";
	
	if (CFile::GetStatus(strDstName, status))
	{
		CFile::Remove(strDstName);
	}
	strCall.MakeLower();

	// built page0 .bin
	if (strCall == "none")
	{
		_MergeFile (strCurDir, strSrcName, strDstName, strVer, strCall, strRes, strOem, strVersion);
		return;
	}

	// built upgrade .bin
	if (!_MergeFile (strCurDir, strSrcName, strDstName, strVer, strCall, strRes, strOem, strVersion))
	{
		return;
	}

	// built _all.bin
	if (!out.Open(strAllName, CFile::modeCreate|CFile::modeWrite))
	{
		return;
	}

	// built page0 name
	strPage0Name = strCurDir + strVer + "_" + "none" + "_" + strRes + "_";
	if (strOem != "Unknown")
	{
		strPage0Name += strOem + "_";
	}
	strPage0Name += strVersion;
	strPage0Name += ".bin";
	if (!in.Open(strPage0Name, CFile::modeRead))
	{
		goto Error;
	}
	iLength = (int)in.GetLength();
	p = (char *)malloc(iLength);
	in.Read(p, iLength);
	in.Close();
	out.Write(p, iLength);
	free(p);

	// write settings_sip.dat or settings_iax2.dat
	strSettingsFile = strCurDir + "\\settings\\" + strVer + "_" + strCall + "_" + strRes;
	if (strOem != "Unknown")
	{
		strSettingsFile +=  "_" + strOem + ".txt";
	}
	else
		strSettingsFile += ".txt";

	if (!CFile::GetStatus(strSettingsFile, status))
	{	// use default settings if speical .txt not found
		strSettingsFile = strCurDir + "\\settings\\" + "default" + "_" + strCall + ".txt";
	}

	strCmdLine.Format("..\\bin\\convert -c -f %s settings.dat", strSettingsFile);
	system(strCmdLine);

	strSettingName = strCurDir + "settings.dat";
	if (!in.Open(strSettingName, CFile::modeRead))
	{
		printf("Unable to open %s\n" ,strSettingName);
		goto Error;
	}
	iLength = (int)in.GetLength();
	p = (char *)malloc(iLength);
	in.Read(p, iLength);
	in.Close();

	// store settings contents
	_SetFlag((char *)(p + OPT_FLAG_PRODUCT), strVer, MAX_FLAG_PRODUCT_LEN);
	_SetFlag((char *)(p + OPT_FLAG_PROTOCOL), strCall, MAX_FLAG_PROTOCOL);
	_SetFlag((char *)(p + OPT_FLAG_COUNTRY), strRes, MAX_FLAG_COUNTRY);
	if (strOem != "Unknown")
	{
		_SetFlag((char *)(p + OPT_FLAG_OEM), strOem, MAX_FLAG_OEM_LEN);
	}
	else
	{
		memset((char *)(p + OPT_FLAG_OEM), 0, MAX_FLAG_OEM_LEN);
	}
	_SetFlag((char *)(p + OPT_FLAG_VERSION), strVersion, MAX_FLAG_VERSION);
	out.Write(p, iLength);
	free(p);

	// write default settings
	strSettingsFile = strCurDir + "\\settings\\" + "default" + "_" + strCall + ".txt";
	strCmdLine.Format("..\\bin\\convert -c -f %s settings.dat", strSettingsFile);
	system(strCmdLine);
	strSettingName = strCurDir + "settings.dat";
	if (!in.Open(strSettingName, CFile::modeRead))
	{
		printf("Unable to open %s\n", strSettingName);
		goto Error;
	}
	iLength = (int)in.GetLength();
	p = (char *)malloc(iLength);
	in.Read(p, iLength);
	in.Close();

	// store settings contents
	_SetFlag((char *)(p + OPT_FLAG_PRODUCT), strVer, MAX_FLAG_PRODUCT_LEN);
	_SetFlag((char *)(p + OPT_FLAG_PROTOCOL), strCall, MAX_FLAG_PROTOCOL);
	_SetFlag((char *)(p + OPT_FLAG_COUNTRY), strRes, MAX_FLAG_COUNTRY);
	if (strOem != "Unknown")
	{
		_SetFlag((char *)(p + OPT_FLAG_OEM), strOem, MAX_FLAG_OEM_LEN);
	}
	else
	{
		memset((char *)(p + OPT_FLAG_OEM), 0, MAX_FLAG_OEM_LEN);
	}
	_SetFlag((char *)(p + OPT_FLAG_VERSION), strVersion, MAX_FLAG_VERSION);
	out.Write(p, iLength);
	free(p);

	// Write phonebook.dat
	strPhonebookName = strCurDir + "\\res\\" + "phonebook.dat";
	if (!_WriteFile(out, strPhonebookName, PHONEBOOK_FILE_SIZE))
	{
		goto Error;
	}

	// write ringtone.dat
	strRingtoneName = strCurDir + "\\res\\" + "ringtone.dat";
	if (!_WriteFile(out, strRingtoneName, SYSTEM_RINGTONE_PAGE_NUM * FILE_FULL_PAGE_SIZE))
	{
		goto Error;
	}

	// write ringtone_hold.dat
	strHoldmusicName = strCurDir + "\\res\\" + "holdmusic.dat";
	if (!_WriteFile(out, strHoldmusicName, SYSTEM_HOLDMUSIC_PAGE_NUM * FILE_FULL_PAGE_SIZE))
	{
		goto Error;
	}

	// write font.dat or ivr_xx.dat
	if (strOem == "ivr" || strVer == "ar168l" || strVer == "ar168ls" || strVer == "ar168n")
	{
		strFontName = strCurDir + "\\res\\" + "ivr_" + strRes + ".dat";
	}
	else
	{
		strFontName = strCurDir + "\\res\\" + "font.dat";
	}
	if (!_WriteFile(out, strFontName, SYSTEM_FONT_PAGE_NUM * FILE_FULL_PAGE_SIZE))
	{
		goto Error;
	}

	// write upgrade .bin
	if (!_WriteFile(out, strDstName, SYSTEM_PROGRAM_PAGE_NUM * FILE_FULL_PAGE_SIZE))
	{
		goto Error;
	}

	out.Close();
	return;

Error:
	out.Close();
	CFile::Remove(strAllName);
}

