////////////////////////////////////////////////////////////////////////////
// PluginFunc.cc プラグインに提供する機能を実装
//
////////////////////////////////////////////////////////////////////////////

#include "PluginFunc.h"
#include "PluginFuncID.h"
#include "Plugin.h"
#include "TaEditShell.h"
#include "CompoundStr.h"

PFT_BOOL PFunc_GetChar( unsigned long argLP, unsigned long argCP, wchar_t *pC );
PFT_BOOL PFunc_SetChar( unsigned long argLP, unsigned long argCP, wchar_t c );
PFT_BOOL PFunc_GetString( unsigned long argSLP, unsigned long argSCP, unsigned long argELP, unsigned long argECP, wchar_t *pBuf, unsigned long BufLength );
PFT_BOOL PFunc_Replace( unsigned long argSLP, unsigned long argSCP, unsigned long argELP, unsigned long argECP, const wchar_t *pBuf );
PFT_BOOL PFunc_GetLineCount( unsigned long *pCnt );
PFT_BOOL PFunc_GetCharCount( unsigned long argLP, unsigned long *pCnt );
PFT_BOOL PFunc_GetCursorPosition( unsigned long *pLP, unsigned long *pCP );
PFT_BOOL PFunc_SetCursorPosition( unsigned long LP, unsigned long CP );
PFT_BOOL PFunc_GetSelectionRange( unsigned long *argSLP, unsigned long *argSCP, unsigned long *argELP, unsigned long *argECP );
PFT_BOOL PFunc_SetSelectionRange( unsigned long argSLP, unsigned long argSCP, unsigned long argELP, unsigned long argECP );
const wchar_t* PFunc_GetConfigValue( const wchar_t *pName );
const char* PFunc_GetFileName();
void PFunc_ShowInformationMsgBox( const wchar_t *pMsg );
int PFunc_ShowQuestionMsgBox( const wchar_t *pMsg, PFT_BOOL ShowCancel );
void PFunc_ShowErrorMsgBox( const wchar_t *pMsg );
PFT_BOOL PFunc_GetModifiedFlg();
int PFunc_GetVersion();
int PFunc_GetGetExtendInfoCount();
PFT_BOOL PFunc_GetExtendInfo( unsigned long argLP, unsigned long idx, PFT_BOOL* pFlg );
PFT_BOOL PFunc_SetExtendInfo( unsigned long argLP, unsigned long idx, PFT_BOOL Flg );
PFT_BOOL PFunc_SaveFile();
PFT_BOOL PFunc_OpenFile( const char* pFileName );
PFT_BOOL PFunc_OpenFileNewWindow( const char* pFileName );
void* PFunc_AllocWorkMemory( unsigned long size, const wchar_t* pName, PFT_BOOL IsGlobal );
void* PFunc_FindWorkMemory( const wchar_t* pName, PFT_BOOL IsGlobal );
void PFunc_FreeWorkMemory( const wchar_t* pName, PFT_BOOL IsGlobal );
PFT_BOOL PFunc_IsConstructionMode();
PFT_BOOL PFunc_SetConstruction( PFT_BOOL ShowMessage );
PFT_BOOL PFunc_SetStandalone( PFT_BOOL ShowMessage );

