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

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

//	標準名
#define	DEFAULT_CLASS_TYPE	"CConfig"

//	リードオンリーフラグ確認
#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)
{
	//	自動置き換えを削除
	for(int i=0;i<m_autoSwap.GetSize();i++)
		m_autoSwap[i]->Delete();
	m_autoSwap.RemoveAll();
}


/*********************************************************
	アクセス可能な関数
**********************************************************/
/*!
	アクセスクラスを取得する
*/
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::MBStrToUTF8Str(ToXMLString(savePath).GetBuffer(0)));
}

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

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

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

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

		//	保存
		CWorkspaceXMLWriter	writer;
		return(writer.ToString(&m_root, m_className));
	}
	catch(CXMLTextParserException 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::SetReadOnly(int readOnly)
{
	SCOPE_LOCK();
	m_readOnly = readOnly;
}

/*!
	自動置き換え(古い順に置き換え実行)
*/
void CWorkspace::AddAutoSwap(IWorkspaceAutoSwapPtr autoSwap)
{
	SCOPE_LOCK();

	DelAutoSwap(autoSwap);
	m_autoSwap.Add(autoSwap);
};

/*!
	自動置き換え解除
*/
void CWorkspace::DelAutoSwap(IWorkspaceAutoSwapPtr autoSwap)
{
	SCOPE_LOCK();

	for(int i=0;i<m_autoSwap.GetSize();i++)
	{
		if(m_autoSwap[i] == autoSwap)
		{
			m_autoSwap.RemoveAt(i);
			break;
		}
	}
};


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

	path = ToNodePath(path);

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

	node->Clear();
}


/*!
	コピー

	srCWorkspaceに別のCWorkspaceクラスを指定すると、別のクラスへコピーできる
*/
void CWorkspace::Copy(CString destPath, CString srcPath, CWorkspace* srCWorkspace)
{
	SCOPE_LOCK();
	WRITE_FUNCTION_CHECK();

	destPath = ToNodePath(destPath);
	srcPath = ToNodePath(srcPath);

	if(srCWorkspace==NULL || srCWorkspace==this)
	{
		CString key;
		CWorkspaceNode * dNode = GetSubNode(destPath,key);
		_Copy(dNode,srcPath);
	}
	else
	{
		srCWorkspace->m_scopeLock.Lock();
		CString key;
		CWorkspaceNode * dNode = GetSubNode(destPath,key);
		srCWorkspace->_Copy(dNode,srcPath);
		srCWorkspace->m_scopeLock.Unlock();
	}

}



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

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

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


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

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

	if(!m_autoSwap.IsEmpty())
	{
		CString	data = node->GetKeyData(key, defaultData, noCase);
		for(int i=0;i<m_autoSwap.GetCount();i++)
			data = m_autoSwap[i]->SwapString(key, data);
		return(data);
	}
	else
		return(node->GetKeyData(key, defaultData, noCase));
}


/*!
	キーの存在を確認
*/
int CWorkspace::KeyIsExist(CString path,int noCase)
{
	SCOPE_LOCK();

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

	return node->KeyIsExist(key, noCase);
}


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

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

	node->DeleteKey(key, noCase);
}


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

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

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

	return(node->GetKeyCount());
}


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

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

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

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


/*!
	全てのキーをコピーする
*/
void CWorkspace::CopyAllKeys(CString path,CKeyDataArray &keyData)
{
	SCOPE_LOCK();

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

	sNode->CopyAllKeys(keyData);
}

/*!
	文字列中のキー名をデータに置き換えた文字列を取得する
*/
CString CWorkspace::GetKeySwapString(CString path, CString str, CString noData, IWorkspaceAutoSwapPtr tempSwap)
{
	SCOPE_LOCK();

	if(tempSwap != NULL)
		AddAutoSwap(tempSwap);

	CString key;
	CWorkspaceNode * node = GetSubNode(path,key);
	CString	data = node->GetKeySwapString(str,noData);

	if(tempSwap != NULL)
		DelAutoSwap(tempSwap);

	return(data);
}

/////////////////////////////////////////////////////////////////////////////////////
//	Keyに関する処理 - WorkspaceStringList
/////////////////////////////////////////////////////////////////////////////////////
/*!
	キーを検索
*/
int CWorkspace::FindKeyData(CString path, CString sData, int noCase)
{
	SCOPE_LOCK();

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

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

/*!
	キーを検索
*/
int CWorkspace::FindKeyDataPath(CString path, CString fPath, int eqPath)
{
	SCOPE_LOCK();

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

	return(node->FindKeyDataPath(fPath, eqPath));
}



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

	//	パスがノードを示していると仮定する
	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(CString path)
{
	SCOPE_LOCK();

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

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

	return(node->GetSubNodeCount());
}


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

	//	パスがノードを示していると仮定する
	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::_Copy(CWorkspaceNode *dest, CString srcPath)
{
	SCOPE_LOCK();

	CString key;
	CWorkspaceNode * sNode = GetSubNode(srcPath,key);

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