// CAtlComObjectGenerator.cpp
//
#include "stdafx.h"
#include "AtlComObjectGenerator.h"
#include "XmlProjectSettings.h"
#include "XmlClassInfo.h"
#include "XmlMemberInfo.h"
#include "XmlProject.h"

CAtlComObjectGenerator::CAtlComObjectGenerator()
{}

CAtlComObjectGenerator::~CAtlComObjectGenerator()
{}

void CAtlComObjectGenerator::Generate()
{
	// generate header file
	//
	GenerateHeader();
	
	// generate implementation file
	//
	GenerateImplementation();
}
	
void CAtlComObjectGenerator::GenerateHeader()
{
	cmString fileName;
	cmString pathName;
	
	Head_generateHeader();
	Head_generateIfDefBegin();
	Head_generateIncludeSection();
	Head_generateForwardDecl();
	Head_generateClassBegin();
	Head_generateConstructor();
	Head_generateDestructor();
	Head_generateUtils();
	Head_generateSerialization();
	Head_generateGetSet();
	Head_generateMembers();
	Head_generateClassEnd();
	Head_generateIfDefEnd();

	pathName = BuildGeneratedSourcePath() + _T("include\\");
	fileName = GetComClassName(classInfo_) +  _T(".h");
	SaveFile(pathName + fileName, headCode_);

	hGeneratedFiles_[fileName] = pathName + fileName;
}

void CAtlComObjectGenerator::Head_generateHeader()
{
	headCode_ += _T("// ") + GetComClassName(classInfo_) + _T(".h") + xCrLf;
	headCode_ += _T("// ") + xCrLf; 
	headCode_ += GetGenerationTimeStamp();
}

void CAtlComObjectGenerator::Head_generateIfDefBegin()
{
	headCode_ += _T("#if !defined(") + DefineOf(GetComClassName(classInfo_)) + _T(")") + xCrLf;
	headCode_ += _T("#define ") + DefineOf(GetComClassName(classInfo_)) + xCrLf + xCrLf;
}

void CAtlComObjectGenerator::Head_generateIncludeSection()
{
	headCode_ += _T("#include <string>") + xCrLf;
	//headCode_ += "#include \"XmlSerializable.h\"" + xCrLf;
	//headCode_ += "#include \"" + GetClassName(classInfo_->GetName()) + ".h\"" + xCrLf;
	headCode_ += _T("#include \"resource.h\"       // main symbols") + xCrLf;
	
	// include children header files
	//
	ClassMemberMap::iterator it;
	ClassMemberMap* members;
	CXmlBaseElement* member;
	CXmlClassInfo* classInfo;

	members = classInfo_->GetMembers();
	for(it = members->begin(); it != members->end(); it++) {
		member = it->second;
	
		if (member->GetDataType() == enDataType_Class) {
			cmString name;
			cmString p;

			classInfo = dynamic_cast<CXmlClassInfo*>(member);
			if (!classInfo->GetDefinitionInheritance()) {
				name = member->GetName();
				p = GetCardinalityPostfix(member);
			} else {
				CXmlClassInfo* inheritClassInfo;

				inheritClassInfo = dynamic_cast<CXmlClassInfo*>(rootClassInfo_->GetMemberById(classInfo->GetInherithClassId()));
				name = inheritClassInfo->GetName();
				p = GetCardinalityPostfix(inheritClassInfo);
				classInfo = inheritClassInfo;
			}

			headCode_ += _T("#include \"") + GetComClassName(classInfo) + p + _T(".h\"");
			headCode_ += xCrLf;
		}
	}

	headCode_ += xCrLf;
	headCode_ += _T("using namespace std;") + xCrLf;
	headCode_ += xCrLf;
}

void CAtlComObjectGenerator::Head_generateForwardDecl()
{
	ClassMemberMap::iterator it;
	ClassMemberMap* members;
	CXmlBaseElement* member;

	members = classInfo_->GetMembers();
	for(it = members->begin(); it != members->end(); it++) {
		member = it->second;
	
		if (member->GetDataType() == enDataType_Class) {
			CXmlClassInfo* classInfo;
			CXmlClassInfo* inheritClassInfo;
			cmString name;

			classInfo = dynamic_cast<CXmlClassInfo*>(member);
			if (classInfo->GetDefinitionInheritance()) {
				inheritClassInfo = dynamic_cast<CXmlClassInfo*>(rootClassInfo_->GetMemberById(classInfo->GetInherithClassId()));
				name = inheritClassInfo->GetName();
			} else {
				name = classInfo->GetName();
			}
			headCode_ += _T("class I") + GetClassName(name) + _T(";") + xCrLf;
		}
	}

	headCode_ += xCrLf;
}