// 関数のアドレスを取得
void* GetFunctionAddress( unsigned int ID )
{
	switch ( ID ) {
	case PFID_GETCHAR:
		return reinterpret_cast< void* >( PFunc_GetChar );
	case PFID_SETCHAR:
		return reinterpret_cast< void* >( PFunc_SetChar );
	case PFID_GETSTRING:
		return reinterpret_cast< void* >( PFunc_GetString );
	case PFID_REPLACE:
		return reinterpret_cast< void* >( PFunc_Replace );
	case PFID_GETLINECOUNT:
		return reinterpret_cast< void* >( PFunc_GetLineCount );
	case PFID_GETCHARCOUNT:
		return reinterpret_cast< void* >( PFunc_GetCharCount );
	case PFID_GETCURSORPOSITION:
		return reinterpret_cast< void* >( PFunc_GetCursorPosition );
	case PFID_SETCURSORPOSITION:
		return reinterpret_cast< void* >( PFunc_SetCursorPosition );
	case PFID_GETSELECTIONRANGE:
		return reinterpret_cast< void* >( PFunc_GetSelectionRange );
	case PFID_SETSELECTIONRANGE:
		return reinterpret_cast< void* >( PFunc_SetSelectionRange );
	case PFID_GETCONFIGVALUE:
		return reinterpret_cast< void* >( PFunc_GetConfigValue );
	case PFID_GETFILENAME:
		return reinterpret_cast< void* >( PFunc_GetFileName );
	case PFID_SHOWINFORMATIONMSGBOX:
		return reinterpret_cast< void* >( PFunc_ShowInformationMsgBox );
	case PFID_SHOWQUESTIONMSGBOX:
		return reinterpret_cast< void* >( PFunc_ShowQuestionMsgBox );
	case PFID_SHOWERRORMSGBOX:
		return reinterpret_cast< void* >( PFunc_ShowErrorMsgBox );
	case PFID_GETMODIFIEDFLG:
		return reinterpret_cast< void* >( PFunc_GetModifiedFlg );
	case PFID_GETVERSION:
		return reinterpret_cast< void* >( PFunc_GetVersion );
	case PFID_GETEXTENDINFOCOUNT:
		return reinterpret_cast< void* >( PFunc_GetGetExtendInfoCount );
	case PFID_GETEXTENDINFO:
		return reinterpret_cast< void* >( PFunc_GetExtendInfo );
	case PFID_SETEXTENDINFO:
		return reinterpret_cast< void* >( PFunc_SetExtendInfo );
	case PFID_SAVEFILE:
		return reinterpret_cast< void* >( PFunc_SaveFile );
	case PFID_OPENFILE:
		return reinterpret_cast< void* >( PFunc_OpenFile );
	case PFID_OPENFILENEWWINDOW:
		return reinterpret_cast< void* >( PFunc_OpenFileNewWindow );
	case PFID_ALLOCWORKMEMORY:
		return reinterpret_cast< void* >( PFunc_AllocWorkMemory );
	case PFID_FINDWORKMEMORY:
		return reinterpret_cast< void* >( PFunc_FindWorkMemory );
	case PFID_FREEWORKMEMORY:
		return reinterpret_cast< void* >( PFunc_FreeWorkMemory );
	case PFID_ISCONSTRUCTIONMODE:
		return reinterpret_cast< void* >( PFunc_IsConstructionMode );
	case PFID_SETCONSTRUCTION:
		return reinterpret_cast< void* >( PFunc_SetConstruction );
	case PFID_SETSTANDALONE:
		return reinterpret_cast< void* >( PFunc_SetStandalone );

	}
	return NULL;
}

// 指定した位置の文字を取得する
PFT_BOOL PFunc_GetChar( unsigned long argLP, unsigned long argCP, wchar_t *pC )
{
	if ( NULL == pC ) return PFT_FALSE;
	const CTaEditDoc *pDoc = m_TaEditShell->GetDocument();
	if ( NULL == pDoc ) return PFT_FALSE;
		const T_LineData& rData = pDoc->RefData();
	if ( argLP < 0 || argLP >= rData.size() ) return PFT_FALSE;
	if ( argCP < 0 || argCP > rData[ argLP ].length() ) return PFT_FALSE;
	if ( argCP < rData[ argLP ].length() )
		(*pC) = pDoc->RefData()[ argLP ][ argCP ].moji;
	else
		(*pC) = L'\n';
	return PFT_TRUE;
}

// 指定した文字を置換する
PFT_BOOL PFunc_SetChar( unsigned long argLP, unsigned long argCP, wchar_t c )
{
	wchar_t v[2] = { c, L'\0' };
	const CTaEditDoc *pDoc = m_TaEditShell->GetDocument();
	if ( NULL == pDoc ) return PFT_FALSE;
	const T_LineData& rData = pDoc->RefData();
	if ( argLP < 0 || argLP >= rData.size() ) return PFT_FALSE;
	if ( argCP < 0 || argCP > rData[ argLP ].length() ) return PFT_FALSE;
	if ( argLP == rData.size() - 1 && argCP == rData[ argLP ].length() + 1 ) return PFT_FALSE;
	if ( argCP < rData[ argLP ].length() )
		return PFunc_Replace( argLP, argCP, argLP, argCP + 1, v );
	else
		return PFunc_Replace( argLP, argCP, argLP + 1, 0, v );
}

