// CAtlClassMapGenerator.cpp
//
#include "stdafx.h"
#include "AtlClassMapGenerator.h"
#include "XmlProjectSettings.h"
#include "XmlClassInfo.h"
#include "XmlMemberInfo.h"
#include "XmlProject.h"

CAtlClassMapGenerator::CAtlClassMapGenerator()
{}

CAtlClassMapGenerator::~CAtlClassMapGenerator()
{}


void CAtlClassMapGenerator::Generate()
{
	// generate header file
	//
	GenerateHeader();
	
	// generate implementation file
	//
	GenerateImplementation();
}
	
void CAtlClassMapGenerator::GenerateHeader()
{
	cmString fileName;
	cmString pathName;

	Head_generateHeader();
	Head_generateIfDefBegin();
	Head_generateIncludeSection();
	Head_generateForwardDecl();
	Head_generateClassBegin();
	Head_generateConstructor();
	Head_generateDestructor();
	Head_generateMethods();
	Head_generateSerialization();
	Head_generateMembers();
	Head_generateClassEnd();
	Head_generateIfDefEnd();

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

	hGeneratedFiles_[fileName] = pathName + fileName;
}

void CAtlClassMapGenerator::Head_generateHeader()
{
	headCode_ += _T("// ") + GetClassName() + GetCardinalityPostfix(classInfo_) + _T(".h") + xCrLf;
	headCode_ += _T("// ") + xCrLf; 
	headCode_ += GetGenerationTimeStamp();
}

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