void CAtlComObjectGenerator::Head_generateClassBegin()
{
	cmString prefix;
	cmString comName;
	cmString name;

	prefix = project_->GetProjectSettings()->GetAtlSettings()->GetClassPrefix();
	comName = GetComClassName(classInfo_);
	name = GetClassName();

	headCode_ += _T("/////////////////////////////////////////////////////////////////////////////") + xCrLf;
	headCode_ += _T("// ") + comName + xCrLf;
	headCode_ += _T("class ATL_NO_VTABLE ") + comName + _T(":") + xCrLf; 
	headCode_ += _T("public CComObjectRootEx<CComSingleThreadModel>,") + xCrLf;
	headCode_ += _T("public CComCoClass<") + comName + _T(", &CLSID_") + comName + _T(">,") + xCrLf;
	headCode_ += _T("public IDispatchImpl<I") + name + _T(", &IID_I") + name + _T(", &LIBID_") + ToUpperCase(prefix) + _T("Lib>") + xCrLf;
	headCode_ += _T("{") + xCrLf;

}

void CAtlComObjectGenerator::Head_generateConstructor()
{
	cmString comName;
	
	comName = GetComClassName(classInfo_);

	headCode_ += _T("public:") + xCrLf;
	headCode_ += xTab + comName + _T("();") + xCrLf;
}

void CAtlComObjectGenerator::Head_generateDestructor()
{
	headCode_ += xTab + _T("virtual ~") + GetComClassName(classInfo_) + _T("();") + xCrLf + xCrLf;
}

void CAtlComObjectGenerator::Head_generateUtils()
{
	/*
	headCode_ += xTab + "// utils" + xCrLf;
	headCode_ += xTab + "//" + xCrLf;
	headCode_ += "public:" + xCrLf;
	headCode_ += xTab + "void operator=(const " + GetClassName() + "& copy);" + xCrLf + xCrLf;
	headCode_ += xTab + "void SetDefaults();"  + xCrLf;
	headCode_ += xTab + "void Clear();"  + xCrLf;
	headCode_ += xTab + "virtual string GetXmlNodeName(){return \"" + classInfo_->GetName() + "\";}" + xCrLf;
	headCode_ += xCrLf;
	headCode_ += "protected:" + xCrLf;
	headCode_ += xTab + "void Copy(const " + GetClassName() + "& copy);"  + xCrLf;
	headCode_ += xCrLf;
	*/

	headCode_ += xTab + _T("DECLARE_REGISTRY_RESOURCEID(IDR_") + ToUpperCase(GetClassName()) + _T(")") + xCrLf;
	headCode_ += xTab + _T("DECLARE_NOT_AGGREGATABLE(") + GetComClassName(classInfo_) + _T(")") + xCrLf;
	headCode_ += xCrLf;
	headCode_ += xTab + _T("DECLARE_PROTECT_FINAL_CONSTRUCT()") + xCrLf;
	headCode_ += xCrLf;
	headCode_ += xTab + _T("BEGIN_COM_MAP(") + GetComClassName(classInfo_) + _T(")") + xCrLf;
	headCode_ += xTab + xTab + _T("COM_INTERFACE_ENTRY(I") + GetClassName() + _T(")") + xCrLf;
	headCode_ += xTab + xTab + _T("COM_INTERFACE_ENTRY(IDispatch)") + xCrLf;
	headCode_ += xTab + _T("END_COM_MAP()") + xCrLf;
	headCode_ += xCrLf;
}