// 指定された範囲の文字列を取得する
PFT_BOOL PFunc_GetString( unsigned long argSLP, unsigned long argSCP, unsigned long argELP, unsigned long argECP, wchar_t *pBuf, unsigned long BufLength )
{
	if ( NULL == pBuf ) return PFT_FALSE;
	if ( BufLength <= 0 ) return PFT_TRUE;
	const CTaEditDoc *pDoc = m_TaEditShell->GetDocument();
	if ( NULL == pDoc ) return PFT_FALSE;
	const T_LineData& rData = pDoc->RefData();
	if ( argSLP < 0 || argSLP >= rData.size() ) return PFT_FALSE;
	if ( argSCP < 0 || argSCP > rData[ argSLP ].length() ) return PFT_FALSE;
	if ( argELP < 0 || argELP >= rData.size() ) return PFT_FALSE;
	if ( argECP < 0 || argECP > rData[ argELP ].length() ) return PFT_FALSE;
	const wchar_t *ep = pBuf + BufLength - 1;
	wchar_t *wp = pBuf;
	unsigned long wcp = argSCP;
	unsigned long wlp = argSLP;

	while ( ( wlp < argELP || wlp == argELP && wcp < argECP ) && wp < ep ) {
		if ( wcp < rData[wlp].length() ) {
			(*wp) = rData[ wlp ][ wcp ].moji;
			wcp++;
		}
		else {
			(*wp) = L'\n';
			wcp = 0;
			wlp++;
		}
		wp++;
	}
	(*wp) = L'\0';
	return PFT_TRUE;
}

// 指定した範囲の文字列を置換する
PFT_BOOL PFunc_Replace( unsigned long argSLP, unsigned long argSCP, unsigned long argELP, unsigned long argECP, const wchar_t *pBuf )
{
	if ( NULL == pBuf ) return PFT_FALSE;
	const CTaEditDoc *pDoc = m_TaEditShell->GetDocument();
	if ( NULL == pDoc ) return PFT_FALSE;
	const T_LineData& rData = pDoc->RefData();
	if ( argSLP < 0 || argSLP >= rData.size() ) return PFT_FALSE;
	if ( argSCP < 0 || argSCP > rData[ argSLP ].length() ) return PFT_FALSE;
	if ( argELP < 0 || argELP >= rData.size() ) return PFT_FALSE;
	if ( argECP < 0 || argECP > rData[ argELP ].length() ) return PFT_FALSE;
	CPlugin &rPlugin = m_TaEditShell->RefPluginMgr();

	T_SelRange Range = T_SelRange( T_CurPos( argSLP, argSCP ), T_CurPos( argELP, argECP ) );
	if ( rPlugin.Replace( Range, pBuf ) )
		return PFT_TRUE;
	else
		return PFT_FALSE;
}

// 行数を取得する
PFT_BOOL PFunc_GetLineCount( unsigned long *pCnt )
{
	if ( NULL == pCnt ) return PFT_FALSE;
	const CTaEditDoc *pDoc = m_TaEditShell->GetDocument();
	if ( NULL == pDoc ) return PFT_FALSE;
	(*pCnt) = pDoc->RefData().size();
	return PFT_TRUE;
}

// 指定した行の文字数を取得する
PFT_BOOL PFunc_GetCharCount( unsigned long argLP, unsigned long *pCnt )
{
	if ( NULL == pCnt ) return PFT_FALSE;
	const CTaEditDoc *pDoc = m_TaEditShell->GetDocument();
	if ( NULL == pDoc ) return PFT_FALSE;
	if ( argLP < 0 || argLP >= pDoc->RefData().size() ) return PFT_FALSE;
	(*pCnt) = pDoc->RefData()[ argLP ].length();
	if ( argLP < pDoc->RefData().size() - 1 )
		(*pCnt)++;	// 行末の改行コードを含める
	return PFT_TRUE;
}

// 現在のカーソル位置を取得する
PFT_BOOL PFunc_GetCursorPosition( unsigned long *pLP, unsigned long *pCP )
{
	if ( !( pLP && pCP ) ) return PFT_FALSE;
	const T_CurPos& rCurPos = m_TaEditShell->RefPluginMgr().GetCurPos();
	(*pLP) = rCurPos.GetLine();
	(*pCP) = rCurPos.GetCPos();
	return PFT_TRUE;
}

// カーソル位置の設定
PFT_BOOL PFunc_SetCursorPosition( unsigned long LP, unsigned long CP )
{
	CPlugin &rPlugin = m_TaEditShell->RefPluginMgr();
	if ( rPlugin.SetCurPos_SelRange( T_CurPos( LP, CP ), rPlugin.GetSelRange() ) )
		return PFT_TRUE;
	else
		return PFT_FALSE;
}

