// XmlClassInfo.cpp: implementation of the CXmlClassInfo class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "XmlClassInfo.h"
#include "XmlMemberInfo.h"
#include "XmlElementsFactory.h"

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

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CXmlClassInfo::CXmlClassInfo():
	renderingMode_(enRenderingMode_None),
	definitionInheritance_(false),
	lockedByInheritance_(false)
{
	categoryList_.SetClassInfo(this);
}

CXmlClassInfo::~CXmlClassInfo()
{
	Clear();
}

bool CXmlClassInfo::BuildFromXml(IXMLDOMNode* node)
{
	Clear();

	IXMLDOMNode* tmp;
	cmString dummy;

	tmp = GetChildNode(node, CXmlBaseElement::GetXmlNodeName(), dummy);
	assert(tmp);
	if (tmp) {
		CXmlBaseElement::BuildFromXml(tmp);
		tmp->Release();
	}

	ExtractMemberNode(node, _T("Caption"), caption_);
	ExtractMemberNode(node, _T("ContainerCaption"), containerCaption_);
	ExtractMemberNode(node, _T("RenderingMode"), (int&)renderingMode_);
	ExtractMemberNode(node, _T("LockedByInheritance"), lockedByInheritance_);
	ExtractMemberNode(node, _T("DefinitionInheritance"), definitionInheritance_);;
	ExtractMemberNode(node, _T("InheritClassId"), inherithClassId_);
	ExtractMemberNode(node, _T("AtlClassGuid"), atlClassGuid_);
	ExtractMemberNode(node, _T("AtlInterfaceGuid"), atlInterfaceGuid_);
	ExtractMemberNode(node, categoryList_.GetXmlNodeName(), categoryList_);
	ExtractMemberNode(node, gridInfo_.GetXmlNodeName(), gridInfo_);
	ExtractMemberNode(node, cardinality_.GetXmlNodeName(), cardinality_);
	
	IXMLDOMNode* childNode;
	IXMLDOMNodeList* children;
	CComBSTR nodeName;
	CComVariant nodeValue;
	HRESULT hRes;
	long i;
	long size;
	
	hRes = node->get_childNodes(&children);
	hRes = children->get_length(&size);
	
	for (i = 0; i < size; i++) {
		
		hRes = children->get_item(i, &childNode);
		hRes = childNode->get_nodeName(&nodeName);
		hRes = childNode->get_nodeTypedValue(&nodeValue);
		
		if(cmString(_T("MemberList")) == nodeName) {
			IXMLDOMNode* memberNode;
			IXMLDOMNodeList* memberList;
			CComBSTR memberNodeName;
			CXmlBaseElement* newXmlElement;
			enDataType newElementDataType;
			long len;
			long j;

			hRes = childNode->get_childNodes(&memberList);
			hRes = memberList->get_length(&len);
			for (j = 0; j < len; j++) {
				
				hRes = memberList->get_item(j, &memberNode);
				hRes= memberNode->get_nodeName(&memberNodeName);
				
				if ((BSTR)memberNodeName == CXmlClassInfo::GetXmlNodeName()) {
					newElementDataType = enDataType_Class;
				} else if ((BSTR)memberNodeName == CXmlMemberInfo::GetXmlNodeName()) {
					newElementDataType = enDataType_String;
				}

				newXmlElement = CXmlElementsFactory::CreateXmlElement(newElementDataType);
				newXmlElement->BuildFromXml(memberNode);
				
				members_[newXmlElement->GetName()] = newXmlElement;
			}
		} else if(CXmlTreeIcons::GetXmlNodeName() == nodeName) {
			treeIcons_.BuildFromXml(childNode);
		} else if (cmString(_T("MapIcons")) == nodeName) {
			IXMLDOMNodeList* memberList;
			long len;

			hRes = childNode->get_childNodes(&memberList);
			hRes = memberList->get_length(&len);
			if (len) {
				IXMLDOMNode* memberNode;
				hRes = memberList->get_item(0, &memberNode);
				mapTreeIcons_.BuildFromXml(memberNode);
			}
			
		} else if (cmString(_T("ArrayIcons")) == nodeName) {
			IXMLDOMNodeList* memberList;
			long len;

			hRes = childNode->get_childNodes(&memberList);
			hRes = memberList->get_length(&len);
			if (len) {
				IXMLDOMNode* memberNode;
				hRes = memberList->get_item(0, &memberNode);

				arrayTreeIcons_.BuildFromXml(memberNode);
			}
		}
	}

	return true;
}