void CAtlComObjectGenerator::Head_generateGetSet()
{
	ClassMemberMap::iterator it;
	ClassMemberMap* members;
	CXmlBaseElement* member;
	cmString p;
	cmString type;
	
	headCode_ += xTab + _T("// I") + GetClassName() + xCrLf;
	headCode_ += xTab + _T("public:") + xCrLf;

	members = classInfo_->GetMembers();
	for(it = members->begin(); it != members->end(); it++) {
		member = it->second;
			
		if (member->GetDataType() == enDataType_Class) {
			CXmlClassInfo* classInfo;
			CXmlClassInfo* inheritClassInfo;
			cmString name;

			classInfo = dynamic_cast<CXmlClassInfo*>(member);
			if (classInfo->GetDefinitionInheritance()) {
				inheritClassInfo = dynamic_cast<CXmlClassInfo*>(rootClassInfo_->GetMemberById(classInfo->GetInherithClassId()));
				name = inheritClassInfo->GetName();
				p = GetCardinalityPostfix(inheritClassInfo);
				classInfo = inheritClassInfo;
			} else {
				name = classInfo->GetName();
				p = GetCardinalityPostfix(classInfo);
			}
			
			type = _T("I") + GetClassName(name) + p + _T("*");
			
		} else {

			type = OleTypeOf(member->GetDataType());
			
		}

		headCode_ += xTab + _T("STDMETHOD(get_") + member->GetName() + _T(")(/*[out, retval]*/ ") + type + _T("* pVal);") + xCrLf;
		headCode_ += xTab + _T("STDMETHOD(put_") + member->GetName() + _T(")(/*[in]*/ ") + type + _T(" newVal);") + xCrLf;
		headCode_ += xCrLf;
	}
}

void CAtlComObjectGenerator::Head_generateSerialization()
{
	headCode_ += xTab + _T("// serialization") + xCrLf;
	headCode_ += xTab + _T("//") + xCrLf;
	headCode_ += xTab + _T("public:") + xCrLf;
	headCode_ += xTab + _T("virtual bool BuildFromXml(CXMLDOMNode& node);") + xCrLf;
	headCode_ += xTab + _T("virtual bool AppendToDOMDocument(CXMLDOMDocument2& xmlDoc, CXMLDOMElement& parentElement, bool parentIsValid = true);") + xCrLf;
	headCode_ += xCrLf;
}

void CAtlComObjectGenerator::Head_generateMembers()
{
	ClassMemberMap::iterator it;
	ClassMemberMap* members;
	CXmlBaseElement* member;
	
	headCode_ += xTab + _T("// inner members") + xCrLf;
	headCode_ += xTab + _T("//") + xCrLf;
	headCode_ += _T("protected:") + xCrLf;

	members = classInfo_->GetMembers();
	for(it = members->begin(); it != members->end(); it++) {
		member = it->second;
	
		if (member->GetDataType() == enDataType_Class) {
			CXmlClassInfo* classInfo;
			cmString p;
			cmString name;

			classInfo = dynamic_cast<CXmlClassInfo*>(member);
			if (classInfo->GetDefinitionInheritance()) {
				CXmlClassInfo* inheritClassInfo;

				inheritClassInfo = dynamic_cast<CXmlClassInfo*>(rootClassInfo_->GetMemberById(classInfo->GetInherithClassId()));
				name = inheritClassInfo->GetName();
				p = GetCardinalityPostfix(inheritClassInfo);

				classInfo = inheritClassInfo;
			} else {
				name = classInfo->GetName();
				p = GetCardinalityPostfix(member);
			}

			headCode_ += xTab + GetComClassName(classInfo) + p + _T(" ");
			headCode_ += GetCamelCase(name) + p + _T("_;") + xCrLf;
		} else {
			cmString type;

			type = TypeOf(member->GetDataType());

			headCode_ += xTab + type + _T(" ") + GetCamelCase(member->GetName()) + _T("_;") + xCrLf;
		}
	}
}

void CAtlComObjectGenerator::Head_generateClassEnd()
{
	headCode_ += xCrLf;
	headCode_ += _T("};") + xCrLf + xCrLf;
}

void CAtlComObjectGenerator::Head_generateIfDefEnd()
{
	headCode_ += _T("#endif //!defined(") + DefineOf(GetComClassName(classInfo_)) + _T(")") + xCrLf + xCrLf;
}