// 現在の選択範囲を取得する
PFT_BOOL PFunc_GetSelectionRange( unsigned long *argSLP, unsigned long *argSCP, unsigned long *argELP, unsigned long *argECP )
{
	if ( !( argSLP && argSCP && argELP && argECP ) ) return PFT_FALSE;
	const T_SelRange& rSelRange = m_TaEditShell->RefPluginMgr().GetSelRange();
	(*argSLP) = rSelRange.GetSPos().GetLine();
	(*argSCP) = rSelRange.GetSPos().GetCPos();
	(*argELP) = rSelRange.GetEPos().GetLine();
	(*argECP) = rSelRange.GetEPos().GetCPos();
	return PFT_TRUE;
}

// 選択範囲の設定
PFT_BOOL PFunc_SetSelectionRange( unsigned long argSLP, unsigned long argSCP, unsigned long argELP, unsigned long argECP )
{
	CPlugin &rPlugin = m_TaEditShell->RefPluginMgr();
	T_SelRange selrange( T_CurPos( argSLP, argSCP ), T_CurPos( argELP, argECP ) );
	if ( rPlugin.SetCurPos_SelRange( rPlugin.GetCurPos(), selrange ) )
		return PFT_TRUE;
	else
		return PFT_FALSE;
}

// 名前に対応した設定情報を取得する
const wchar_t* PFunc_GetConfigValue( const wchar_t *pName )
{
	if ( NULL == pName ) return NULL;
	return m_TaEditShell->RefPluginMgr().GetCurPluginConfig( pName );
}

// ファイル名を取得
const char* PFunc_GetFileName()
{
	return m_TaEditShell->GetDocument()->GetFileName().c_str();
}

// 情報メッセージボックスの表示
void PFunc_ShowInformationMsgBox( const wchar_t *pMsg )
{
	if ( NULL == pMsg ) return ;
	CCompoundStr str( pMsg );
	m_TaEditShell->ShowInformationMsgBox( str );
}

// 質問メッセージボックスの表示
// ShowCancel : 真にした場合、「キャンセル」ボタンが表示される。
// 戻り値：「はい」が押された場合は1
// 　　　：「いいえ」の場合は2
// 　　　：「キャンセル」の場合は3
// 　　　：エラーの場合は0
int PFunc_ShowQuestionMsgBox( const wchar_t *pMsg, PFT_BOOL ShowCancel )
{
	if ( NULL == pMsg ) return 0;
	CCompoundStr str( pMsg );
	return m_TaEditShell->ShowQuestionMsgBox( str, ShowCancel ? true : false );
}

// エラーメッセージボックスの表示
void PFunc_ShowErrorMsgBox( const wchar_t *pMsg )
{
	if ( NULL == pMsg ) return ;
	CCompoundStr str( pMsg );
	m_TaEditShell->ShowErrorMsgBox( str );
}

// 変更フラグを取得
PFT_BOOL PFunc_GetModifiedFlg()
{
	bool f = m_TaEditShell->GetDocument()->GetIsModify();
	return f ? PFT_TRUE : PFT_FALSE;
}

// エディタのバージョンを取得
int PFunc_GetVersion()
{
	return TAEDIT_VERSION;
}

// 利用可能な拡張情報の数を取得
int PFunc_GetGetExtendInfoCount()
{
	VClsPtr< CConfigInfo > pConf = m_TaEditShell->GetConfigInfo();
	return pConf->GetExInfoColumnCount();
}

// 行ごとの拡張情報を取得
PFT_BOOL PFunc_GetExtendInfo( unsigned long argLP, unsigned long idx, PFT_BOOL* pFlg )
{
	if ( NULL == pFlg ) return PFT_FALSE;
	const CTaEditDoc *pDoc = m_TaEditShell->GetDocument();
	if ( NULL == pDoc ) return PFT_FALSE;
	if ( argLP < 0 || argLP >= pDoc->RefData().size() ) return PFT_FALSE;
	if ( idx < 0 && idx >= PFunc_GetGetExtendInfoCount() ) return PFT_FALSE;
	(*pFlg) = pDoc->RefData()[argLP].GetExtendInfo( idx );
	return PFT_TRUE;
}

