// CategoryInfo.h
//

#include "stdafx.h"
#include "XmlGuiCategoryInfo.h"
#include "XmlGuiCategoryField.h"
#include "XmlClassInfo.h"
#include "XmlMemberInfo.h"

CXmlGuiCategoryInfo::CXmlGuiCategoryInfo():
	contracted_(false),
	classInfo_(NULL),
	sorted_(false)
{

}

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

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

cmString CXmlGuiCategoryInfo::GetCaption()
{
	return caption_;
}

void CXmlGuiCategoryInfo::SetDescription(const cmString& description)
{
	description_ = description;
}

cmString CXmlGuiCategoryInfo::GetDescription()
{
	return description_;
}

CXmlGuiCategoryField* CXmlGuiCategoryInfo::GetField(int index)
{
	if (index < 0 || index >= fields_.size())
		return NULL;

	return fields_[index];
}

CXmlGuiCategoryField* CXmlGuiCategoryInfo::GetFieldByCaption(const cmString& caption)
{
	CXmlGuiCategoryField* ret = NULL;
	CXmlMemberInfo* member;
	cmString memberId;

	for (int i = 0; i < fields_.size(); i++) {
		memberId = fields_[i]->GetMemberId();
		if (memberId.GetLength()) {
			member = dynamic_cast<CXmlMemberInfo*>(classInfo_->GetMemberById(memberId));
			if (member && member->GetCaption() == caption) {
				ret = fields_[i];
				break;
			}
		}
	}

	return ret;
}

CXmlGuiCategoryField* CXmlGuiCategoryInfo::GetFieldByMemberName(const cmString& memberName)
{
	CXmlGuiCategoryField* ret = NULL;
	CXmlMemberInfo* member;
	cmString memberId;

	for (int i = 0; i < fields_.size(); i++) {
		memberId = fields_[i]->GetMemberId();
		if (memberId.GetLength()) {
			member = dynamic_cast<CXmlMemberInfo*>(classInfo_->GetMemberById(memberId));
			if (member && member->GetName() == memberName) {
				ret = fields_[i];
				break;
			}
		}
	}

	return ret;
}

void CXmlGuiCategoryInfo::MoveUpField(int index)
{
	if (index <= 0)
		return;

	MoveField(index, index - 1);
}

void CXmlGuiCategoryInfo::MoveDownField(int index)
{
	if (index >= fields_.size() - 1)
		return;

	MoveField(index, index + 1);
}

void CXmlGuiCategoryInfo::Clear()
{
	for (int i = 0; i < fields_.size(); i++)
		delete fields_[i];
}

void CXmlGuiCategoryInfo::MoveField(int oldIndex, int newIndex)
{
	FieldList::iterator it;
	CXmlGuiCategoryField* field;
	int index;
	
	it = fields_.begin();
	for (index = 0; index < fields_.size(); index++) {
		if (index == oldIndex) {
			field = fields_[oldIndex];
			fields_.erase(it);
			break;
		}
		it++;
	}
	
	index = 0;
	for (it = fields_.begin(); it != fields_.end(); it++) {
		
		if (index == newIndex) {
			fields_.insert(it, field);
			return;
		}
		
		index++;
	}

	fields_.push_back(field);
}

CXmlGuiCategoryField* CXmlGuiCategoryInfo::InsertField(int index)
{
	CXmlGuiCategoryField* newField;
	FieldList::iterator it;

	newField = new CXmlGuiCategoryField;
	newField->SetClassInfo(classInfo_);

	it = fields_.begin();
	for (int i = 0; i < fields_.size(); i++) {
		if (i == index) {
			fields_.insert(it, newField);
			return newField;
		}
		it++;
	}
	
	fields_.push_back(newField);

	return newField;
}

