// CCSharpBaseGenerator.cpp
//

#include "stdafx.h"
#include "CSharpBaseGenerator.h"
#include "XmlClassInfo.h"
#include "XmlProjectSettings.h"
#include "XmlBaseFormItem.h"
#include "XmlBaseElement.h"
#include "XmlProject.h"


map<cmString, cmString> CCSharpBaseGenerator::generatedFiles_;

CCSharpBaseGenerator::CCSharpBaseGenerator():
	classInfo_(NULL),
	projectSettings_(NULL),
	cSharpSettings_(NULL),
	rootClassInfo_(NULL),
	project_(NULL)
{}

CCSharpBaseGenerator::~CCSharpBaseGenerator()
{}


bool CCSharpBaseGenerator::SaveFile(const cmString& fileName, const cmString& fileContent, bool saveIfDifferent)
{
	USES_CONVERSION;

	CFile file;
	BOOL ret;
	CFileException err;
	int fileSize;
	string tmp;

	tmp = W2A((const TCHAR*)fileContent);

	//if (saveIfDifferent && ExistingFileHasSameContent(fileName, fileContent))
	//	return true;
	
	ret = file.Open(fileName, CFile::modeCreate | CFile::modeWrite, &err);
	if (!ret)
		return false;

	fileSize = tmp.size();
	
	file.Write(tmp.c_str(), fileSize);
	
	file.Close();

	return true;
}

/*******************************************************
cmString CCSharpBaseGenerator::DefineOf(const cmString& className)
{
	cmString define;

	define = _T("_") + ToUpperCase(className) + _T("_H_");

	return define;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::TypeOf(enDataType dataType)
{
	cmString ret;

	switch (dataType) {
		case enDataType_None:
			ret = _T("void");
			break;

		case enDataType_Long:
			ret = _T("long");
			break;

		case enDataType_Double:
			ret = _T("double");
			break;

		case enDataType_String:
			ret = _T("cmString");
			break;

		case enDataType_Date:
			ret = _T("void");
			break;

		case enDataType_Class:
			ret = _T("");
			break;

		case enDataType_Boolean:
			ret = _T("bool");
			break;
	}

	return ret;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetClassName(const cmString& elementName)
{
	cmString classPrefix;

	classPrefix = cppSettings_->GetClassPrefix();

	if (elementName.GetLength())
		return classPrefix + elementName;

	return classPrefix + classInfo_->GetName();
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetCardinalityPostfix(CXmlBaseElement* element)
{
	cmString postfix;

	if (element->GetDataType() == enDataType_Class) {
		CXmlClassInfo* memberClass;
		
		memberClass = dynamic_cast<CXmlClassInfo*>(element);
		
		switch (memberClass->GetCardinalityInfo()->GetCardinality()) {
			case enCardinality_SingleInstance:
				postfix = _T("");
				break;

			case enCardinality_Array:
				postfix = _T("Array");
				break;

			case enCardinality_Map:
				postfix = _T("Map");
				break;
		}
	}

	return postfix;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::ToLowCase(const cmString& s)
{
	cmString ret(s);

	ret.MakeLower();
	
	return ret;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::ToUpperCase(const cmString& s)
{
	cmString ret(s);

	ret.MakeUpper();
	
	return ret;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetCamelCase(const cmString& s)
{
	cmString ret(s);
	cmString ch;

	ch = ret.Mid(0, 1);
	ch.MakeLower();

	ret.SetAt(0, ch[0]);
	
	return ret;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetGenerationTimeStamp()
{
	SYSTEMTIME t;
	cmString buf;

	::GetLocalTime(&t);

	buf.Format(_T("// generated on %04d.%02d.%02d at %02d:%02d:%02d.%03d\r\n//\r\n"),
				t.wYear, 
				t.wMonth, 
				t.wDay, 
				t.wHour, 
				t.wMinute, 
				t.wSecond, 
				t.wMilliseconds);

	return buf;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetControlId(CXmlBaseFormItem* formItem, CXmlClassInfo* classInfo)
{
	cmString controlId;

	controlId += _T("IDC_");
	controlId += ToUpperCase(cppSettings_->GetClassPrefix());
	controlId += _T("_");
	controlId += ToUpperCase(classInfo->GetName());
	controlId += _T("_");
	controlId += ToUpperCase(formItem->GetName());

	return controlId;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetDialogId(CXmlClassInfo* classInfo, int count)
{
	cmString dialogId;
	wchar_t buf[20];

	wsprintf(buf, _T("%04d"), count);
	dialogId += _T("IDD_");
	dialogId += ToUpperCase(cppSettings_->GetClassPrefix());
	dialogId += _T("_");
	dialogId += ToUpperCase(buf);
	
	return dialogId ;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetResourceFileName()
{
	cmString ret;

	ret = cppSettings_->GetClassPrefix() + _T("Resource");

	return ret;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetDlgName(CXmlClassInfo* classInfo)
{
	cmString className;

	if (classInfo)
		className = classInfo->GetName();
	else
		className = classInfo_->GetName();

	return cppSettings_->GetClassPrefix() + className + _T("Dlg");
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetArrayDialogName(CXmlClassInfo* classInfo)
{
	cmString className;

	if (classInfo)
		className = classInfo->GetName();
	else
		className = classInfo_->GetName();

	return cppSettings_->GetClassPrefix() + className + _T("ArrayDlg");
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetMapDialogName(CXmlClassInfo* classInfo)
{
	cmString className;

	if (classInfo)
		className = classInfo->GetName();
	else
		className = classInfo_->GetName();

	return cppSettings_->GetClassPrefix() + className + _T("MapDlg");
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetTreeControlID()
{
	cmString treeControlId;

	treeControlId = _T("IDC_GLOBAL_") + ToUpperCase(cppSettings_->GetClassPrefix()) + _T("DOC_TREE");

	return treeControlId;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::BuildGeneratedSourcePath()
{
	cmString ret;

	ret =  cppSettings_->GetGenerationPath();
	ret += _T("\\");
	ret += cppSettings_->GetClassPrefix() + _T("\\");

	return ret;
}
*******************************************************/