// 行ごとの拡張情報を設定
PFT_BOOL PFunc_SetExtendInfo( unsigned long argLP, unsigned long idx, PFT_BOOL Flg )
{
	CPlugin &rPlugin = m_TaEditShell->RefPluginMgr();
	const CTaEditDoc *pDoc = m_TaEditShell->GetDocument();
	if ( NULL == pDoc ) return PFT_FALSE;
	if ( argLP < 0 || argLP >= pDoc->RefData().size() ) return PFT_FALSE;
	if ( idx < 0 && idx >= PFunc_GetGetExtendInfoCount() ) return PFT_FALSE;
	return rPlugin.SetExtendInfo( argLP, idx, Flg );
}

// ファイルを保存する
PFT_BOOL PFunc_SaveFile()
{
	CPlugin &rPlugin = m_TaEditShell->RefPluginMgr();
	bool r = m_TaEditShell->SaveFileProcedure();
	if ( r ) rPlugin.ClearModifiedFlg();
	return r ? PFT_TRUE : PFT_FALSE;
}

// 現在のウインドウでファイルを開く
PFT_BOOL PFunc_OpenFile( const char* pFileName )
{
	if ( NULL == pFileName ) return FALSE;
	CPlugin &rPlugin = m_TaEditShell->RefPluginMgr();
	string wFileName ( pFileName );
	bool r = m_TaEditShell->OpenFile( wFileName );
	if ( r ) rPlugin.ClearModifiedFlg();
	return r ? PFT_TRUE : PFT_FALSE;
}

// 新しいウインドウでファイルを開く
PFT_BOOL PFunc_OpenFileNewWindow( const char* pFileName )
{
	VClsPtr< CConfigInfo > pConf = m_TaEditShell->GetConfigInfo();
	string wFileName( pFileName );
	int wLine;

	if ( NULL == pFileName ) return PFT_FALSE;

	// カーソルは先頭の行に設定する
	wLine = pConf->GetLineNumberOrigin();
	return m_TaEditShell->OpenFileInNewWindow( wFileName.c_str(), wLine ) ? PFT_TRUE : PFT_FALSE;
}

// 作業用メモリの割り当て
void* PFunc_AllocWorkMemory( unsigned long size, const wchar_t* pName, PFT_BOOL IsGlobal )
{
	if ( size <= 0 || NULL == pName ) return NULL;
	CPlugin &rPlugin = m_TaEditShell->RefPluginMgr();
	if ( IsGlobal )
		return rPlugin.GetWorkMemoryMgr().Alloc( size, pName, NULL );
	else
		return rPlugin.GetWorkMemoryMgr().Alloc( size, pName, rPlugin.GetPluginID() );
}

// 作業用メモリの取得
void* PFunc_FindWorkMemory( const wchar_t* pName, PFT_BOOL IsGlobal )
{
	if ( NULL == pName ) return NULL;
	CPlugin &rPlugin = m_TaEditShell->RefPluginMgr();
	if ( IsGlobal )
		return rPlugin.GetWorkMemoryMgr().Find( pName, NULL );
	else
		return rPlugin.GetWorkMemoryMgr().Find( pName, rPlugin.GetPluginID() );
}

// 作業用メモリの解放
void PFunc_FreeWorkMemory( const wchar_t* pName, PFT_BOOL IsGlobal )
{
	if ( NULL == pName ) return ;
	CPlugin &rPlugin = m_TaEditShell->RefPluginMgr();
	if ( IsGlobal )
		return rPlugin.GetWorkMemoryMgr().Free( pName, NULL );
	else
		return rPlugin.GetWorkMemoryMgr().Free( pName, rPlugin.GetPluginID() );
}

// コンストラクション・モードか否かを取得する
PFT_BOOL PFunc_IsConstructionMode()
{
	return m_TaEditShell->IsConstructionMode() ? PFT_TRUE : PFT_FALSE;
}

// コンストラクション・モードに変更する
PFT_BOOL PFunc_SetConstruction( PFT_BOOL ShowMessage )
{
	CErrorBool r = m_TaEditShell->SetConstructionMode();
	if ( ShowMessage ) m_TaEditShell->ProcErrorMsg( r );
	return r ? PFT_TRUE : PFT_FALSE;
}

// スタンドアロン・モードに変更する
PFT_BOOL PFunc_SetStandalone( PFT_BOOL ShowMessage )
{
	CErrorBool r = m_TaEditShell->SetStandaloneMode();
	if ( ShowMessage ) m_TaEditShell->ProcErrorMsg( r );
	return r ? PFT_TRUE : PFT_FALSE;
}