void CAtlComObjectGenerator::GenerateImplementation()
{
	cmString fileName;
	cmString pathName;
	
	Impl_generateHeader();
	Impl_generateIncludeSection();
	
	Impl_generateConstructor();
	Impl_generateDestructor();
	Impl_generateUtils();
	Impl_generateGetSet();
	Impl_generateSerialization();

	pathName = BuildGeneratedSourcePath() + _T("src\\");
	fileName = GetComClassName(classInfo_) +  _T(".cpp");
	SaveFile(pathName + fileName, implCode_);

	cppGeneratedFiles_[fileName] = pathName + fileName;
}

void CAtlComObjectGenerator::Impl_generateHeader()
{
	implCode_ += _T("// ") + GetComClassName(classInfo_) + _T(".cpp : implementation of ") + GetComClassName(classInfo_) + xCrLf;
	implCode_ += _T("// ") + xCrLf; 
	implCode_ += GetGenerationTimeStamp();
	implCode_ += _T("#include \"ProjectConfigAtl.h\"") + xCrLf;
	implCode_ += xCrLf;
}

void CAtlComObjectGenerator::Impl_generateIncludeSection()
{
	implCode_ += _T("#include \"stdafx.h\"") + xCrLf;
	implCode_ += _T("#include \"") + GetClassName() + _T(".h\"") + xCrLf;

	ClassMemberMap::iterator it;
	ClassMemberMap* members;
	CXmlBaseElement* member;

	members = classInfo_->GetMembers();
	for(it = members->begin(); it != members->end(); it++) {
		member = it->second;
		if (member->GetDataType() == enDataType_Class) {
			CXmlClassInfo* classInfo;

			classInfo = dynamic_cast<CXmlClassInfo*>(member);
			if (!classInfo->GetDefinitionInheritance())
				implCode_ += _T("#include \"") + GetClassName(classInfo->GetName()) + _T(".h\"") + xCrLf;
		}
	}

	implCode_ +=  xCrLf;
}

void CAtlComObjectGenerator::Impl_generateConstructor()
{
	// default constructor
	//
	implCode_ += GetClassName() + _T("::") + GetClassName() + _T("()") + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("SetDefaults();") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

	// copy constructor
	//
	implCode_ += GetClassName() + _T("::") + GetClassName() + _T("(const ") + GetClassName() + _T("& ") + GetCamelCase(classInfo_->GetName()) + _T(")") + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("Copy(") + GetCamelCase(classInfo_->GetName()) + _T(");") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;
}

void CAtlComObjectGenerator::Impl_generateDestructor()
{
	implCode_ += GetClassName() + _T("::~") + GetClassName() + _T("()") + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("Clear();") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;
}

void CAtlComObjectGenerator::Impl_generateUtils()
{
	ClassMemberMap::iterator it;
	ClassMemberMap* members;
	CXmlBaseElement* member;
	CXmlClassInfo* classInfo;
	cmString p;
	cmString name;

	// operator =
	//
	implCode_ += _T("void ") +  GetClassName() + _T("::operator=(const ") + GetClassName() + _T("& ") + GetCamelCase(classInfo_->GetName()) + _T(")") + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("Copy(") + GetCamelCase(classInfo_->GetName()) + _T(");") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

	// copy
	//
	implCode_ += _T("void ") + GetClassName() + _T("::Copy(const ") + GetClassName() + _T("& ") + GetCamelCase(classInfo_->GetName()) + _T(")")  + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("Clear();") + xCrLf;
	implCode_ += xCrLf;

	members = classInfo_->GetMembers();
	for(it = members->begin(); it != members->end(); it++) {
		member = it->second;

		if (member->GetDataType() == enDataType_Class) {
			classInfo = dynamic_cast<CXmlClassInfo*>(member);
			if (classInfo->GetDefinitionInheritance()) {
				classInfo = dynamic_cast<CXmlClassInfo*>(rootClassInfo_->GetMemberById(classInfo->GetInherithClassId()));
			}
			p = GetCardinalityPostfix(classInfo);
			name = classInfo->GetName();
			implCode_ += xTab + GetCamelCase(name) + p + _T("_ = ") + GetCamelCase(classInfo_->GetName()) + _T(".") + GetCamelCase(name) + p + _T("_;") + xCrLf;
		} else {
			implCode_ += xTab + GetCamelCase(member->GetName()) + _T("_ = ") + GetCamelCase(classInfo_->GetName()) + _T(".") + GetCamelCase(member->GetName()) + _T("_;") + xCrLf;
		}
	}
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

	// SetDefaults
	//
	implCode_ += _T("void ") + GetClassName() + _T("::SetDefaults()")  + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("Clear();") + xCrLf;
	members = classInfo_->GetMembers();
	for(it = members->begin(); it != members->end(); it++) {
		member = it->second;
	
		switch (member->GetDataType()) {
			case enDataType_Class:
				classInfo = dynamic_cast<CXmlClassInfo*>(member);
				if (classInfo->GetDefinitionInheritance()) {
					classInfo = dynamic_cast<CXmlClassInfo*>(rootClassInfo_->GetMemberById(classInfo->GetInherithClassId()));
				}
				p = GetCardinalityPostfix(classInfo);
				name = classInfo->GetName();
				implCode_ += xTab + GetCamelCase(name) + p + _T("_.SetDefaults();") + xCrLf;
				break;

			case enDataType_Long:
			case enDataType_Double:
				implCode_ += xTab + GetCamelCase(member->GetName()) + _T("_ = 0;") + xCrLf;
				break;

			case enDataType_Boolean:
				implCode_ += xTab + GetCamelCase(member->GetName()) + _T("_ = false;") + xCrLf;
				break;
		}
			
	}
	implCode_ += _T("}") + xCrLf + xCrLf;

	// SetDefaults
	//
	implCode_ += _T("void ") + GetClassName() + _T("::Clear()")  + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += _T("}") + xCrLf + xCrLf;
}