/*******************************************************
void CCSharpBaseGenerator::SetProject(CXmlProject* project)
{
	project_ = project;
	projectSettings_ = project->GetProjectSettings();
	cppSettings_ = projectSettings_->GetCppSettings();
	rootClassInfo_ = project->GetRootElement();
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::EscapeString(const cmString& str)
{
	cmString ret;

	for (int i = 0; i < str.GetLength(); i++) {
		if (str[i] == '\n')
			ret += _T("\\n");
		else if (str[i] == '\r')
			ret += _T("\\n");
		else if (str[i] == '\\')
			ret += _T("\\");
		else if (str[i] == '\"')
			ret += _T("\\\"");
		else if (str[i] == '\'')
			ret += _T("\\\'");
		else
			ret += str[i];
	}
	
	return ret;
}
*******************************************************/

/*******************************************************
bool CCSharpBaseGenerator::ExistingFileHasSameContent(const cmString& fileName, const cmString& fileContent)
{
	USES_CONVERSION;

	CFile file;
	CFileException err;
	cmString code1;
	cmString code2;
	string ansiFileContent;
	char* buf;
	UINT bytesRead;
	BOOL ret;
	int	len1;
	int len2;
	bool sameContent;

	ret = file.Open(fileName, CFile::modeRead, &err);
	if (!ret)
		return false;
#ifdef _UNICODE
	ansiFileContent = W2A((const TCHAR*)fileContent);
#else
	ansiFileContent = (const char*)fileContent;
#endif

	len1 = ansiFileContent.length();
	len2 = file.GetLength();
	buf = new char[len2 + 1];
	
	bytesRead = file.Read(buf, len2);
	buf[len2] = '\0';
	code1 = GetCodeFromFileContent(ansiFileContent);
	code2 = GetCodeFromFileContent(buf);

	len1 = code1.GetLength();
	len2 = code2.GetLength();

	file.Close();

	delete [] buf;

	sameContent = (code1 == code2);
	
	return sameContent;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetCodeFromFileContent(const string& fileContent)
{
	USES_CONVERSION;

	cmString ret;
	int pos;
	int len;

	len = fileContent.length();

	pos = fileContent.find("// generated on");
	if (pos == string::npos)
		return _T("");

	pos = fileContent.find("\r\n", pos);
	if (pos == string::npos)
		return _T("");

#ifdef _UNICODE
	ret = A2W(fileContent.substr(pos + strlen("\r\n")).c_str());
#else
	ret = fileContent.substr(pos + strlen("\r\n"));
#endif

	return ret;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetMainDlgName()
{
	return cppSettings_->GetClassPrefix() + _T("CfgManagerDlg");
}
*******************************************************/

/*******************************************************
void CCSharpBaseGenerator::SetClassInfo(CXmlClassInfo* classInfo, vector<CXmlClassInfo*> parentStack)
{
	classInfo_ = classInfo;
	parentStack_ = parentStack;
}
*******************************************************/

/*******************************************************
cmString CCSharpBaseGenerator::GetParentPath(CXmlClassInfo* classInfo, vector<CXmlClassInfo*> parentStack, bool addContainers)
{
	cmString parentPath;

	for (int i = 0; i < parentStack.size(); i++) {
		parentPath += _T("_");
		if (parentStack[i]->GetCardinalityInfo()->GetCardinality() != enCardinality_SingleInstance && addContainers)
			parentPath += parentStack[i]->GetName() + GetCardinalityPostfix(parentStack[i]) + _T("_");
		
		parentPath += parentStack[i]->GetName();
	}

	if (classInfo)
		parentPath += _T("_") + classInfo->GetName();

	return parentPath;
}
*******************************************************/