void CAtlClassMapGenerator::Head_generateIncludeSection()
{
	headCode_ += _T("#include <string>") + xCrLf;
	headCode_ += _T("#include <map>") + xCrLf;
	headCode_ += _T("#include \"XmlSerializable.h\"") + xCrLf;
	headCode_ += _T("#include \"ProjectConfigAtl.h\"") + xCrLf;

	// include contained class header
	//
	headCode_ += _T("#include \"") + GetClassName(classInfo_->GetName()) + _T(".h\"") + xCrLf;
	headCode_ += xCrLf;

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

void CAtlClassMapGenerator::Head_generateForwardDecl()
{
}

void CAtlClassMapGenerator::Head_generateClassBegin()
{
	//headCode_ += "class " + GetClassName() + GetCardinalityPostfix(classInfo_) + ": public CXmlSerializable" + xCrLf;
	//headCode_ += "{" + xCrLf;

	cmString prefix;
	cmString name;
	cmString p;

	p =  GetCardinalityPostfix(classInfo_);
	prefix = project_->GetProjectSettings()->GetAtlSettings()->GetClassPrefix();
	name = GetClassName() + p;
	
	headCode_ += _T("/////////////////////////////////////////////////////////////////////////////") + xCrLf;
	headCode_ += _T("// ") + name + xCrLf;
	headCode_ += _T("class ATL_NO_VTABLE ") + name + _T(":") + xCrLf; 
	headCode_ += _T("public CComObjectRootEx<CComSingleThreadModel>,") + xCrLf;
	headCode_ += _T("public CComCoClass<") + name + _T(", &CLSID_") + classInfo_->GetName() + p + _T(">,") + xCrLf;
	headCode_ += _T("public IDispatchImpl<I") + name + _T(", &IID_I") + name + _T(", &LIBID_") + ToUpperCase(prefix) + _T("Lib>,") + xCrLf;
	headCode_ += _T("public CXmlSerializable") + xCrLf;
	headCode_ += _T("{") + xCrLf;
	headCode_ += xCrLf;
	headCode_ += _T("public:") + xCrLf;
	headCode_ += xTab + _T("DECLARE_REGISTRY_RESOURCEID(IDR_") + ToUpperCase(classInfo_->GetName() + p) + _T(")") + xCrLf;
	headCode_ += xTab + _T("DECLARE_NOT_AGGREGATABLE(") + name + _T(")") + xCrLf;
	headCode_ += xCrLf;
	headCode_ += xTab + _T("DECLARE_PROTECT_FINAL_CONSTRUCT()") + xCrLf;
	headCode_ += xCrLf;
	headCode_ += xTab + _T("BEGIN_COM_MAP(") + name + _T(")") + xCrLf;
	headCode_ += xTab + xTab + _T("COM_INTERFACE_ENTRY(I") + name + _T(")") + xCrLf;
	headCode_ += xTab + xTab + _T("COM_INTERFACE_ENTRY(IDispatch)") + xCrLf;
	headCode_ += xTab + _T("END_COM_MAP()") + xCrLf;
	headCode_ += xCrLf;
}

void CAtlClassMapGenerator::Head_generateConstructor()
{
	headCode_ += _T("public:") + xCrLf;
	headCode_ += xTab + GetClassName() + GetCardinalityPostfix(classInfo_) + _T("();") + xCrLf;
}

void CAtlClassMapGenerator::Head_generateDestructor()
{
	headCode_ += xTab + _T("virtual ~") + GetClassName() + GetCardinalityPostfix(classInfo_) + _T("();") + xCrLf + xCrLf;
}

void CAtlClassMapGenerator::Head_generateMethods()
{
	CXmlBaseElement* sortKeyMember;
	cmString keyParam;

	sortKeyMember = classInfo_->GetMember(classInfo_->GetCardinalityInfo()->GetMapSortKey());
	if (sortKeyMember == NULL)
		return;

	if (sortKeyMember->GetDataType() == enDataType_String)
		keyParam = _T("const ") + TypeOf(sortKeyMember->GetDataType()) + _T("& key");
	else
		keyParam = TypeOf(sortKeyMember->GetDataType()) + _T(" key");

	headCode_ += xTab + _T("// utils") + xCrLf;
	headCode_ += xTab + _T("//") + xCrLf;
	headCode_ += _T("public:") + xCrLf;
	//headCode_ += xTab + "void operator=(const " + GetClassName() + GetCardinalityPostfix(classInfo_) + "& copy);" + xCrLf + xCrLf;
	headCode_ += xTab + _T("void SetDefaults();")  + xCrLf;
	headCode_ += xTab + _T("void Clear();")  + xCrLf;
	headCode_ += xCrLf;
	headCode_ += xTab + _T("// I") + GetClassName() + GetCardinalityPostfix(classInfo_) + xCrLf;
	headCode_ += xTab + _T("//") + xCrLf;
	headCode_ += _T("public:") + xCrLf;
	headCode_ += xTab + _T("STDMETHOD(MoveFirst)(/*[out, retval]*/ VARIANT_BOOL* retval);") + xCrLf;
	headCode_ += xTab + _T("STDMETHOD(MoveNext)(/*[out, retval]*/ VARIANT_BOOL* retval);")  + xCrLf;
	headCode_ += xTab + _T("STDMETHOD(GetPair)(/*[out]*/") + OleTypeOf(sortKeyMember->GetDataType()) + _T("* key, /*[out]*/ I") + GetClassName() + _T("** ") + GetCamelCase(classInfo_->GetName()) + _T(", /*[out, retval]*/ VARIANT_BOOL* retval);")  + xCrLf;
	headCode_ += xTab + _T("STDMETHOD(FindItem)(/*[in]*/") + OleTypeOf(sortKeyMember->GetDataType()) + _T(" key, /*[out]*/ I") + GetClassName() + _T("** ") + GetCamelCase(classInfo_->GetName()) + _T(");")  + xCrLf;
	headCode_ += xTab + _T("STDMETHOD(Insert)(/*[in]*/ I") + GetClassName() + _T("* ") + GetCamelCase(classInfo_->GetName()) + _T(");") + xCrLf;
	headCode_ += xTab + _T("STDMETHOD(Delete)(/*[in]*/") + OleTypeOf(sortKeyMember->GetDataType()) + _T(" key);") + xCrLf;
	headCode_ += xTab + _T("STDMETHOD(GetSize)(/*[out, retval]*/ long* retval);") + xCrLf;
	headCode_ += xTab + _T("STDMETHOD(CleanUp)();") + xCrLf;
	headCode_ += xTab + _T("STDMETHOD(RestoreDefaults)();") + xCrLf;
	headCode_ += xTab +_T("STDMETHOD(Copy)(/*[in]*/ I") + GetClassName() + GetCardinalityPostfix(classInfo_) + _T("* source);") + xCrLf;
	headCode_ += xTab + _T("STDMETHOD(Load)(/*[in]*/ BSTR fileName, /*[out, retval]*/ VARIANT_BOOL* retval);") + xCrLf;
	headCode_ += xTab + _T("STDMETHOD(Save)(/*[in]*/ BSTR fileName, /*[out, retval]*/ VARIANT_BOOL* retval);") + xCrLf;
	headCode_ += xTab + _T("STDMETHOD(ReplaceKey)(/*[in]*/ BSTR currentKey, /*[in]*/ BSTR newKey);") + xCrLf;
	headCode_ += xCrLf;

	headCode_ += xTab + _T("virtual cmString GetXmlNodeName(){return xmlNodeName_;}") + xCrLf;
	headCode_ += xTab + _T("static cmString xmlNodeName_;") + xCrLf;
		
	
	//headCode_ += xTab + "const " + GetClassName() + "& operator[] (" + keyParam + ") const;" + xCrLf;
	//headCode_ += xTab + GetClassName() + "& operator[] (" + keyParam + ");" + xCrLf;
		
	headCode_ += xCrLf;

	//headCode_ += "protected:" + xCrLf;
	//headCode_ += xTab + "void Copy(I" + GetClassName() + GetCardinalityPostfix(classInfo_) + "* source);"  + xCrLf;
	//headCode_ += xCrLf;
}

void CAtlClassMapGenerator::Head_generateSerialization()
{
	headCode_ += xTab + _T("// serialization") + xCrLf;
	headCode_ += xTab + _T("//") + xCrLf;
	headCode_ += xTab + _T("public:") + xCrLf;
	headCode_ += xTab + _T("virtual bool BuildFromXml(IXMLDOMNode* node);") + xCrLf;
	headCode_ += xTab + _T("virtual bool AppendToDOMDocument(IXMLDOMDocument2* xmlDoc, IXMLDOMElement* parentElement);") + xCrLf;
	headCode_ += xCrLf;
}

void CAtlClassMapGenerator::Head_generateMembers()
{
	CXmlBaseElement* sortKeyMember;
	
	sortKeyMember = classInfo_->GetMember(classInfo_->GetCardinalityInfo()->GetMapSortKey());
	if (sortKeyMember == NULL)
		return;

	headCode_ += xTab + _T("// inner members") + xCrLf;
	headCode_ += xTab + _T("//") + xCrLf;
	headCode_ += _T("protected:") + xCrLf;

	headCode_ += xTab + _T("map<") + TypeOf(sortKeyMember->GetDataType()) + _T(", CComObject<")  + GetClassName() + _T(">* > ") + GetCamelCase(classInfo_->GetName()+ GetCardinalityPostfix(classInfo_))  + _T("_;") + xCrLf;
	headCode_ += xTab + _T("map<") + TypeOf(sortKeyMember->GetDataType()) + _T(", CComObject<")  + GetClassName() + _T(">* >::iterator it_;") + xCrLf;
}

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

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

void CAtlClassMapGenerator::GenerateImplementation()
{
	cmString fileName;
	cmString pathName;

	Impl_generateHeader();
	Impl_generateIncludeSection();
	
	Impl_generateConstructor();
	Impl_generateDestructor();
	Impl_generateMethods();
	Impl_generateSerialization();

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

	cppGeneratedFiles_[fileName] = pathName + fileName;
}

void CAtlClassMapGenerator::Impl_generateHeader()
{
	implCode_ += _T("// ") + GetClassName() + GetCardinalityPostfix(classInfo_) + _T(".cpp") + xCrLf;
	implCode_ += _T("// ") + xCrLf; 
	implCode_ += GetGenerationTimeStamp();
	implCode_ += _T("#pragma warning(disable:4786)") + xCrLf;
	implCode_ += xCrLf;
}

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

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

	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())
				classInfo = dynamic_cast<CXmlClassInfo*>(rootClassInfo_->GetMemberById(classInfo->GetInherithClassId()));

			name = classInfo->GetName();
			implCode_ += _T("#include \"") + GetClassName(name) + _T(".h\"") + xCrLf;
		}
	}

	implCode_ +=  xCrLf;
}

