#include "StdAfx.h"
#include ".\workspacenode.h"


//////////////////////////////////////////////////////////////////////////////////////////
//	初期化など
//////////////////////////////////////////////////////////////////////////////////////////
CWorkspaceNode::CWorkspaceNode(const CWorkspaceNode &other) :
	m_subNode(other.m_memoryPool), m_keyData(GetPairArrayMemoryPool(other.m_memoryPool))
{
	SetNodeName(other.GetNodeName());
	m_memoryPool = other.m_memoryPool;
	m_keyData.Copy(other.m_keyData);
	m_subNode.Copy(other.m_subNode);
}

CWorkspaceNode::CWorkspaceNode(IWorkspaceNodeArrayMemoryPool *memoryPool) :
	m_subNode(memoryPool), m_keyData(GetPairArrayMemoryPool(memoryPool))
{
	m_memoryPool = memoryPool;
}

CWorkspaceNode::CWorkspaceNode(IWorkspaceNodeArrayMemoryPool *memoryPool, LPCSTR name) :
	m_subNode(memoryPool), m_keyData(GetPairArrayMemoryPool(memoryPool))
{
	SetNodeName(name);
	m_memoryPool = memoryPool;
}

CWorkspaceNode::~CWorkspaceNode(void)
{
}

//	コピーオペレータ
void CWorkspaceNode::operator=(const CWorkspaceNode &other)
{
	//	データのコピー
	SetNodeName(other.GetNodeName());
	m_keyData.Copy(other.m_keyData);
	m_subNode.Copy(other.m_subNode);
}

//	全てクリア
void CWorkspaceNode::Clear(void)
{
	//	データ削除
	m_keyData.RemoveAll();
	m_subNode.RemoveAll();
}


//////////////////////////////////////////////////////////////////////////////////////////
//	Keyに対する処理(Public)
//////////////////////////////////////////////////////////////////////////////////////////
/*!
	データの設定

	このノードのデータに対するアクセス
*/
void CWorkspaceNode::SetKeyData(LPCSTR key, LPCSTR data, int noCase)
{
	m_keyData.Add(key, data,  noCase);
}

/*!
	データの取得

	このノードのデータに対するアクセス
*/
LPCSTR CWorkspaceNode::GetKeyData(LPCSTR key, LPCSTR defaultData, int noCase)
{
	return m_keyData.Get(key, defaultData,  noCase);
}


/*!
	データの削除

	このノードのデータに対するアクセス
*/
void CWorkspaceNode::DeleteKey(LPCSTR key)
{
	m_keyData.Delete(key);
}


/*!
	キー数を取得
*/
int CWorkspaceNode::GetKeyCount()
{
	return((int)m_keyData.GetCount());
}

/*!
	全てのキーを文字列として取得
*/
int CWorkspaceNode::GetAllKeyPair(IStringArrayPtr keys, IStringArrayPtr datas)
{
	//	サイズ初期化
	int count = (int)m_keyData.GetCount();
	if(keys != NULL)
		keys->SetSize(count);
	if(datas != NULL)
		datas->SetSize(count);

	//	設定
	for(int i=0;i<count;i++)
	{
		CWorkspaceKeyPair	*keyPair = m_keyData.GetByIndex(i);

		//	NULLでなければ設定
		if(keys != NULL)
			keys->SetString(i, keyPair->GetKey());
		if(datas != NULL)
			datas->SetString(i, keyPair->GetData());
	}

	return(count);
}



/*!
	キーを検索

	\param	pathCompare	左からの部分一致を許可
*/
int CWorkspaceNode::FindKeyData(LPCSTR sData, int noCase, int pathCompare)
{
	CString	cstring(sData);

	if(pathCompare)
	{
		//	比較
		for(int i=0;i<m_keyData.GetCount();i++)
		{
			LPCSTR sStr = m_keyData.GetByIndex(i)->GetData();
			if(cstring.Left(strlen(sStr)).CompareNoCase(sStr) == 0)
				return(i);
		}

		return(-1);
	}
	else
		return(m_keyData.Find(sData, noCase));
}
	

/*!
	キーをまとめて設定
*/
void CWorkspaceNode::ClearAndSetKeys(CStringArray &keys, CStringArray &datas)
{
	//	全削除
	m_keyData.RemoveAll();

	//	設定
	for(int i=0;i<keys.GetCount();i++)
		m_keyData.AddNoCompare(keys[i], datas[i]);
}

//////////////////////////////////////////////////////////////////////////////////////////
//	Keyに対する処理(Protect)
//////////////////////////////////////////////////////////////////////////////////////////
/*!
	Leafの検索
*/
int CWorkspaceNode::FindKeyIndex(LPCSTR key,int noCase)
{
	return(m_keyData.Find(key, noCase));
}

