/*!
	ManagedInterfaceAccessArgStack.h

	関数呼び出しのための引数受け渡しシステムを提供する
	引数は、呼び出し側が IManagedInterfaceArgStack を引き渡す。

	呼び出し側用
*/
#pragma once
#include "ManagedInterfaceExchangeInterfaces.h"
#include "BinaryData.h"
#include "WorkspaceAccess.h"

/************************************************************************************/
//	クラス用受け渡しラッパ(関数呼び出し側用)
//	C標準形式以外のデータ型は、クラスラッパを使用し、インタフェースを渡す
/************************************************************************************/
/*!
	インターフェースマッパ例外
*/
class CManagedInterfaceException
{
public:
	//!	コンストラクタ
	CManagedInterfaceException(int type = MI_EXCEPTION_TYPE_NOEXCEPTION)
	{
		m_type = type;
	}

	//!	タイプ取得
	int GetExceptionType() { return m_type; };

protected:
	///////////////////////////////////////////////////////////////////////////////
	//	メンバ変数
	///////////////////////////////////////////////////////////////////////////////
	//!	例外タイプ
	int	m_type;
};


/*!
	CStringラッパクラス
*/
class CManagedInterfaceAccessArgStringWarp : public IString
{
public:
	//!	コンストラクタ
	CManagedInterfaceAccessArgStringWarp() { m_str = NULL; };

	//!	設定
	void SetArg(CString *str) { m_str = str; };

	//!	文字列を設定
	virtual void SetString(LPCSTR str) { *m_str = str; };

	//!	取得
	virtual LPCSTR GetString() { return *m_str; };

	//!	空？
	int IsEmpty() { return m_str->IsEmpty(); };

protected:
	CString	*m_str;
};


/*!
	CBinaryDataラッパクラス
*/
class CManagedInterfaceAccessArgBinaryWarp : public IBinaryData
{
public:
	//!	コンストラクタ
	CManagedInterfaceAccessArgBinaryWarp() { m_bd = NULL; };

	//!	設定
	void SetArg(CBinaryData *bd) { m_bd = bd; };

	//!	サイズ変更
	virtual void ReSize(int size) { m_bd->ReSize(size); };

	//!	サイズ取得
	virtual int GetSize() { return m_bd->GetSize(); };

	//!	保持しているデータポインタを取得
	virtual char *GetPtr() { return m_bd->GetPtr(); };

protected:
	CBinaryData	*m_bd;
};


/*!
	CWorkspaceAccessラッパクラス
*/
class CManagedInterfaceAccessArgWorkspaceWarp : public IWorkspaceAccess
{
public:
	//!	コンストラクタ
	CManagedInterfaceAccessArgWorkspaceWarp()	{ m_ws = NULL; };

	//!	設定
	void SetArg(CWorkspaceAccess *ws)			{ m_ws = ws; };

	//!	初期化
	virtual void SetWorkspaceAccess(IWorkspacePtr root, LPCSTR path)
	{
		*m_ws = CWorkspaceAccess(root, path);
	};

	//!	インターフェース取得
	virtual IWorkspacePtr	GetIWorkspacePtr()	{ return m_ws->GetRoot(); };

	//!	パス取得
	virtual LPCSTR			GetAccessPath()		{ return m_ws->GetPath(); };

protected:
	CWorkspaceAccess	*m_ws;
};


/************************************************************************************/
//	引数スタッククラス
//	引数スタックインタフェースを提供する
/************************************************************************************/
/*!
	インタフェース受け渡し用引数、関数呼び出し側用
	このクラスは、ポインタ以外のデータを保存しない
	使用時は、割り当てた変数がスタックから消滅しないように注意する
*/
class CManagedInterfaceAccessArg
{
public:
	///////////////////////////////////////////////////////////////////////////////
	//	コンストラクタ
	///////////////////////////////////////////////////////////////////////////////
	//!	データなし
	CManagedInterfaceAccessArg()
	{
		SetArg(MI_ARG_TYPE_NODATA, NULL);
	};

	//!	Int
	CManagedInterfaceAccessArg(int &val)
	{
		SetArg(MI_ARG_TYPE_INT, &val);
	};

	//!	Int*
	CManagedInterfaceAccessArg(int *val)
	{
		SetArg(MI_ARG_TYPE_INT_REFERENCE, val);
	};

	//!	Int64
	CManagedInterfaceAccessArg(__int64 &val)
	{
		SetArg(MI_ARG_TYPE_INT64, &val);
	};

	//!	Int64*
	CManagedInterfaceAccessArg(__int64 *val)	
	{
		SetArg(MI_ARG_TYPE_INT64_REFERENCE, val);
	};


	///////////////////////////////////////////////////////////////////////////////
	//	コンストラクタ クラス用ラッパ使用
	///////////////////////////////////////////////////////////////////////////////
	//!	CString
	CManagedInterfaceAccessArg(CString &val)
	{
		m_strWarp.SetArg(&val);
		SetArg(MI_ARG_TYPE_STR, NULL);
	};

	//!	CString*
	CManagedInterfaceAccessArg(CString *val)
	{
		m_strWarp.SetArg(val);
		SetArg(MI_ARG_TYPE_STR_REFERENCE, NULL);
	};

