/*/////////////////////////////////////////////////////////////////////////////
// confman 設定情報入出力ライブラリ
// confman.cc confmanインタフェース関数の実体
*/

/* ヘッダファイル */
#include "confman.h"
#include "ConfImp.h"
#include <limits.h>
#include <string>
#include <wchar.h>
#include <widec.h>
using namespace std;

/* マクロの定義 */
#define IMP( p ) ( (CConfImp*)( p->pConf ) )
#define SMB( p ) ( (map<wstring,ULONG>*)( p->smb ) )

/* CONFMANを生成 */
CONFMAN confman_CreateConf( const char *FileName )
{
	CONFMAN p;

	/* 構造体の領域を確保 */
	p = (CONFMAN)malloc( sizeof( tagConf ) );
	if ( p == NULL ) return NULL;

	/* クラスを構築 */
	p->pConf = (void*)new CConfImp();
	if ( p->pConf == NULL ){
		free( p );		/* クラスの構築に失敗したら */
		return NULL;	/* 領域を開放し、NULLを返す */
	}

	/* ファイル名を登録 */
	IMP(p)->ConfImp_SetFileName( FileName );

	p->smb = NULL;	/* 使わないうちはNULLを格納 */
	return p;
}

/* 読み込み指示 */
CF_BOOL confman_Open( CONFMAN p )
{
	return IMP(p)->ConfImp_Open();
}


/* 入力 */

CF_BOOL confman_GetString(	CONFMAN p,
				const wchar_t *SectionName,
				const wchar_t *KeyName,
				wchar_t *buf,
				int length )
{
	return IMP( p )->ConfImp_GetString( SectionName, KeyName, buf, length );
}

/* 出力 */

CF_BOOL confman_SetString(	CONFMAN p,
				const wchar_t *SectionName,
				const wchar_t *KeyName,
				const wchar_t *value )
{
	return IMP( p )->ConfImp_SetString( SectionName, KeyName, value );
}

/* ファイルを閉じる */
CF_BOOL confman_Close( CONFMAN p )
{
	CF_BOOL r;

	/* ファイルに保存 */
	r = IMP( p )->ConfImp_Close( );

	/* オブジェクトを解放 */
	delete IMP(p);

	/* シンボルが使用されていた場合はオブジェクトを開放 */
	if ( SMB(p) != NULL )
		delete SMB(p);

	/* tagConf型のメモリ領域を開放 */
	free( p );
	return r;
}

// 更新フラグを取得する
CF_BOOL confman_GetModify( CONFMAN p )
{
	return IMP( p )->ConfImp_GetModifyFlag();
}

// 更新フラグを変更する
void confman_SetModify( CONFMAN p, CF_BOOL b )
{
	IMP( p )->ConfImp_SetModifyFlag( b );
}

// セクション名リストを取得
CF_BOOL confman_GetSectionList( CONFMAN p, wchar_t *buf, int Length )
{
	wstring w;
	CF_BOOL r;

	r = IMP( p )->ConfImp_GetSectionList( w, Length );
	memcpy( buf, w.c_str(), w.size() * sizeof( wchar_t ) );
	buf[Length-1] = L'\0';	// 如何なる場合も必ず最後にはNULLをつける
	return r;
}

/* キー名のリストを取得 */
CF_BOOL confman_GetKeyList( CONFMAN p, const wchar_t *SectionName, wchar_t *buf, int Length )
{
	wstring w;
	CF_BOOL r;

	r = IMP( p )->ConfImp_GetKeyList( SectionName, w, Length );
	memcpy( buf, w.c_str(), w.size() * sizeof( wchar_t ) );
	buf[Length-1] = L'\0';	// 如何なる場合も必ず最後にはNULLをつける
	return r;
}


/* セクションの追加 */
CF_BOOL confman_AddSection( CONFMAN p, const wchar_t *SectionName )
{
	return IMP( p )->ConfImp_AddSection( SectionName );
}

/* キーの追加 */
CF_BOOL confman_AddKey( CONFMAN p, const wchar_t *SectionName, const wchar_t *KeyName, const wchar_t *Value )
{
	return IMP( p )->ConfImp_AddKey( SectionName, KeyName, Value );
}

/* セクションを削除 */
CF_BOOL confman_RemoveSection( CONFMAN p, const wchar_t *SectionName )
{
	return IMP( p )->ConfImp_RemoveSection( SectionName );
}


/* キーの削除 */
CF_BOOL confman_RemoveKey( CONFMAN p, const wchar_t *SectionName, const wchar_t *KeyName )
{
	return IMP( p )->ConfImp_RemoveKey( SectionName, KeyName );
}