void CAtlComObjectGenerator::Impl_generateGetSet()
{
	ClassMemberMap::iterator it;
	ClassMemberMap* members;
	CXmlBaseElement* member;
	cmString type;
	cmString name;

	members = classInfo_->GetMembers();
	for(it = members->begin(); it != members->end(); it++) {
		member = it->second;
	
		if (member->GetDataType() == enDataType_Class) {
			CXmlClassInfo* classInfo;
			CXmlClassInfo* inheritClassInfo;
			cmString name;
			cmString p;

			classInfo = dynamic_cast<CXmlClassInfo*>(member);
			if (classInfo->GetDefinitionInheritance()) {
				inheritClassInfo = dynamic_cast<CXmlClassInfo*>(rootClassInfo_->GetMemberById(classInfo->GetInherithClassId()));
				name = inheritClassInfo->GetName();
				p = GetCardinalityPostfix(inheritClassInfo);
			} else {
				name = classInfo->GetName();
				p = GetCardinalityPostfix(member);
			}

			type = GetClassName(name) + p;	
			
			implCode_ += _T("STDMETHODIMP ") + GetComClassName(name) + _T("::get_") + type + _T("(I") + type + _T("** pVal)") + xCrLf;
			implCode_ += _T("{") + xCrLf;
			implCode_ += xTab + _T("AFX_MANAGE_STATE(AfxGetStaticModuleState());") + xCrLf;
			implCode_ += xCrLf;
			implCode_ += xTab + _T("return S_OK;") + xCrLf;
			implCode_ += _T("}") + xCrLf;
			implCode_ += xCrLf;

			implCode_ += _T("STDMETHODIMP ") + GetComClassName(name) + _T("::put_") + type + _T("(I") + type + _T("* newVal)") + xCrLf;
			implCode_ += _T("{") + xCrLf;
			implCode_ += xTab + _T("AFX_MANAGE_STATE(AfxGetStaticModuleState())") + xCrLf;
			implCode_ += xTab + _T("return S_OK;") + xCrLf;
			implCode_ += _T("}") + xCrLf;
			implCode_ += xCrLf;
			
		} else {
			type = OleTypeOf(member->GetDataType());
			name = member->GetName();

			implCode_ += _T("STDMETHODIMP ") + GetComClassName(classInfo_) + _T("::get_") + name + _T("(") + type + _T("* pVal)") + xCrLf;
			implCode_ += _T("{") + xCrLf;
			implCode_ += xTab + _T("AFX_MANAGE_STATE(AfxGetStaticModuleState());") + xCrLf;
			implCode_ += xCrLf;
			implCode_ += xTab + _T("*pVal = ") + GetCamelCase(member->GetName()) + _T("_;") + xCrLf;
			implCode_ += xCrLf;
			implCode_ += xTab + _T("return S_OK;") + xCrLf;
			implCode_ += _T("}") + xCrLf;

			implCode_ += _T("STDMETHODIMP ") + GetComClassName(name) + _T("::put_") + type + _T("(") + type + _T(" newVal)") + xCrLf;
			implCode_ += _T("{") + xCrLf;
			implCode_ += xTab + _T("AFX_MANAGE_STATE(AfxGetStaticModuleState())") + xCrLf;
			implCode_ += xCrLf;
			implCode_ += xTab + GetCamelCase(member->GetName()) + _T("_ = newVal;") + xCrLf;
			implCode_ += xCrLf;
			implCode_ += xTab + _T("return S_OK;") + xCrLf;
			implCode_ += _T("}") + xCrLf;
		}
	}
}