bool CXmlClassInfo::AppendToDOMDocument(IXMLDOMDocument2* xmlDoc, 
										IXMLDOMElement* parentElement) 
{
	IXMLDOMElement* newElement;
	bool ret;
	HRESULT hr;
	
	hr = xmlDoc->createElement(CComBSTR((const TCHAR*)GetXmlNodeName()), &newElement);

	ret = CXmlBaseElement::AppendToDOMDocument(xmlDoc, newElement);
	if (!ret)
		return false;

	AppendMemberNode(_T("Caption"), caption_, newElement, xmlDoc);
	AppendMemberNode(_T("ContainerCaption"), containerCaption_, newElement, xmlDoc);
	AppendMemberNode(_T("RenderingMode"), renderingMode_, newElement, xmlDoc);
	AppendMemberNode(_T("RenderingModeStr"), RenderingMode2String(renderingMode_), newElement, xmlDoc);
	AppendMemberNode(_T("LockedByInheritance"), lockedByInheritance_, newElement, xmlDoc);
	AppendMemberNode(_T("DefinitionInheritance"), definitionInheritance_, newElement, xmlDoc);
	AppendMemberNode(_T("InheritClassId"), inherithClassId_, newElement, xmlDoc);
	AppendMemberNode(_T("AtlClassGuid"), atlClassGuid_, newElement, xmlDoc);
	AppendMemberNode(_T("AtlInterfaceGuid"), atlInterfaceGuid_, newElement, xmlDoc);

	treeIcons_.AppendToDOMDocument(xmlDoc, newElement);
	
	IXMLDOMElement* mapIcons;
	IXMLDOMElement* arrayIcons;
	IXMLDOMNode* newOutNode;

	hr = xmlDoc->createElement(_T("MapIcons"), &mapIcons);
	mapTreeIcons_.AppendToDOMDocument(xmlDoc, mapIcons);
	hr = newElement->appendChild(mapIcons, &newOutNode);
	newOutNode->Release();

	hr = xmlDoc->createElement(_T("ArrayIcons"), &arrayIcons);
	arrayTreeIcons_.AppendToDOMDocument(xmlDoc, arrayIcons);
	hr = newElement->appendChild(arrayIcons, &newOutNode);
	newOutNode->Release();

	cardinality_.AppendToDOMDocument(xmlDoc, newElement);
	
	// serialize members
	//
	ClassMemberMap::iterator it;
	CXmlBaseElement* member;
	IXMLDOMElement* memberList;

	hr = xmlDoc->createElement(_T("MemberList"), &memberList);

	for (it = members_.begin(); it != members_.end(); it++) {
		member = it->second;

		member->AppendToDOMDocument(xmlDoc, memberList);
	}
	
	hr = newElement->appendChild(memberList, &newOutNode);
	newOutNode->Release();

	switch (renderingMode_) {
		case enRenderingMode_None:
			break;

		case enRenderingMode_FlatList:
			break;

		case enRenderingMode_CategoryList:
			categoryList_.AppendToDOMDocument(xmlDoc, newElement);
			break;

		case enRenderingMode_Grid:
			gridInfo_.AppendToDOMDocument(xmlDoc, newElement);
			break;

		case enRenderingMode_CustomDialog:
			break;
	}

	// append node to parent element
	//
	if (parentElement)
		hr = parentElement->appendChild(newElement, &newOutNode);
	else
		hr = xmlDoc->appendChild(newElement, &newOutNode);

	return ret;
}



void CXmlClassInfo::Clear()
{
	ClassMemberMap::iterator it;

	for (it = members_.begin(); it != members_.end(); it++)
		delete it->second;

	members_.clear();
	cardinality_.Clear();
	categoryList_.Clear();
	gridInfo_.Clear();
}

void CXmlClassInfo::SetDefaults()
{

}

ClassMemberMap* CXmlClassInfo::GetMembers()
{
	return &members_;
}

CXmlBaseElement* CXmlClassInfo::AddMember(enDataType dataType)
{
	CXmlBaseElement* newMember;

	newMember = CXmlElementsFactory::CreateXmlElement(dataType);
	
	// members are indexed by name. By default when a member is created
	// its name is equal to its id
	//
	members_[newMember->GetId()] = newMember;

	return newMember;
}