void CXmlGuiCategoryInfo::RemoveField(const cmString& memberName)
{
	CXmlMemberInfo* member;
	cmString memberId;
	
	for (int i = 0; i < fields_.size(); i++) {
		memberId = fields_[i]->GetMemberId();
		member = dynamic_cast<CXmlMemberInfo*>(classInfo_->GetMemberById(memberId));
		if (member->GetName() == memberName) {
			RemoveField(i);
			break;
		}
	}
}

void CXmlGuiCategoryInfo::RemoveField(int index)
{
	if (index < 0 || index >= fields_.size())
		return;

	delete fields_[index];
	fields_.erase(fields_.begin() + index);
}

void CXmlGuiCategoryInfo::RemoveField(CXmlGuiCategoryField* field)
{
	for (int i = 0; i < fields_.size(); i++) {
		if (fields_[i] == field) {
			RemoveField(i);
			break;
		}
	}
}

int CXmlGuiCategoryInfo::GetFieldCount()
{
	return fields_.size();
}

void CXmlGuiCategoryInfo::SetContracted(bool contracted)
{
	contracted_ = contracted;
}

bool CXmlGuiCategoryInfo::GetContracted()
{
	return contracted_;
}

bool CXmlGuiCategoryInfo::BuildFromXml(IXMLDOMNode* node)
{
	IXMLDOMNode* childNode;
	IXMLDOMNodeList* children;
	CComBSTR nodeName;
	CComVariant nodeValue;
	long i;
	long size;
	HRESULT hRes;

	Clear();
	
	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 (wcscmp(nodeName, _T("Contracted")) == 0) {
			contracted_ = (_wtoi(nodeValue.bstrVal) == 1);
		} else if(wcscmp(nodeName, _T("Caption")) == 0) {
			caption_ = nodeValue.bstrVal;
		} else if(wcscmp(nodeName, _T("Description")) == 0) {
			description_ = nodeValue.bstrVal;
		} else if(wcscmp(nodeName, _T("Sorted")) == 0) {
			sorted_ = (_wtoi(nodeValue.bstrVal) == 1);
		} else if(wcscmp(nodeName, _T("FieldList")) == 0) {
			IXMLDOMNode* fieldNode;
			IXMLDOMNodeList* fieldList;
			CComBSTR fieldNodeName;
			CXmlGuiCategoryField* newField;
			long j;
			long len;

			hRes = childNode->get_childNodes(&fieldList);
			hRes = fieldList->get_length(&len);
			for (j = 0; j < len; j++) {
				hRes = fieldList->get_item(j, &fieldNode);
				hRes = fieldNode->get_nodeName(&fieldNodeName);
				
				if ((BSTR)fieldNodeName == CXmlGuiCategoryField::GetXmlNodeName()) {
					
					newField = new CXmlGuiCategoryField;
					newField->SetClassInfo(classInfo_);
					newField->BuildFromXml(fieldNode);
					fields_.push_back(newField);
				}
			}
		}
	}

	return true;
}

bool CXmlGuiCategoryInfo::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("Contracted"), contracted_, newElement, xmlDoc);
	AppendMemberNode(_T("Caption"), caption_, newElement, xmlDoc);
	AppendMemberNode(_T("Description"), description_, newElement, xmlDoc);
	AppendMemberNode(_T("Sorted"), sorted_, newElement, xmlDoc);

	// serialize members
	//
	CXmlGuiCategoryField* field;
	IXMLDOMElement* fieldList;
	IXMLDOMNode* newOutNode;

	hr = xmlDoc->createElement(CComBSTR(_T("FieldList")), &fieldList);

	for (int i = 0; i < fields_.size(); i++) {
		field = fields_[i];

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

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

	return ret;
}

void CXmlGuiCategoryInfo::SetClassInfo(CXmlClassInfo* classInfo)
{
	classInfo_ = classInfo;
}

void CXmlGuiCategoryInfo::SetSorted(bool sorted)
{
	sorted_ = sorted;
}

bool CXmlGuiCategoryInfo::GetSorted() const
{
	return sorted_;
}