/* エラー値の取得 */
unsigned long confman_GetLastError( CONFMAN p )
{
	return IMP( p )->ConfImp_GetLastError();
}

/* エラー値のクリア */
void confman_ClearLastError( CONFMAN p )
{
	IMP( p )->ConfImp_ClearLastError();
}

/* 拡張機能 */
/* シンボルの追加 */
CF_BOOL exconf_AddSymbol( CONFMAN p, const wchar_t *symbol, ULONG val )
{
	/* まだ使われていなければ領域を確保 */
	if ( p->smb == NULL ){
		p->smb = (void*)new map<wstring, ULONG>;
		/* 領域確保に失敗したら偽を返す */
		if ( p->smb == NULL )
			return CF_FALSE;
	}

	/* シンボルと値を登録 */
	SMB(p)->insert( pair<wstring, ULONG>( (wstring)symbol, val ) );
	return CF_TRUE;
}

/* キーに対応する文字列からシンボル値を取得 */
ULONG exconf_GetSymbol( CONFMAN p, const wchar_t *SectionName, const wchar_t *KeyName )
{
	wstring w;

	if ( SMB(p) == NULL ){
		// シンボル機能が未使用
		IMP(p)->ConfImp_SetError(ECF_UNUSESYMBOL);
		return ULONG_MAX;
	}

	/* キーを検索 */
	if ( IMP(p)->ConfImp_GetSTLString( SectionName, KeyName, w ) == CF_FALSE )
		return ULONG_MAX;	/* キーが見つからない */

	/* キーに対応するシンボル値を返す */
	return exconf_StrToVal( p, w.c_str() );
}

/* シンボルデータを解放 */
void exconf_ReleaseSymbol( CONFMAN p )
{
	if ( SMB(p) != NULL ){
		delete SMB(p);
		p->smb = NULL;
	}
}

/* 文字列からシンボル値を取得 */
ULONG exconf_StrToVal( CONFMAN p, const wchar_t *Symbol )
{
	map<wstring,ULONG>::iterator i;

	/* シンボルを検索 */
	i = SMB(p)->find( (wstring)Symbol );
	if ( i == SMB(p)->end() ){
		// シンボル名が見つからない
		IMP(p)->ConfImp_SetError(ECF_NOSYMBOL);
		return ULONG_MAX;
	}
	return i->second;
}

/* 数値で取得 */
CF_BOOL exconf_GetInt( CONFMAN p, const wchar_t *SectionName, const wchar_t *KeyName, int *c )
{
	wstring w;
	if ( !IMP(p)->ConfImp_GetSTLString( SectionName, KeyName, w ) )
		return CF_FALSE;
	(*c) = watoi( w.c_str() );
	return CF_TRUE;
}

/* 内部セクション名リストを作成 */
void* exconf_CreateInternalSectionList( CONFMAN p, int *Length )
{
	wstring *s;
	s = new wstring;
	if ( s == NULL ) return NULL;	// stringの構築に失敗
	if ( !IMP( p )->ConfImp_GetSectionList( *s, -1 ) ){	// リストを取得
		delete s;		// 失敗
		return NULL;
	}

	(*Length) = s->size();	// サイズを格納
	return (void*)s;		// アドレスを返す
}

/* 内部キー名リストを作成 */
void* exconf_CreateInternalKeyList( CONFMAN p, const wchar_t *SectionName, int *Length )
{
	wstring *s;
	s = new wstring;
	if ( s == NULL ) return NULL;	// stringの構築に失敗
	if ( !IMP( p )->ConfImp_GetKeyList( SectionName, *s, -1 ) ){	// リストを取得
		delete s;		// 失敗
		return NULL;
	}

	(*Length) = s->size();	// サイズを格納
	return (void*)s;		// アドレスを返す
}

/* 内部リストを取得 */
void exconf_GetInternalList( void *h, wchar_t *buf, int Length )
{
	wstring *p = ((wstring*)h);			// キャストする
	int l = Length < p->size() ? Length : p->size();	// 小さいほう

	memcpy( buf, p->c_str(), l * sizeof( wchar_t ) );	// バッファに格納
	buf[l-1] = L'\0';					// 最後がNULL２つになることを保証
	buf[l-2] = L'\0';
	delete p;							// stringはここで開放する
}

/* 内部で保持している値のアドレスを取得 */
const wchar_t* exconf_GetConstStr( CONFMAN p, const wchar_t *SectionName, const wchar_t *KeyName )
{
	return IMP( p )->ConfImp_GetConstStr( SectionName, KeyName );
}

