#include "StdAfx.h"
#include ".\workspace.h"
#include ".\workspaceAccess.h"
#include "WorkspaceXMLReader.h"
#include "WorkspaceXMLWriter.h"
#include "TextTools.h"

//	デバッグ補助
#ifndef DEBUG_OUT
	#define	DEBUG_OUT	TRACE
#endif

//	標準名
#define	DEFAULT_CLASS_TYPE	"CWorkspace"

//	リードオンリーフラグ確認
#define	WRITE_FUNCTION_CHECK()	if(m_readOnly) { ASSERT(0); return; };

CWorkspace::CWorkspace(CString className)
{
	if(className.IsEmpty())
		m_className = DEFAULT_CLASS_TYPE;
	else
		m_className = className;

	//	ルート名設定
	m_root.SetNodeName(m_className);

	//	読み込み専用ではない
	m_readOnly = 0;
}

CWorkspace::~CWorkspace(void)
{
}
/*********************************************************
	アクセス可能な関数
**********************************************************/
/*!
	アクセスクラスを取得する
*/
CWorkspaceAccess CWorkspace::GetAccess(CString path)
{
	return CWorkspaceAccess(this,path);
}


/*!
	アクセスクラスを取得し、中身をクリア
*/
CWorkspaceAccess CWorkspace::GetCleanAccess(CString path)
{
	CWorkspaceAccess ret = CWorkspaceAccess(this, path);
	ret.Clear();
	return ret;
}


/////////////////////////////////////////////////////////////////////////////////////
//	入出力に関する処理
/////////////////////////////////////////////////////////////////////////////////////
/*!
	XMLファイルへ出力
*/
int CWorkspace::SaveToXMLFile(CString filePath, CString savePath)
{
	SCOPE_LOCK();

	try
	{
		//	保存ノードの取得
		CString key;
		CWorkspaceNode * node = GetSubNode(savePath,key);

		//	保存
		CWorkspaceXMLWriter	writer;
		writer.SaveToFile(&m_root, filePath, m_className);
	}
	catch(CXMLTextParserException err)
	{
		DEBUG_OUT("XML LoadError : %s\n", err.m_error);
		return(-1);
	}
	return(0);
}

/*!
	XMLファイルよりロード
*/
int CWorkspace::LoadFromXMLFile(CString filePath)
{
	SCOPE_LOCK();

	try
	{
		//	クリア
		m_root.Clear();

		//	読み込み
		CWorkspaceXMLReader	reader;
		reader.LoadFromFile(&m_root, filePath, m_className);
	}
	catch(CXMLTextParserException err)
	{
		DEBUG_OUT("XML LoadError : %s\n", err.m_error);
		return(-1);
	}
	return(0);
}


/*!
	XML文字列へ出力
*/
CStringA CWorkspace::ToXMLStringUTF8(CString savePath)
{
	SCOPE_LOCK();

	return(CTextTools::StrToUTF8(ToXMLString(savePath).GetBuffer(0)));
}

/*!
	XML文字列から生成
*/
int CWorkspace::FromXMLStringUTF8(CStringA xml)
{
	SCOPE_LOCK();

	return(FromXMLString(CTextTools::UTF8ToANSIStr(xml.GetBuffer(0))));
}

/*!
	XML文字列へ出力
*/
CString CWorkspace::ToXMLString(CString savePath)
{
	SCOPE_LOCK();

	try
	{
		//	保存ノードの取得
		CString key;
		CWorkspaceNode * node = GetSubNode(savePath,key);

		//	保存
		CWorkspaceXMLWriter	writer;
		return(writer.ToString(&m_root, m_className));
	}
	catch(CWorkspaceXMLWriterException err)
	{
		TRACE("XML LoadError : %s\n", err.m_error);
		return("");
	}
}

/*!
	XML文字列から生成
*/
int CWorkspace::FromXMLString(CStringA xml)
{
	SCOPE_LOCK();


	try
	{
		//	クリア
		m_root.Clear();

		//	読み込み
		CWorkspaceXMLReader	reader;
		reader.FromString(&m_root, xml, m_className);
	}
	catch(CXMLTextParserException err)
	{
		TRACE("XML LoadError : %s\n", err.m_error);
		return(-1);
	}
	return(0);
}