void CAtlComObjectGenerator::Impl_generateSerialization()
{
	ClassMemberMap::iterator it;
	ClassMemberMap* members;
	CXmlBaseElement* member;
	CXmlClassInfo* classInfo;
	bool firstDone;
	TCHAR buf[100];
	cmString p;
	cmString name;

	//////////////////////////////////////////////////////////////////////
	// BuildFromXml
	//
	implCode_ += _T("bool ") + GetClassName() + _T("::BuildFromXml(CXMLDOMNode& node)") + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("USES_CONVERSION;") + xCrLf + xCrLf;

	implCode_ += xTab + _T("CXMLDOMNode childNode;") + xCrLf;
    implCode_ += xTab + _T("CXMLDOMNodeList children;") + xCrLf;
	implCode_ += xTab + _T("string nodeName;") + xCrLf + xCrLf;

	implCode_ += xTab + _T("SetDefaults();") + xCrLf;
	implCode_ += xTab + xCrLf;

	implCode_ += xTab + _T("children = node.GetChildNodes();") + xCrLf;
	
	implCode_ += xTab + _T("for (long i = 0; i < children.GetLength(); i++) {") + xCrLf;
	implCode_ += xTab + xTab + _T("childNode = children.GetItem(i);") + xCrLf;
	
	implCode_ += xTab + xTab + _T("nodeName = childNode.GetNodeName();") + xCrLf;

	members = classInfo_->GetMembers();
	firstDone = false;
	implCode_ += xTab + xTab;
	for(it = members->begin(); it != members->end(); it++) {
		member = it->second;
	
		if (firstDone)
			implCode_ += _T(" else ");
		
		switch (member->GetDataType()) {
			case enDataType_Class:
				classInfo = dynamic_cast<CXmlClassInfo*>(member);
				if (classInfo->GetDefinitionInheritance())
					classInfo = dynamic_cast<CXmlClassInfo*>(rootClassInfo_->GetMemberById(classInfo->GetInherithClassId()));
				
				p = GetCardinalityPostfix(classInfo);
				name = classInfo->GetName();
				implCode_ += _T("if (nodeName == ") + GetCamelCase(name) + p + _T("_.GetXmlNodeName()) {") + xCrLf;
				implCode_ += xTab + xTab + xTab + GetCamelCase(name) + p + _T("_.BuildFromXml(childNode);") + xCrLf;
				break;

			case enDataType_String:
				implCode_ += _T("if (nodeName == \"") + GetCamelCase(member->GetName()) + _T("\") {") + xCrLf;
				implCode_ += xTab + xTab + xTab + GetCamelCase(member->GetName()) + _T("_ = W2T(childNode.GetNodeTypedValue().bstrVal);") + xCrLf;
				break;

			case enDataType_Double:
				implCode_ += _T("if (nodeName == \"") + GetCamelCase(member->GetName()) + _T("\") {") + xCrLf;
				implCode_ += xTab + xTab + xTab + GetCamelCase(member->GetName()) + _T("_ = atof(W2A(childNode.GetNodeTypedValue().bstrVal));") + xCrLf;
				break;

			case enDataType_Long:
				implCode_ += _T("if (nodeName == \"") + GetCamelCase(member->GetName()) + _T("\") {") + xCrLf;
				implCode_ += xTab + xTab + xTab + GetCamelCase(member->GetName()) + _T("_ = atol(W2A(childNode.GetNodeTypedValue().bstrVal));") + xCrLf;
				break;

			case enDataType_Boolean:
				implCode_ += _T("if (nodeName == \"") + GetCamelCase(member->GetName()) + _T("\") {") + xCrLf;
				implCode_ += xTab + xTab + xTab + GetCamelCase(member->GetName()) + _T("_ = (atoi(W2A(childNode.GetNodeTypedValue().bstrVal)) == 1);") + xCrLf;
				break;
		}
		implCode_ += xTab + xTab + _T("}");
		
		firstDone = true;
	}

	implCode_ += xCrLf;
	implCode_ += xTab + _T("}") + xCrLf + xCrLf;

	implCode_ += xTab + _T("return true;") + xCrLf;

	implCode_ += _T("}") + xCrLf + xCrLf;

	//////////////////////////////////////////////////////////////////////
	// AppendToDOMDocument
	//
	implCode_ += _T("bool ") + GetClassName() + _T("::AppendToDOMDocument(CXMLDOMDocument2& xmlDoc, CXMLDOMElement& parentElement, bool parentIsValid)") + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("CXMLDOMElement newElement;") + xCrLf;
    implCode_ += xTab + _T("CXMLDOMElement rectElement;") + xCrLf;
	implCode_ += xTab + _T("CXMLDOMElement member;") + xCrLf + xCrLf;
   
    implCode_ += xTab + _T("newElement = xmlDoc.CreateElement(GetXmlNodeName().c_str());") + xCrLf;
		
	members = classInfo_->GetMembers();
	for(it = members->begin(); it != members->end(); it++) {
		member = it->second;
	
		switch (member->GetDataType()) {
			case enDataType_Class:
				classInfo = dynamic_cast<CXmlClassInfo*>(member);
				if (classInfo->GetDefinitionInheritance())
					classInfo = dynamic_cast<CXmlClassInfo*>(rootClassInfo_->GetMemberById(classInfo->GetInherithClassId()));
				
				p = GetCardinalityPostfix(classInfo);
				name = classInfo->GetName();
				implCode_ += xTab + GetCamelCase(name) + p + _T("_.AppendToDOMDocument(xmlDoc, newElement);") + xCrLf;
				break;

			case enDataType_Double:
				wsprintf(buf,_T("%d"), (dynamic_cast<CXmlMemberInfo*>(member))->GetDecimalPlaces());
				implCode_ += xTab + _T("AppendMemberNode(_T(\"") + member->GetName() + _T("\"), ") + GetCamelCase(member->GetName()) + _T("_, ") + cmString(buf) + _T(", newElement, xmlDoc);") + xCrLf;	
				break;

			default:
				implCode_ += xTab + _T("AppendMemberNode(_T(\"") + member->GetName() + _T("\"), ") + GetCamelCase(member->GetName()) + _T("_, newElement, xmlDoc);") + xCrLf;	
		}	
	}

	implCode_ += xCrLf;
	implCode_ += xTab + _T("if (!parentIsValid)") + xCrLf;
    implCode_ += xTab + xTab + _T("xmlDoc.AppendChild(newElement);") + xCrLf;
	implCode_ += xTab + _T("else") + xCrLf;
    implCode_ += xTab + xTab + _T("parentElement.AppendChild(newElement);") + xCrLf + xCrLf;
	implCode_ += xTab + _T("return true;") + xCrLf;
	implCode_ += _T("}") + xCrLf + xCrLf;

	//////////////////////////////////////////////////////////////////////
	// loadFromFile
	//
	/*
	implCode_ += "bool " + GetClassName() + "::LoadFromFile(const string& fileName)" + xCrLf;
	implCode_ += "{" + xCrLf;


	implCode_ += xTab + "CXMLDOMDocument2 xmlDoc;" + xCrLf;
	implCode_ += xTab + "CXMLDOMNodeList childList;" + xCrLf;
	implCode_ += xTab + "CXMLDOMNode child;" + xCrLf;
	implCode_ += xTab + "BOOL ret;" + xCrLf + xCrLf;
   	
	implCode_ += xTab + "Reset();" + xCrLf + xCrLf;

	implCode_ += xTab + "try" + xCrLf;
	implCode_ += xTab + "{" + xCrLf;
	implCode_ += xTab + xTab + "xmlDoc = CDOMDocument30Class::CreateXMLDOMDocument2();" + xCrLf;
	implCode_ += xTab + "}" + xCrLf;
	implCode_ += xTab + "catch (CComException *pE)" + xCrLf;
	implCode_ += xTab + "{" + xCrLf;
	implCode_ += xTab + xTab + "pE->Delete();" + xCrLf;
	implCode_ += xTab + xTab + "return false;" + xCrLf;
	implCode_ += xTab + "}" + xCrLf + xCrLf;

	implCode_ += xTab + "ret = xmlDoc.Load(_variant_t(fileName.c_str()));" + xCrLf;
	implCode_ += xTab + "if (!ret) {" + xCrLf;
	implCode_ += xTab + xTab + "// TODO: display parser error message" + xCrLf;
	implCode_ += xTab + xTab + "//" + xCrLf;
	implCode_ += xTab + xTab + "return false;" + xCrLf;
	implCode_ += xTab + "}" + xCrLf + xCrLf;
   
	
	implCode_ += xTab + "childList = xmlDoc.GetChildNodes();" + xCrLf;

	implCode_ += xTab + "for (long i = 0; i < childList.GetLength(); i++) {" + xCrLf;
	implCode_ += xTab + xTab + "child = childList.GetItem(i);" + xCrLf;

	implCode_ += xTab + xTab + "if (child.GetNodeName() == \"" + GetCamelCase(classInfo_->GetName()) + "\")" + xCrLf;
	implCode_ += xTab + xTab + xTab + "BuildFromXml(child);" + xCrLf;
	implCode_ += xTab + "}" + xCrLf;

	implCode_ += xTab + "return true;" + xCrLf;
	implCode_ += "}" + xCrLf + xCrLf;
	*/

	//////////////////////////////////////////////////////////////////////
	// saveToFile
	//
	/*
	implCode_ += "bool " + GetClassName() + "::SaveToFile(const string& fileName)" + xCrLf;
	implCode_ += "{" + xCrLf;
	implCode_ += xTab + "CXMLDOMDocument2 xmlDoc;" + xCrLf;
	implCode_ += xTab + "CXMLDOMProcessingInstruction pi;" + xCrLf + xCrLf;

	implCode_ += xTab + "try" + xCrLf;
	implCode_ += xTab + "{" + xCrLf;
	implCode_ += xTab + xTab + "xmlDoc = CDOMDocument30Class::CreateXMLDOMDocument2();" + xCrLf;
	implCode_ += xTab + "}" + xCrLf;
	implCode_ += xTab + "catch (CComException *pE)" + xCrLf;
	implCode_ += xTab + "{" + xCrLf;
	implCode_ += xTab + xTab + "pE->Delete();" + xCrLf;
	implCode_ += xTab + xTab + "return false;" + xCrLf;
	implCode_ += xTab + "}" + xCrLf + xCrLf;

	implCode_ += xTab + "pi = xmlDoc.CreateProcessingInstruction(\"xml\", \" version='1.0' encoding='ISO-8859-1'\");" + xCrLf;
	implCode_ += xTab + "xmlDoc.AppendChild(pi);" + xCrLf + xCrLf;

	implCode_ += xTab + "AppendToDOMDocument(xmlDoc, *(CXMLDOMElement*)NULL, false);" + xCrLf + xCrLf;
	implCode_ += xTab + "xmlDoc.Save(fileName.c_str());" + xCrLf + xCrLf;

	implCode_ += xTab + "return true;" + xCrLf;
	implCode_ += "}" + xCrLf + xCrLf;
	*/
}

cmString CAtlComObjectGenerator::GetComClassName(CXmlClassInfo* classInfo)
{
	cmString name;

	if (classInfo->GetDefinitionInheritance()) {
		CXmlClassInfo* inheritClassInfo;

		inheritClassInfo = dynamic_cast<CXmlClassInfo*>(rootClassInfo_->GetMemberById(classInfo->GetInherithClassId()));
		name = inheritClassInfo->GetName();
	} else {
		name = classInfo->GetName();
	}

	return GetComClassName(GetClassName(name));
}

cmString CAtlComObjectGenerator::GetComClassName(const cmString& className)
{
	return _T("CCom") + className;
}