	//!	CBinaryData
	CManagedInterfaceAccessArg(CBinaryData &val)
	{
		m_bdWrap.SetArg(&val);
		SetArg(MI_ARG_TYPE_BINARY, NULL);
	};

	//!	CBinaryData
	CManagedInterfaceAccessArg(CBinaryData *val)
	{
		m_bdWrap.SetArg(val);
		SetArg(MI_ARG_TYPE_BINARY_REFERENCE, NULL);
	};

	//!	CWorkspaceAccess
	CManagedInterfaceAccessArg(CWorkspaceAccess &val)
	{
		m_wsWrap.SetArg(&val);
		SetArg(MI_ARG_TYPE_WORKSPACE, NULL);
	};

	//!	CWorkspaceAccess
	CManagedInterfaceAccessArg(CWorkspaceAccess *val)
	{
		m_wsWrap.SetArg(val);
		SetArg(MI_ARG_TYPE_WORKSPACE_REFERENCE, NULL);
	};

	///////////////////////////////////////////////////////////////////////////////
	//	利用
	///////////////////////////////////////////////////////////////////////////////
	//!	タイプ取得
	int GetType()	{ return m_argType; };

	//!	ポインタ取得
	void *GetPtr()
	{
		//	種類により分岐
		if(m_argType == MI_ARG_TYPE_STR ||				m_argType == MI_ARG_TYPE_STR_REFERENCE)
			return (IStringPtr)&m_strWarp;
		else if(m_argType == MI_ARG_TYPE_BINARY ||		m_argType == MI_ARG_TYPE_BINARY_REFERENCE)
			return (IStringPtr)&m_strWarp;
		else if(m_argType == MI_ARG_TYPE_WORKSPACE ||	m_argType == MI_ARG_TYPE_WORKSPACE_REFERENCE)
			return (IStringPtr)&m_strWarp;
		else
			return m_argPtr;
	};

protected:
	///////////////////////////////////////////////////////////////////////////////
	//	補助
	///////////////////////////////////////////////////////////////////////////////
	//!	ポインタと型を設定
	void SetArg(int type, void *arg)
	{
		m_argType = type;
		m_argPtr = arg;
	}

	///////////////////////////////////////////////////////////////////////////////
	//	メンバ変数
	///////////////////////////////////////////////////////////////////////////////
	//!	型
	int						m_argType;

	//!	共通ポインタ
	void					*m_argPtr;

	//!	文字列用
	CManagedInterfaceAccessArgStringWarp		m_strWarp;

	//!	BinaryData
	CManagedInterfaceAccessArgBinaryWarp		m_bdWrap;

	//!	CWorkspace用
	CManagedInterfaceAccessArgWorkspaceWarp	m_wsWrap;
};


/*!
	インタフェース受け渡し用引数のスタック、関数呼び出し側用
*/
class CManagedInterfaceAccessArgStack :
	public IManagedInterfaceArgStack
{
public:

	CManagedInterfaceAccessArgStack(void)
	{
		m_exceptionType = MI_EXCEPTION_TYPE_NOEXCEPTION;
	}

	///////////////////////////////////////////////////////////////////
	//	生成
	///////////////////////////////////////////////////////////////////
	//!	void 追加
	void AddEmptyArg()
	{
		m_args.Add(CManagedInterfaceAccessArg());
	};

	//!	追加
	void AddArg(CManagedInterfaceAccessArg val)
	{
		m_args.Add(val);
	};

	///////////////////////////////////////////////////////////////////
	//	例外処理
	///////////////////////////////////////////////////////////////////
	//!	例外タイプ取得
	int GetExceptionType() { return m_exceptionType; };

	//!	例外名取得
	CString &GetExceptionName() { return m_exceptionName; };

	//!	例外情報取得
	CString &GetExceptionInfo() { return m_exceptionInfo; };

protected:
	///////////////////////////////////////////////////////////////////
	//	IManagedInterfaceArgStack
	///////////////////////////////////////////////////////////////////
	//!	引数の個数取得
	virtual int GetArgCount()
	{
		return m_args.GetSize();
	};

	//!	指定した引数の型取得
	virtual int GetArgType(int index)
	{
		if(index < 0 || index >= m_args.GetSize())
			return MI_ARG_TYPE_NODATA;
		return m_args[index].GetType();
	};

	//!	取得
	virtual void *GetArgPtr(int index)
	{
		if(index < 0 || index >= m_args.GetSize())
			return NULL;
		return m_args[index].GetPtr();
	};

	//!	例外を設定
	virtual void SetException(int type, LPCSTR name, LPCSTR info)
	{
		m_exceptionType = type;

		if(name != NULL)
			m_exceptionName = name;
		else
			m_exceptionName.Empty();

		if(info != NULL)
			m_exceptionInfo = info;
		else
			m_exceptionInfo.Empty();
	}

protected:
	///////////////////////////////////////////////////////////////////////////////
	//	メンバ変数
	///////////////////////////////////////////////////////////////////////////////
	//!	引数配列
	CArray<CManagedInterfaceAccessArg>	m_args;

	//!	例外タイプ
	int				m_exceptionType;

	//!	例外情報
	CString			m_exceptionName;

	//!	例外情報
	CString			m_exceptionInfo;

};
