/*!
	ManagedInterfaceImplementArgStack.h

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

	実装側用	
*/
#pragma once
#include "ManagedInterfaceExchangeInterfaces.h"
#include "ManagedInterfaceAccessArgStack.h"
#include "BinaryData.h"
#include "WorkspaceAccess.h"


/************************************************************************************/
//	引数スタッククラス
//	引数スタックインタフェースを提供する
/************************************************************************************/
/*!
	インタフェース受け渡し用引数、関数提供側用
	基本型以外の参照は、一時的に内部にデータを保存し、終了時に書き出す
*/
class CManagedInterfaceImplementArg
{
public:
	CManagedInterfaceImplementArg()
	{
		SetArg(MI_ARG_TYPE_NODATA, NULL);
	}
	CManagedInterfaceImplementArg(int type, void *arg)
	{
		SetArg(type, arg);
	}

	///////////////////////////////////////////////////////////////////////////////
	//	初期化
	///////////////////////////////////////////////////////////////////////////////
	//!	ポインタと型を設定
	void SetArg(int type, void *arg)
	{
		m_argType = type;
		m_argPtr = arg;
	}

	//!	参照型を書き戻し
	void FlashRefData()
	{
		if(m_argType == MI_ARG_TYPE_STR_REFERENCE)
		{
			((IStringPtr)m_argPtr)->SetString(m_strRef);
		}
		else if(m_argType == MI_ARG_TYPE_BINARY_REFERENCE)
		{
			((IBinaryData*)m_argPtr)->ReSize(m_bdRef.GetSize());
			memcpy(((IBinaryData*)m_argPtr)->GetPtr(), m_bdRef.GetPtr(), m_bdRef.GetSize());
		}
		else if(m_argType == MI_ARG_TYPE_WORKSPACE_REFERENCE)
		{
			((IWorkspaceAccessPtr)m_argPtr)->SetWorkspaceAccess(m_wsRef.GetRoot(), m_wsRef.GetPath());
		}
	}

	///////////////////////////////////////////////////////////////////////////////
	//	引数用
	///////////////////////////////////////////////////////////////////////////////
	//!	Int型
	operator int()
	{
		CheckArgType(MI_ARG_TYPE_INT);
		return(*(int*)m_argPtr);
	}

	//!	Int*型
	operator int*()
	{
		CheckArgType(MI_ARG_TYPE_INT_REFERENCE);
		return((int*)m_argPtr);
	}

	//!	Int64型
	operator __int64()
	{
		CheckArgType(MI_ARG_TYPE_INT64);
		return(*(__int64*)m_argPtr);
	}

	//!	Int64*型
	operator __int64*()
	{
		CheckArgType(MI_ARG_TYPE_INT64_REFERENCE);
		return((__int64*)m_argPtr);
	}

	//!	CString型
	operator CString()
	{
		CheckArgType(MI_ARG_TYPE_STR);
		return(((IStringPtr)m_argPtr)->GetString());
	}

	//!	CString*型
	operator CString*()
	{
		CheckArgType(MI_ARG_TYPE_STR_REFERENCE);

		//	一旦取得
		m_strRef = ((IStringPtr)m_argPtr)->GetString();
		return(&m_strRef);
	}

	//!	CBinaryData型
	operator CBinaryData()
	{
		CheckArgType(MI_ARG_TYPE_BINARY);

		//	一旦取得
		m_bdRef.Empty();
		m_bdRef.Append(((IBinaryDataPtr)m_argPtr)->GetPtr(), ((IBinaryData*)m_argPtr)->GetSize());
		return(m_bdRef);
	}

	//!	CBinaryData*型
	operator CBinaryData*()
	{
		CheckArgType(MI_ARG_TYPE_BINARY_REFERENCE);

		//	一旦取得
		m_bdRef.Empty();
		m_bdRef.Append(((IBinaryDataPtr)m_argPtr)->GetPtr(), ((IBinaryData*)m_argPtr)->GetSize());
		return(&m_bdRef);
	}