//////////////////////////////////////////////////////////////////////////////////////////
//	サブノードに対する処理(Public)
//////////////////////////////////////////////////////////////////////////////////////////
/*!
	サブノードを検索する
*/
CWorkspaceNode *CWorkspaceNode::GetSubNode(CWorkspaceNodeWalker &path, CWorkspaceString255 &key)
{
	//	最後？
	if(path.CurrentIsLastNode())
	{
		//	自分のキー
		key = path.GetCurrentNode();
		return this;
	}
	else
	{
		//	自分のサブノードを検索
		CWorkspaceNode *subNode = GetSubNodeByName(path.GetCurrentNode());

		//	さらに下を検索
		path.WalkToNextNode();
		return(subNode->GetSubNode(path, key));
	}
}


/*!
	ノードを削除する

*/
void CWorkspaceNode::DeleteNode(LPCSTR name)
{
	int index = FindSubNodeIndex(name);
	if(index != -1)
		m_subNode.RemoveAt(index);
}


/*!
	サブノード数を得る
*/
int CWorkspaceNode::GetSubNodeCount()
{
	return((int)m_subNode.GetCount ());
}


/*!
	全てのサブノード名を文字列として取得

	自分のサブノードのみです。
	下位ノードへは検索に行きません
*/
int CWorkspaceNode::GetAllSubNode(IStringArrayPtr list)
{
	//	サイズ初期化
	int count = (int)m_subNode.GetCount ();
	list->SetSize(count);

	//	設定
	for(int i=0;i<count;i++)
		list->SetString(i, m_subNode[i].GetNodeName());

	return(count);
}



//////////////////////////////////////////////////////////////////////////////////////////
//	サブノードに対する処理(Protected)
//////////////////////////////////////////////////////////////////////////////////////////
/*!
	サブノードを検索する
*/
int CWorkspaceNode::FindSubNodeIndex(LPCSTR name)
{
	for(int i=0;i<(int)m_subNode.GetCount();i++)
	{
		if(strcmp(m_subNode[i].GetNodeName(), name) == 0)
			return(i);
	}
	return -1;
}


/******************************************************
	入出力に関する処理
*******************************************************/
/*!
	サブノードを名前から取得・作成する

	\param errorIfExist	TRUEだと、既に存在している場合にエラーとなる
*/
CWorkspaceNode *CWorkspaceNode::GetSubNodeByName(LPCSTR name, int errorIfExist)
{
	int	index = FindSubNodeIndex(name);
	if(index == -1)
	{
		//	追加
		m_subNode.Add(CWorkspaceNode(m_memoryPool, name));
		return &m_subNode[m_subNode.GetCount ()-1];
	}

	//	エラー扱い？
	if(errorIfExist)
		return(NULL);
	return(&m_subNode[index]);
}


/*!
	サブノードをインデックスで取得する
*/
CWorkspaceNode *CWorkspaceNode::GetSubNodeByIndex(int index)
{
	if(index < 0 || index >= (int)m_subNode.GetCount())
		return(NULL);

	return(&m_subNode[index]);
}

/*!
	キーをインデックスで取得する
*/
CWorkspaceKeyPair *CWorkspaceNode::GetKeyByIndex(int index)
{
	if(index < 0 || index >= m_keyData.GetCount())
		return(NULL);

	return(m_keyData.GetByIndex(index));
}


/******************************************************
	メモリプール関係の処理
*******************************************************/
/*!
	IWorkspaceKeyPairArrayMemoryPoolを取得
	NULLチェック付
*/
IWorkspaceKeyPairArrayMemoryPool *CWorkspaceNode::GetPairArrayMemoryPool(IWorkspaceNodeArrayMemoryPool *basePool)
{
	if(basePool == NULL)
		return(NULL);
	return(basePool->GetKeyPairArrayMemoryPool());
}

/******************************************************
	CWorkspaceNodeArrayItmeConstructor
*******************************************************/
/*!
	コンストラクタを呼ぶ
*/
void CWorkspaceNodeArrayItmeConstructor::ConstructItem(CWorkspaceNode *item, void *userData)
{
	//	マクロ定義を書き換え
	#pragma push_macro("new")
	#undef new

	//	プレースメント new で要素を初期化
	::new(item) CWorkspaceNode((IWorkspaceNodeArrayMemoryPool*)userData);

	//	マクロ定義を戻す
	#pragma pop_macro("new")
};

/*!
	デストラクタを呼ぶ
*/
void CWorkspaceNodeArrayItmeConstructor::DestructItem(CWorkspaceNode *item, void *userData)
{
	item->~CWorkspaceNode();
};

/*!
	最適チャンクサイズ取得
*/
int IWorkspaceNodeArrayMemoryPool::GetChunkSize()
{
	return(sizeof(CWorkspaceNode) * NODE_GROW_SIZE);
}