//DEL CXmlBaseElement* CXmlClassInfo::AddMember(const CXmlBaseElement& member)
//DEL {
//DEL 	// check if the class already contains a member with the same name
//DEL 	//
//DEL 	if (GetMember(member.GetName()))
//DEL 		return NULL;
//DEL 
//DEL 	CXmlBaseElement* newMember;
//DEL 	
//DEL 	newMember = CXmlElementsFactory::CreateXmlElement(member.GetDataType());
//DEL 	*newMember = member;
//DEL 	members_[newMember->GetId()] = newMember;
//DEL 
//DEL 	return newMember;
//DEL }

void CXmlClassInfo::RemoveMemberById(const cmString& id)
{
	ClassMemberMap::iterator it;
	CXmlBaseElement* member;

	for (it = members_.begin(); it != members_.end(); it++) {
		member = it->second;
		if (member->GetId() == id) {
			delete member;
			members_.erase(it);
			return;
		}
	}
}

void CXmlClassInfo::RemoveMember(const cmString& name)
{
	CXmlBaseElement* member;

	member = GetMember(name);
	if (member) {
		delete member;

		members_.erase(name);
	}
}

CXmlBaseElement* CXmlClassInfo::GetMember(const cmString& name, 
										  enDataType dataType, 
										  bool recursive)
{
	CXmlBaseElement* member;
	ClassMemberMap::iterator it;

	for (it = members_.begin(); it != members_.end(); it++) {
		member = it->second;

		if (dataType != enDataType_None) {
			if (member->GetDataType() == dataType && member->GetName() == name)
				return member;
		} else {
			if (member->GetName() == name)
				return member;
		}

		if (recursive) {
			if (member->GetDataType() == enDataType_Class) {
				CXmlClassInfo* classInfo;

				classInfo = dynamic_cast<CXmlClassInfo*>(member);
				assert(classInfo);
				member = classInfo->GetMember(name, dataType, recursive);
				if (member)
					return member;
			}
		}
	}

	return NULL;
}

CXmlBaseElement* CXmlClassInfo::GetMemberById(const cmString& id, bool recursive)
{
	CXmlBaseElement* member;
	ClassMemberMap::iterator it;

	for (it = members_.begin(); it != members_.end(); it++) {
		member = it->second;
		if (member->GetId() == id)
			return member;

		if (recursive) {
			if (member->GetDataType() == enDataType_Class) {
				CXmlClassInfo* classInfo;

				classInfo = dynamic_cast<CXmlClassInfo*>(member);
				member = classInfo->GetMemberById(id, recursive);
				if (member)
					return member;
			}
		}
	}

	return NULL;
}

void CXmlClassInfo::SetCaption(const cmString& caption)
{
	caption_ = caption;
}

cmString CXmlClassInfo::GetCaption() const
{
	return caption_;
}

void CXmlClassInfo::SetContainerCaption(const cmString& containerCaption)
{
	containerCaption_ = containerCaption;
}

cmString CXmlClassInfo::GetContainerCaption() const
{
	return containerCaption_;
}

void CXmlClassInfo::SetRenderingMode(enRenderingMode renderingMode)
{
	renderingMode_ = renderingMode;
}

enRenderingMode CXmlClassInfo::GetRenderingMode()
{
	return renderingMode_;
}

CXmlGuiCategoryInfoList* CXmlClassInfo::GetCategoryInfoList()
{
	return &categoryList_;
}

CXmlFormInfo* CXmlClassInfo::GetForm()
{
	return &form_;
}

int CXmlClassInfo::GetMemberCount(enDataType dataType)
{
	if (dataType == enDataType_None)
		return members_.size();

	int memberCount = 0;
	ClassMemberMap::iterator it;
	CXmlBaseElement* member;

	for (it = members_.begin(); it != members_.end(); it++) {
		member = it->second;
		if (member->GetDataType() == dataType)
			memberCount++;
	}

	return memberCount;
}

CXmlClassCardinality* CXmlClassInfo::GetCardinalityInfo()
{
	return &cardinality_;
}

CXmlGuiGridInfo* CXmlClassInfo::GetGridInfo()
{
	return &gridInfo_;
}


void CXmlClassInfo::GetMembers(ClassMemberMap& members, enDataType dataType, bool recursive)
{
	ClassMemberMap::iterator it;
	CXmlBaseElement* member;
	CXmlClassInfo* classInfo;

	for (it = members_.begin(); it != members_.end(); it++) {
		member = it->second;
		if (dataType == enDataType_None || member->GetDataType() == dataType)
			members[member->GetId()] = member;
		
		if (recursive && member->GetDataType() == enDataType_Class) {
			classInfo = dynamic_cast<CXmlClassInfo*>(member);
			
			classInfo->GetMembers(members, dataType, recursive);
		}
	}
}