	//!	CWorkspaceAccess型
	operator CWorkspaceAccess()
	{
		CheckArgType(MI_ARG_TYPE_WORKSPACE);
		return(CWorkspaceAccess((IWorkspaceAccessPtr)m_argPtr));
	}

	//!	CWorkspaceAccess型
	operator CWorkspaceAccess*()
	{
		CheckArgType(MI_ARG_TYPE_WORKSPACE_REFERENCE);

		//	一旦取得
		m_wsRef = CWorkspaceAccess((IWorkspaceAccessPtr)m_argPtr);
		return(&m_wsRef);
	}

	///////////////////////////////////////////////////////////////////////////////
	//	戻り値用
	///////////////////////////////////////////////////////////////////////////////
	//!	int
	void operator=(int val)
	{
		CheckArgType(MI_ARG_TYPE_INT_REFERENCE);
		*(int*)m_argPtr = val;
	}

	//!	int64
	void operator=(__int64 val)
	{
		CheckArgType(MI_ARG_TYPE_INT64_REFERENCE);
		*(__int64*)m_argPtr = val;
	}

	//!	String
	void operator=(CString val)
	{
		CheckArgType(MI_ARG_TYPE_STR_REFERENCE);
		((IStringPtr)m_argPtr)->SetString(val);
	}

	//!	Binary
	void operator=(CBinaryData val)
	{
		CheckArgType(MI_ARG_TYPE_STR_REFERENCE);
		((IBinaryData*)m_argPtr)->ReSize(val.GetSize());
		memcpy(((IBinaryData*)m_argPtr)->GetPtr(), val.GetPtr(), val.GetSize());
	}

	//!	CWorkspaceAccess
	void operator=(CWorkspaceAccess val)
	{
		CheckArgType(MI_ARG_TYPE_WORKSPACE);
		((IWorkspaceAccessPtr)m_argPtr)->SetWorkspaceAccess(val.GetRoot(), val.GetPath());
	}

protected:
	///////////////////////////////////////////////////////////////////////////////
	//	補助
	///////////////////////////////////////////////////////////////////////////////
	//!	方の確認
	void CheckArgType(int type)
	{
		if(m_argType != type)
			throw CManagedInterfaceException();
	}

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

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

	//!	文字列用
	CString					m_strRef;

	//!	BinaryData
	CBinaryData				m_bdRef;

	//!	CWorkspaceAccess
	CWorkspaceAccess		m_wsRef;
};

/*!
	インタフェース受け渡し用引数スタック、関数提供側用
*/
class CManagedInterfaceImplementArgStack
{
public:
	//!	コンストラクタ
	CManagedInterfaceImplementArgStack(IManagedInterfaceArgStackPtr stack)
	{
		m_stack = stack;

		//	引数初期化
		int	count = m_stack->GetArgCount();
		for(int i=0;i<count;i++)
			m_args.Add(CManagedInterfaceImplementArg(m_stack->GetArgType(i), m_stack->GetArgPtr(i)));
	}

	//!	デストラクタ
	virtual ~CManagedInterfaceImplementArgStack()
	{
		//	書き戻し
		for(int i=0;i<m_args.GetCount();i++)
			m_args[i].FlashRefData();
	}

	///////////////////////////////////////////////////////////////////////////////
	//	引数アクセス
	///////////////////////////////////////////////////////////////////////////////
	//!	取得
	CManagedInterfaceImplementArg &operator[](int index)
	{
		if(index < 0 || index >= m_args.GetSize())
			throw CManagedInterfaceException();
		return m_args[index];
	};

	///////////////////////////////////////////////////////////////////////////////
	//	例外処理
	///////////////////////////////////////////////////////////////////////////////
	//!	例外を設定
	void SetException(int type, LPCSTR name, LPCSTR info)
	{
		m_stack->SetException(type, name, info);
	}

protected:
	///////////////////////////////////////////////////////////////////////////////
	//	メンバ変数
	///////////////////////////////////////////////////////////////////////////////
	//!	スタック
	IManagedInterfaceArgStackPtr	m_stack;

	//!	引数配列
	CArray<CManagedInterfaceImplementArg>	m_args;
};