void CAtlClassMapGenerator::Impl_generateConstructor()
{
	cmString p;

	p = GetCardinalityPostfix(classInfo_);

	implCode_ += _T("cmString ") + GetClassName() + p + _T("::xmlNodeName_ = _T(\"") + classInfo_->GetName() + p + _T("\");") + xCrLf;	
	implCode_ += xCrLf;

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

}

void CAtlClassMapGenerator::Impl_generateDestructor()
{
	cmString p;

	p = GetCardinalityPostfix(classInfo_);

	implCode_ += GetClassName() + p + _T("::~") + GetClassName() + p + _T("()") + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("CleanUp();") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;
}

void CAtlClassMapGenerator::Impl_generateMethods()
{
	CXmlBaseElement* sortKeyMember;
	cmString p;
	cmString keyParam;

	sortKeyMember = classInfo_->GetMember(classInfo_->GetCardinalityInfo()->GetMapSortKey());
	if (sortKeyMember == NULL)
		return;

	if (sortKeyMember->GetDataType() == enDataType_String)
		keyParam = _T("const ") + TypeOf(sortKeyMember->GetDataType()) + _T("& key");
	else
		keyParam = TypeOf(sortKeyMember->GetDataType()) + _T(" key");

	p = GetCardinalityPostfix(classInfo_);

	// Copy
	//
	cmString mapName;
	cmString paramName;

	mapName = GetCamelCase(classInfo_->GetName()) + p;
	paramName = GetCamelCase(classInfo_->GetName()) + p;
	implCode_ += _T("STDMETHODIMP ") + GetClassName() + p + _T("::Copy(I") + GetClassName() + p + _T("* source)")  + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("USES_CONVERSION;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("CleanUp();") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("VARIANT_BOOL ret;") + xCrLf;
	if (sortKeyMember->GetDataType() == enDataType_String)
		implCode_ += xTab + _T("CComBSTR key;") + xCrLf;
	else
		implCode_ += xTab + OleTypeOf(sortKeyMember->GetDataType()) + _T(" key;") + xCrLf;
	implCode_ += xTab + _T("I") + GetClassName() + _T("* mapItem;") + xCrLf;
	//implCode_ += xTab + "I" + GetClassName() + "* newItem;" + xCrLf;
	implCode_ += xTab + _T("CComObject<") + GetClassName() + _T(">* tmp;") + xCrLf;
	implCode_ += xTab + _T("HRESULT hRes = 0;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("source->MoveFirst(&ret);") + xCrLf;
	implCode_ += xTab + _T("while (ret == VARIANT_TRUE) {") + xCrLf;
	implCode_ += xTab + xTab + _T("source->GetPair(&key, &mapItem, &ret);") + xCrLf;
	implCode_ += xCrLf;
	//implCode_ += xTab + xTab + "tmp = new CComObject<" + GetClassName() + ">;" + xCrLf;
	implCode_ += xTab + xTab + _T("hRes = CComObject<") + GetClassName() + _T(">::CreateInstance(&tmp);") + xCrLf;
	implCode_ += xTab + xTab + _T("tmp->AddRef();") + xCrLf;
	//implCode_ += xTab + xTab + "tmp->QueryInterface(IID_I" + GetClassName() + ", (void**) &newItem);" + xCrLf;
	//implCode_ += xTab + xTab + "newItem->Copy(mapItem);" + xCrLf;
	implCode_ += xTab + xTab + _T("tmp->Copy(mapItem);") + xCrLf;
	implCode_ += xTab + xTab + _T("mapItem->Release();") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + xTab + GetCamelCase(classInfo_->GetName()) + p + _T("_[W2T(key)] = tmp;") + xCrLf;
	//if (sortKeyMember->GetDataType() == enDataType_String) {
	//	implCode_ += xTab + xTab + "SysFreeString(key);" + xCrLf;
	//}
	implCode_ += xTab + xTab + _T("source->MoveNext(&ret);") + xCrLf;
	implCode_ += xTab + _T("}") + xCrLf;
	implCode_ += xTab + _T("return S_OK;") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

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

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

	// RestoreDefaults
	//
	implCode_ += _T("STDMETHODIMP ") + GetClassName() + p + _T("::RestoreDefaults()")  + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("return S_OK;") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

	// CleanUp
	//
	implCode_ += _T("STDMETHODIMP ") + GetClassName() + p + _T("::CleanUp()")  + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("map<") + TypeOf(sortKeyMember->GetDataType()) + _T(", CComObject<") + GetClassName() + _T(">* >::iterator it;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("for(it = ") + mapName + _T("_.begin(); it != ") + mapName + _T("_.end(); it++) {") + xCrLf;
	implCode_ += xTab + xTab + _T("it->second->CleanUp();") + xCrLf;
	implCode_ += xTab + xTab + _T("it->second->Release();") + xCrLf;
	implCode_ += xTab + _T("}") + xCrLf;
	implCode_ += xTab + mapName + _T("_.clear();") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("return S_OK;") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

	// GetSize
	//
	implCode_ += _T("STDMETHODIMP ") + GetClassName() + p + _T("::GetSize(long* retval)")  + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("*retval = ") + GetCamelCase(classInfo_->GetName()) + p + _T("_.size();") + xCrLf;
	implCode_ += xTab + _T("return S_OK;") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

	// ReplaceKey
	//
	implCode_ += _T("STDMETHODIMP ") + GetClassName() + p + _T("::ReplaceKey(BSTR currentKey, BSTR newKey)")  + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("USES_CONVERSION;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("map<") + TypeOf(sortKeyMember->GetDataType()) + _T(", CComObject<") + GetClassName() + _T(">* >::iterator it;") + xCrLf;
	implCode_ += xTab + _T("CComObject<") + GetClassName() + _T(">* tmp;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("// check if new key is already used by another element") + xCrLf;
	implCode_ += xTab + _T("//") + xCrLf;
	implCode_ += xTab + _T("it = ") + mapName + _T("_.find(W2T(newKey));") + xCrLf;
	implCode_ += xTab + _T("if (it != ") + mapName + _T("_.end())") + xCrLf;
	implCode_ += xTab + xTab + _T("return S_OK;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("// check if current key exists") + xCrLf;
	implCode_ += xTab + _T("//") + xCrLf;
	implCode_ += xTab + _T("it = ") + mapName + _T("_.find(W2T(currentKey));") + xCrLf;
	implCode_ += xTab + _T("if (it == ") + mapName + _T("_.end())") + xCrLf;
	implCode_ += xTab + xTab + _T("return S_OK;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("tmp = it->second;") + xCrLf;
	implCode_ += xTab + mapName + _T("_.erase(W2T(currentKey));") + xCrLf;
	implCode_ += xTab + mapName + _T("_[W2T(newKey)] = tmp;") + xCrLf;
	implCode_ += xTab + _T("tmp->put_") + sortKeyMember->GetName() + _T("(newKey);") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("return S_OK;") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

	// Insert
	//
	paramName = GetCamelCase(classInfo_->GetName());
	implCode_ += _T("STDMETHODIMP ") + GetClassName() + p + _T("::Insert(I") + GetClassName() + _T("* item)") + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("USES_CONVERSION;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("CComObject<") + GetClassName() + _T(">* newItem;") + xCrLf;
	if (sortKeyMember->GetDataType() == enDataType_String)
		implCode_ += xTab + _T("CComBSTR key;") + xCrLf;
	else
		implCode_ += xTab + OleTypeOf(sortKeyMember->GetDataType()) + _T(" key;") + xCrLf;

	implCode_ += xTab + _T("HRESULT hRes = 0;") + xCrLf;
	implCode_ += xCrLf;
	//implCode_ += xTab + "newItem = new CComObject<" + GetClassName() + ">;" + xCrLf;
	implCode_ += xTab + _T("hRes = CComObject<") + GetClassName() + _T(">::CreateInstance(&newItem);") + xCrLf;
	implCode_ += xTab + _T("newItem->AddRef();") + xCrLf;
	implCode_ += xTab + _T("newItem->Copy(item);") + xCrLf;
	implCode_ += xTab + _T("newItem->get_") + sortKeyMember->GetName() + _T("(&key);") + xCrLf;
	implCode_ += xTab + mapName + _T("_[W2T(key)] = newItem;") + xCrLf;
	//if (sortKeyMember->GetDataType() == enDataType_String)
	//	implCode_ += xTab + "SysFreeString(key);" + xCrLf;
	implCode_ += xTab + _T("return S_OK;") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

	// Delete
	//
	implCode_ += _T("STDMETHODIMP ") + GetClassName() + p + _T("::Delete(") + OleTypeOf(sortKeyMember->GetDataType()) + _T(" key)") + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("USES_CONVERSION;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("map<") + TypeOf(sortKeyMember->GetDataType()) + _T(", CComObject<") + GetClassName() + _T(">* >::iterator it;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("it = ") + mapName + _T("_.find(W2T(key));") + xCrLf;
	implCode_ += xTab + _T("if (it != ") + mapName + _T("_.end()) {") + xCrLf;
	implCode_ += xTab + xTab + _T("it->second->Release();") + xCrLf;
	implCode_ += xTab + xTab + mapName + _T("_.erase(W2T(key));") + xCrLf;
	implCode_ += xTab + _T("}") + xCrLf;
	implCode_ += xTab + _T("return S_OK;") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

	// MoveFirst
	//
	implCode_ += _T("STDMETHODIMP ") + GetClassName() + p + _T("::MoveFirst(VARIANT_BOOL* retval)")  + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("it_ = ") + mapName + _T("_.begin();") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("*retval = (") + mapName + _T("_.size() != 0) ? VARIANT_TRUE : VARIANT_FALSE;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("return S_OK;") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

	// MoveNext
	//
	implCode_ += _T("STDMETHODIMP ") + GetClassName() + p + _T("::MoveNext(VARIANT_BOOL* retval)")  + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("it_++;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("*retval = (it_ != ") + mapName + _T("_.end()) ? VARIANT_TRUE : VARIANT_FALSE;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("return S_OK;") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;
	
	// GetPair
	//
	implCode_ += _T("STDMETHODIMP ") + GetClassName() + p + _T("::GetPair(") + OleTypeOf(sortKeyMember->GetDataType()) + _T("* key, I") + GetClassName() + _T("** item, VARIANT_BOOL* retval)")  + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("USES_CONVERSION;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("if (it_ != ") + mapName + _T("_.end()) {") + xCrLf;
	implCode_ += xTab + xTab + _T("CComObject<") + GetClassName() + _T(">* tmp;") + xCrLf;
	if (sortKeyMember->GetDataType() == enDataType_String) {
		implCode_ += xTab + xTab + _T("cmString tmpKey;") + xCrLf;
		implCode_ += xCrLf;
		implCode_ += xTab + xTab + _T("tmpKey = it_->first;") + xCrLf;
		implCode_ += xTab + xTab + _T("*key = tmpKey.AllocSysString();") + xCrLf;
	} else {
		implCode_ += xCrLf;
		implCode_ += xTab + xTab + _T("*key = it_->first") + xCrLf; 
	}
	implCode_ += xTab + xTab + _T("tmp = it_->second;") + xCrLf;
	implCode_ += xTab + xTab + _T("tmp->QueryInterface(IID_I") + GetClassName(classInfo_->GetName()) + _T(", (void**) item);") + xCrLf;
	implCode_ += xTab + xTab + _T("*retval = VARIANT_TRUE;") + xCrLf;
	implCode_ += xTab + _T("} else {") + xCrLf;
	implCode_ += xTab + xTab + _T("*retval = VARIANT_FALSE;") + xCrLf;
	implCode_ += xTab + _T("}") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("return S_OK;") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

	// FindItem
	//
	implCode_ += _T("STDMETHODIMP ") + GetClassName() + p + _T("::FindItem(") + OleTypeOf(sortKeyMember->GetDataType()) + _T(" key, I") + GetClassName() + _T("** item)")  + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("USES_CONVERSION;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("map<") + TypeOf(sortKeyMember->GetDataType()) + _T(", CComObject<") + GetClassName() + _T(">* >::iterator it;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("it = ") + mapName + _T("_.find(W2T(key));") + xCrLf;
	implCode_ += xTab + _T("if (it != ") + mapName + _T("_.end()) {") + xCrLf;
	implCode_ += xTab + xTab + _T("CComObject<") + GetClassName() + _T(">* tmp;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + xTab + _T("tmp = it->second;") + xCrLf;
	implCode_ += xTab + xTab + _T("tmp->QueryInterface(IID_I") + GetClassName(classInfo_->GetName()) + _T(", (void**) item);") + xCrLf;
	implCode_ += xTab + _T("} else {") + xCrLf;
	implCode_ += xTab + xTab + _T("*item = NULL;") + xCrLf;
	implCode_ += xTab + _T("}") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("return S_OK;") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

	//////////////////////////////////////////////////////////////////////
	// loadFromFile
	//
	implCode_ += _T("STDMETHODIMP ") + GetClassName() + p + _T("::Load(BSTR fileName, VARIANT_BOOL* retval)") + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("USES_CONVERSION;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("bool ret;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("ret = LoadFromXmlFile(W2T(fileName));") + xCrLf;
	implCode_ += xTab + _T("*retval = ret ? VARIANT_TRUE : VARIANT_FALSE;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("return S_OK;") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;

	//////////////////////////////////////////////////////////////////////
	// saveToFile
	//
	implCode_ += _T("STDMETHODIMP ") + GetClassName() + p + _T("::Save(BSTR fileName, VARIANT_BOOL* retval)") + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("USES_CONVERSION;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("bool ret;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("ret = SaveToXmlFile(W2T(fileName));") + xCrLf;
	implCode_ += xTab + _T("*retval = ret ? VARIANT_TRUE : VARIANT_FALSE;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("return S_OK;") + xCrLf;
	implCode_ += _T("}") + xCrLf;
	implCode_ += xCrLf;
}

void CAtlClassMapGenerator::Impl_generateSerialization()
{
	ClassMemberMap::iterator it;
	CXmlBaseElement* member;
	cmString mapName;
	cmString sortKey;
	cmString p;

	p = GetCardinalityPostfix(classInfo_);
	mapName = GetCamelCase(classInfo_->GetName()) + p;
	sortKey = _T("newChildElement.Get") + classInfo_->GetCardinalityInfo()->GetMapSortKey() + _T("()");
	member = classInfo_->GetMember(classInfo_->GetCardinalityInfo()->GetMapSortKey());

	//////////////////////////////////////////////////////////////////////
	// BuildFromXml
	//
	implCode_ += _T("bool ") + GetClassName() + p + _T("::BuildFromXml(IXMLDOMNode* node)") + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("USES_CONVERSION;") + xCrLf;
	implCode_ += xCrLf;

	implCode_ += xTab + _T("IXMLDOMNode* childNode;") + xCrLf;
    implCode_ += xTab + _T("IXMLDOMNodeList* children;") + xCrLf;
	implCode_ += xTab + _T("long size;") + xCrLf;
	implCode_ += xTab + _T("CComBSTR nodeName;") + xCrLf;
	implCode_ += xTab + _T("cmString tmp;") + xCrLf;
	if (member->GetDataType() == enDataType_String)
		implCode_ += xTab + _T("CComBSTR key;") + xCrLf;
	else
		implCode_ += xTab + OleTypeOf(member->GetDataType()) + _T(" key;") + xCrLf;
	implCode_ += xTab + _T("CComObject<") + GetClassName() + _T(">* newItem;") + xCrLf;
	implCode_ += xTab + _T("HRESULT hr;") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("RestoreDefaults();") + xCrLf;
	implCode_ += xTab + xCrLf;

	implCode_ += xTab + _T("hr = node->get_childNodes(&children);") + xCrLf;
	implCode_ += xTab + _T("hr = children->get_length(&size);") + xCrLf;
	implCode_ += xTab + _T("for (long i = 0; i < size; i++) {") + xCrLf;
	implCode_ += xTab + xTab + _T("hr = children->get_item(i, &childNode);") + xCrLf;
	implCode_ += xTab + xTab + _T("hr = childNode->get_nodeName(&nodeName);") + xCrLf;
	implCode_ += xTab + xTab + _T("tmp = nodeName;") + xCrLf;
	implCode_ += xTab + xTab + _T("if (") + GetClassName() + _T("::xmlNodeName_.CompareNoCase(tmp) == 0) {") + xCrLf;
	//implCode_ += xTab + xTab + xTab + "newItem = new CComObject<" + GetClassName() + ">;" + xCrLf;
	implCode_ += xTab + xTab + xTab + _T("hr = CComObject<") + GetClassName() + _T(">::CreateInstance(&newItem);") + xCrLf;
	implCode_ += xTab + xTab + xTab + _T("newItem->AddRef();") + xCrLf;
	implCode_ += xTab + xTab + xTab + _T("newItem->BuildFromXml(childNode);") + xCrLf;
	implCode_ += xTab + xTab + xTab + _T("newItem->get_") + member->GetName() + _T("(&key);") + xCrLf;
	implCode_ += xTab + xTab + xTab + mapName + _T("_[W2T(key)] = newItem;") + xCrLf;
	implCode_ += xTab + xTab + _T("}") + xCrLf;
	implCode_ += xCrLf;
	implCode_ += xTab + _T("}") + xCrLf + xCrLf;

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

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

	//////////////////////////////////////////////////////////////////////
	// AppendToDOMDocument
	//
	implCode_ += _T("bool ") + GetClassName() + p + _T("::AppendToDOMDocument(IXMLDOMDocument2* xmlDoc, IXMLDOMElement* parentElement)") + xCrLf;
	implCode_ += _T("{") + xCrLf;
	implCode_ += xTab + _T("map<") + TypeOf(member->GetDataType()) + _T(", CComObject<")  + GetClassName() + _T(">* >::iterator it;") + xCrLf;
    
	if (classInfo_->GetCardinalityInfo()->GetUseContainerNode()) {
		implCode_ += xTab + _T("IXMLDOMElement* newElement;") + xCrLf;
		implCode_ += xTab + _T("HRESULT hr;") + xCrLf;
		implCode_ += xCrLf;
		implCode_ += xTab + _T("hr = xmlDoc->createElement(CComBSTR((const TCHAR*)GetXmlNodeName()), &newElement);") + xCrLf;
		implCode_ += xTab + _T("if (FAILED(hr))") + xCrLf;
		implCode_ += xTab + xTab + _T("return false;") + xCrLf;
		implCode_ += xCrLf;
		implCode_ += xTab + _T("for (it = ") + mapName + _T("_.begin(); it != ") + mapName + _T("_.end(); it++)") + xCrLf;
		implCode_ += xTab + xTab + _T("it->second->AppendToDOMDocument(xmlDoc, newElement);") + xCrLf;
		implCode_ += xCrLf;
		implCode_ += xTab + _T("if (parentElement)") + xCrLf;
		implCode_ += xTab + xTab + _T("hr = parentElement->appendChild(newElement, NULL);") + xCrLf;
		implCode_ += xTab + _T("else") + xCrLf;
		implCode_ += xTab + xTab + _T("hr = xmlDoc->appendChild(newElement, NULL);") + xCrLf;
		implCode_ += xCrLf;
	} else {
		implCode_ += xCrLf;
		implCode_ += xTab + _T("for (it = ") + mapName + _T("_.begin(); it != ") + mapName + _T("_.end(); it++)") + xCrLf;
		implCode_ += xTab + xTab + _T("it->second->AppendToDOMDocument(xmlDoc, parentElement);") + xCrLf;
		implCode_ += xCrLf;
	}
	implCode_ += xTab + _T("return true;") + xCrLf;
	implCode_ += _T("}") + xCrLf + xCrLf;

	
}