bool CXmlClassInfo::GetDefinitionInheritance() const
{
	return definitionInheritance_;
}

void CXmlClassInfo::SetDefinitionInheritance(bool inheritance)
{
	definitionInheritance_ = inheritance;
}

cmString CXmlClassInfo::GetInherithClassId() const
{
	return inherithClassId_;
}

void CXmlClassInfo::SetInherithClassId(const cmString& classId)
{
	inherithClassId_ = classId;
}

bool CXmlClassInfo::GetLockedByInheritance() const
{
	return lockedByInheritance_;
}

void CXmlClassInfo::SetLockedByInheritance(bool locked)
{
	lockedByInheritance_ = locked;
	inherithClassId_ = _T("");
}

bool CXmlClassInfo::CanInheritDefinition()
{
	return GetMemberCount(enDataType_Class) == 0;
}

CXmlTreeIcons* CXmlClassInfo::GetTreeIcons()
{
	return &treeIcons_;
}

CXmlTreeIcons* CXmlClassInfo::GetMapTreeIcons()
{
	return &mapTreeIcons_;
}

CXmlTreeIcons* CXmlClassInfo::GetArrayTreeIcons()
{
	return &arrayTreeIcons_;
}

cmString CXmlClassInfo::GetAtlClassGuid() const
{
	return atlClassGuid_;
}

void CXmlClassInfo::SetAtlClassGuid(const cmString& guid)
{
	atlClassGuid_ = guid;
}

cmString CXmlClassInfo::GetAtlInterfaceGuid() const
{
	return atlInterfaceGuid_;
}

void CXmlClassInfo::SetAtlInterfaceGuid(const cmString& guid)
{
	atlInterfaceGuid_ = guid;
}


void CXmlClassInfo::ClearAllGuids(bool recurse)
{
	atlClassGuid_ = _T("");
	atlInterfaceGuid_ = _T("");
	cardinality_.SetArrayClassGuid(_T(""));
	cardinality_.SetArrayInterfaceGuid(_T(""));
	cardinality_.SetMapClassGuid(_T(""));
	cardinality_.SetMapInterfaceGuid(_T(""));

	if (!recurse)
		return;

	ClassMemberMap::iterator it;
	CXmlBaseElement* member;

	for (it = members_.begin(); it != members_.end(); it++) {
		member = it->second;
		if (member->GetDataType() == enDataType_Class)
			(dynamic_cast<CXmlClassInfo*>(member))->ClearAllGuids(recurse);
	}

}

bool CXmlClassInfo::AttachMember(CXmlBaseElement* member)
{
	if (GetMember(member->GetName()))
		return false;

	members_[member->GetName()] = member;

	return true;
}

CXmlBaseElement* CXmlClassInfo::DetachMember(const cmString& id)
{
	CXmlBaseElement* ret;

	int oldSize;

	oldSize = members_.size();

	/*** DEBUG DUMP ***/

	ClassMemberMap::iterator it;

	TRACE(_T("********************\n"));
	TRACE1("size = %d\n", members_.size());
	for (it = members_.begin(); it != members_.end(); it++)
		TRACE1("name = <%s>\n", (const TCHAR*)it->first);
	/***/

	ret = GetMemberById(id, false);
	if (ret)
		members_.erase(ret->GetName());

	TRACE1("removed member %s\n", ret->GetName().c_str());
	TRACE1("size = %d\n", members_.size());

	assert(oldSize == members_.size() + 1);

	return ret;
}

void CXmlClassInfo::SetExpandedAtStartup(bool expanded, bool recursive)
{
	treeIcons_.SetExpandedAtStartup(expanded);

	if (recursive) {
		// apply the same settings to all children
		//
		ClassMemberMap::iterator it;

		for (it = members_.begin(); it != members_.end(); it++) {
			if (it->second->GetDataType() != enDataType_Class)
				continue;

			CXmlClassInfo* classInfo;

			classInfo = dynamic_cast<CXmlClassInfo*>(it->second);
			assert(classInfo);
			if (classInfo)
				classInfo->SetExpandedAtStartup(expanded, true);
		}
	}
}