/*********************************************************
	初期化など
**********************************************************/
/*!
	全データクリア
*/
void CWorkspace::Clear(LPCSTR _path)
{
	SCOPE_LOCK();
	WRITE_FUNCTION_CHECK();

	CString path = ToNodePath(_path);

	CString key;
	CWorkspaceNode * node = GetSubNode(path, key);

	node->Clear();
}


/*!
	コピー

	srcConfigに別のCWorkspaceクラスを指定すると、別のクラスへコピーできる
*/
void CWorkspace::Copy(LPCSTR _destPath, LPCSTR _srcPath, IWorkspacePtr srcWorkspace)
{
	SCOPE_LOCK();
	WRITE_FUNCTION_CHECK();

	CString destPath = ToNodePath(_destPath);
	CString srcPath = ToNodePath(_srcPath);

	if(srcWorkspace==NULL || srcWorkspace==this)
	{
		CString key;
		CWorkspaceNode * dNode = GetSubNode(destPath, key);
		InternalCopy(dNode,srcPath);
	}
	else
	{
		/*
		//	ダウンキャストを試みる
		CWorkspace *src = dynamic_cast<CWorkspace*>(srcWorkspace);
		if(src != NULL)
		{
			src->Lock();

			CString key;
			CWorkspaceNode * dNode = GetSubNode(destPath, key);
			src->_Copy(dNode, srcPath);

			src->Unlock();
		}
		else
		{
			srcWorkspace->Lock();
			srcWorkspace->Unlock();
		}
		*/

		srcWorkspace->Lock();
		ExternalCopy(srcWorkspace, _srcPath, _destPath);
		srcWorkspace->Unlock();
	}
}


/*!
	リードオンリー
*/
void CWorkspace::SetReadOnly(int readOnly)
{
	SCOPE_LOCK();
	m_readOnly = readOnly;
}



/*********************************************************
	Keyに関する処理
**********************************************************/
/*!
	データの設定
*/
void CWorkspace::SetKeyData(LPCSTR path, LPCSTR data, int noCase)
{
	SCOPE_LOCK();
	WRITE_FUNCTION_CHECK();

	CString key;
	CWorkspaceNode * node = GetSubNode(path,key);

	node->SetKeyData(key, data, noCase);
}


/*!
	データの取得
*/
void CWorkspace::GetKeyData(IStringPtr dest, LPCSTR path, LPCSTR defaultData, int noCase)
{
	SCOPE_LOCK();

	CString key;
	CWorkspaceNode * node = GetSubNode(path,key);

	if(!m_autoSwap.IsEmpty())
		dest->SetString(m_autoSwap->GetKeyDataSwap(this, key, node->GetKeyData(key, defaultData, noCase)));
	else
	{
		if(!m_autoSwapDefault.IsEmpty())
			dest->SetString(node->GetKeyData(key, m_autoSwapDefault->GetKeyDataSwap(this, key, defaultData), noCase));
		else
			dest->SetString(node->GetKeyData(key, defaultData, noCase));
	}
}


/*!
	キーを検索
*/
int CWorkspace::FindKeyData(LPCSTR path, LPCSTR sData, int noCase, int pathCompare)
{
	SCOPE_LOCK();

	CString key;
	CWorkspaceNode * node = GetSubNode(path,key);

	return(node->FindKeyData(sData, noCase, pathCompare));
}


/*!
	データの削除
*/
void CWorkspace::DeleteKey(LPCSTR path)
{
	SCOPE_LOCK();
	WRITE_FUNCTION_CHECK();

	CString key;
	CWorkspaceNode * node = GetSubNode(path,key);

	node->DeleteKey(key);
}


/*!
	キー数を取得
*/
int CWorkspace::GetKeyCount(LPCSTR _path)
{
	SCOPE_LOCK();

	//	パスがノードを示していると仮定する
	CString path = ToNodePath(_path);

	CString key;
	CWorkspaceNode * node = GetSubNode(path,key);

	return(node->GetKeyCount());
}


/*!
	全てのキー名を文字列として取得
*/
int CWorkspace::GetAllKey(LPCSTR _path, IStringArrayPtr list)
{
	SCOPE_LOCK();

	//	パスがノードを示していると仮定する
	CString path = ToNodePath(_path);

	CString key;
	CWorkspaceNode * node = GetSubNode(path,key);

	return(node->GetAllKey(list));
}

/*!
	全てのデータを文字列として取得
*/
int CWorkspace::GetAllData(LPCSTR _path, IStringArrayPtr list)
{
	SCOPE_LOCK();

	//	パスがノードを示していると仮定する
	CString path = ToNodePath(_path);

	CString key;
	CWorkspaceNode * node = GetSubNode(path, key);
	return(node->GetAllData(list));
}


/******************************************************
	サブノードに関する処理
*******************************************************/
/*!
	ノードを削除する
*/
void CWorkspace::DeleteNode(LPCSTR _path)
{
	SCOPE_LOCK();
	WRITE_FUNCTION_CHECK();

	//	パスがノードを示していると仮定する
	CString path = ToNodePath(_path);

	//	最後の::を削除
	path = path.Mid(0,path.GetLength()-2);


	if(path.IsEmpty())
	{
		//	ルートを削除？
		m_root.Clear();
	}
	else
	{
		CString key;
		CWorkspaceNode * node = GetSubNode(path,key);
		node->DeleteNode(key);
	}
}


/*!
	サブノード数を得る
*/
int CWorkspace::GetSubNodeCount(LPCSTR _path)
{
	SCOPE_LOCK();

	//	パスがノードを示していると仮定する
	CString path = ToNodePath(_path);

	CString key;
	CWorkspaceNode * node = GetSubNode(path, key);

	return(node->GetSubNodeCount());
}


/*!
	全てのサブノード名を文字列として取得
*/
int CWorkspace::GetAllSubNode(LPCSTR _path,IStringArrayPtr list)
{
	SCOPE_LOCK();

	//	パスがノードを示していると仮定する
	CString path = ToNodePath(_path);

	CString key;
	CWorkspaceNode * node = GetSubNode(path,key);

	return(node->GetAllSubNode(list));

}



/*********************************************************
	その他の処理
**********************************************************/
/*!
 	ノードパスに変更
 
 	@param path	パス
 	@return		パス
*/
CString CWorkspace::ToNodePath(CString path)
{
	if(path.GetLength() >= 2)
	{
		if(path.Right(2) != "::")
			path += "::";
	}
	else
		path += "::";

	return path;
}

/*!
	サブノードのポインタを取得
*/
CWorkspaceNode *CWorkspace::GetSubNode(CString path, CString &key)
{
	SCOPE_LOCK();

	CWorkspaceNode *node = m_root.GetSubNode(path, key);
	ASSERT(node != NULL);

	return(node);
}


/*!
	コピー内部処理
*/
void CWorkspace::InternalCopy(CWorkspaceNode *dest, CString srcPath)
{
	CString key;
	CWorkspaceNode * sNode = GetSubNode(srcPath,key);

	//	名前以外コピー
	CString	name = dest->GetNodeName();
	*dest = *sNode;
	dest->SetNodeName(name);
}


/*!
	コピー内部処理
*/
void CWorkspace::ExternalCopy(IWorkspace *src, CString srcPath, CString destPath)
{
	//
	//	全キーとデータをコピー
	//
	CStringArray		keys, datas;
	CIStringArrayWrap	_keys(keys), _datas(datas);

	//	キー取得
	src->GetAllKey(srcPath, &_keys);

	//	データ取得
	src->GetAllData(srcPath, &_datas);

	//	対象ノードへキーをコピー
	CString key;
	CWorkspaceNode * dNode = GetSubNode(destPath, key);
	dNode->ClearAndSetKeys(keys, datas);


	//
	//	サブノードをコピー
	//
	CStringArray		nodes;
	CIStringArrayWrap	_nodes(nodes);

	//	ノードリスト取得
	src->GetAllSubNode(srcPath, &_nodes);

	//	サブノードのコピー
	for(int i=0;i<nodes.GetCount();i++)
	{
		dNode->AddSubNode(nodes[i]);

		//	再帰
		ExternalCopy(src, srcPath + nodes[i] + "::", destPath + nodes[i] + "::");
	}
}
