/*
 *	clipact.h
 *
 *	アクターオブジェクト
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2016 Naoyuki Sawa
 *
 *	* Sun Feb 07 21:14:38 JST 2016 Naoyuki Sawa
 *	- 1st リリース。
 *	- 有限状態機械とプロパティヘッダとアプリケーション定義のデータをまとめたものを、アクターオブジェクトと呼ぶ事にしました。
 *        当モジュールは、アクターオブジェクトを、ツリー構造で管理する機能を提供します。
 *	- 2016/02/07現在の所、最低限の機能だけを実装しました。
 *	  今後、アクターオブジェクトを検索する機能を追加したり、座標プロパティや当たり判定プロパティを標準化したりする予定です。
 *	* Fri Feb 26 21:51:12 JST 2016 Naoyuki Sawa
 *	- ActObj_ApplyTrans_l(),ActObj_ApplyTrans_a(),ActObj_ApplyTrans_v()を追加しました。
 *	  ActObj_ApplyTransToChildren_l(),ActObj_ApplyTransToChildren_a(),ActObj_ApplyTransToChildren_v()を追加しました。
 *	  ActObj_ApplyTransToTree_l(),ActObj_ApplyTransToTree_a(),ActObj_ApplyTransToTree_v()を追加しました。
 *	  詳細は、clipfsm.h の同日のコメントを参照して下さい。
 *	* Sat Feb 27 21:21:24 JST 2016 Naoyuki Sawa
 *	- FsmObj_Init()の引数で有権状態機械の初期状態を明示しなくなった事に伴い、ActObj_New()からも初期状態を指定する引数を削除しました。
 *	  詳細は、clipfsm.h の同日のコメントを参照して下さい。
 *	- ActObj_GetParent()を追加しました。
 *	  この関数を追加した理由は、clipact.c の実装個所のコメントを参照して下さい。
 *	* Sat Apr 02 23:34:06 JST 2016 Naoyuki Sawa
 *	- ARRAY_SIZE()マクロの変更に伴い、VC++6.0でintとunsignedの比較に対する警告が厳密に出るようになったので、警告が出ないように明示的なキャストを追加しました。
 *	  動作自体はこれまでと変わりません。
 *	  詳細はclipmisc.hの同日のコメントを参照して下さい。
 *	* Fri Jul 08 21:19:03 JST 2016 Naoyuki Sawa
 *	- clipfsm.cモジュールの、FsmObj_ApplyTrans_l(),FsmObj_ApplyTrans_a(),FsmObj_ApplyTrans_v()に対して行ったのと同じ変更を、
 *	  ActObj_ApplyTrans_l(),ActObj_ApplyTrans_a(),ActObj_ApplyTrans_v()、及び、
 *	  ActObj_ApplyTransToChildren_l(),ActObj_ApplyTransToChildren_a(),ActObj_ApplyTransToChildren_v()、及び、
 *	  ActObj_ApplyTransToTree_l(),ActObj_ApplyTransToTree_a(),ActObj_ApplyTransToTree_v()にも適用しました。
 *	  詳細は、clipfsm.cモジュールの、同日のコメントを参照して下さい。
 *	- 余談ですが、これまで、上記の関数のアセンブラ版の実装は、スタック操作のバグが有った事に気付きました。
 *	  今回の変更に合わせて、スタック操作のバグも修正しました。
 *	* Sat Aug 27 12:10:07 JST 2016 Naoyuki Sawa
 *	- gnode.hにG_PRE_ORDER内でnode自身を削除出来るようにするための独自拡張を追加した事に伴い、ActObj_ApplyTransToTree()がG_POST_ORDERでなくG_PRE_ORDERを使用するように変更しました。
 *	  gnode.hの、同日のコメントも参照して下さい。
 *	- gnode.hの「G_PRE_ORDER内でnode自身を削除出来るようにするための独自拡張」で行ったのと同じ検証を、当モジュール経由でも検証しました。
 *	  今回の変更が、正しく反映されている事を確認しました。
 *	  ------------------------------------------------------------------------------
 *	  ■テストプログラム
 *	  (app.c)
 *	  │void test() {
 *	  │  ST_ActObj *root, *node1, *node2, *node11, *node12, *node21, *node22;
 *	  │  root = ActObj_New(NULL, pFsmKey, FsmMap_Test, NULL, 0, sizeof(const char*));
 *	  │  *(const char**)ActObj_GetData(root) = "root";
 *	  │    node1 = ActObj_New(root, pFsmKey, FsmMap_Test, NULL, 0, sizeof(const char*));
 *	  │    *(const char**)ActObj_GetData(node1) = "node1";
 *	  │      node11 = ActObj_New(node1, pFsmKey, FsmMap_Test, NULL, 0, sizeof(const char*));
 *	  │      *(const char**)ActObj_GetData(node11) = "node11";
 *	  │      node12 = ActObj_New(node1, pFsmKey, FsmMap_Test, NULL, 0, sizeof(const char*));
 *	  │      *(const char**)ActObj_GetData(node12) = "node12";
 *	  │    node2 = ActObj_New(root, pFsmKey, FsmMap_Test, NULL, 0, sizeof(const char*));
 *	  │    *(const char**)ActObj_GetData(node2) = "node2";
 *	  │      node21 = ActObj_New(node2, pFsmKey, FsmMap_Test, NULL, 0, sizeof(const char*));
 *	  │      *(const char**)ActObj_GetData(node21) = "node21";
 *	  │      node22 = ActObj_New(node2, pFsmKey, FsmMap_Test, NULL, 0, sizeof(const char*));
 *	  │      *(const char**)ActObj_GetData(node22) = "node22";
 *	  │  ActObj_ApplyTransToTree_l(root, FsmTrans_Exec, 1, 0);
 *	  │  ActObj_Free(root);
 *	  │}
 *	  (FsmMap.txt)
 *	  │Test Run
 *	  │     Run
 *	  │         Exec {`
 *	  │                ST_ActObj* pActObj = ActObj_FromFsmObj(pFsmObj);
 *	  │                const char* name = *(const char**)ActObj_GetData(pActObj);
 *	  │                ST_FsmObj_Arg* pArg = pParam;
 *	  │                int nest = (int)pArg->argv[0];
 *	  │                printf("%*s%s\n", nest, "", name);
 *	  │                if(!strcmp(name, "node1")) {
 *	  │                  if(nest <= 1) {
 *	  │                    ActObj_ApplyTransToTree_l(ActObj_GetParent(pActObj), FsmTrans_Exec, 1, nest + 1);
 *	  │                    if(nest == 1) {
 *	  │                      ActObj_Free(pActObj);
 *	  │                      printf("%*s%s自身を削除しました。\n", nest, "", name);
 *	  │                    }
 *	  │                  }
 *	  │                }
 *	  │              `}
 *	  │     end
 *	  │end
 *	  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 *	  □結果
 *	  │root			←G_PRE_ORDERの順序で、親が先にトラバースされている事を確認しました。
 *	  │node1
 *	  │ root
 *	  │ node1
 *	  │  root
 *	  │  node1
 *	  │  node11
 *	  │  node12
 *	  │  node2
 *	  │  node21
 *	  │  node22
 *	  │ node1自身を削除しました。
 *	  │ node2			←期待通り、ここでnode11とnode12のトラバースが行われていないので、正しく動作している事が確認出来ました。
 *	  │ node21
 *	  │ node22
 *	  │node2			←期待通り、ここでnode11とnode12のトラバースが行われていないので、正しく動作している事が確認出来ました。
 *	  │node21
 *	  │node22
 *	  ------------------------------------------------------------------------------
 *	* Sun Sep 11 21:23:51 JST 2016 Naoyuki Sawa
 *	- アクターオブジェクトに、演出シーケンサを含めました。
 *	  演出シーケンサを使用するアクターオブジェクトは、ActObj_New()の引数fnAct,nDirSeqChに0以外の値を指定して作成して下さい。
 *	  その後、各アクターオブジェクトの演出シーケンサを、ActObj_GetDirSeq()で取得して使用して下さい。
 *	  fnActからアクターオブジェクトを逆引きするには、ActObj_FromDirSeq()を使用して下さい。
 *	- ユーティリティマクロACTOBJ_FSMFUNC_PROLOGUE_BASE,ACTOBJ_FSMFUNC_EPILOGUE_BASEを追加しました。
 *	  ユーティリティマクロACTOBJ_DIRFUNC_PROLOGUE_BASE,ACTOBJ_DIRFUNC_EPILOGUE_BASEを追加しました。
 */
#ifndef __CLIP_ACT_H__
#define __CLIP_ACT_H__
#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus
/****************************************************************************
 *	
 ****************************************************************************/
//{{2016/09/11変更:アクターオブジェクトに、演出シーケンサを含めました。
//typedef struct _ST_ActObj {
//	GNode*		node;
//	ST_FsmObj	stFsmObj;
//	ST_PrpHdr	stPrpHdr;
//    //	int		aPrpTbl[nPrpTblWords];
//    //	int		aData[nDataWords];
//} ST_ActObj;
//↓2016/09/11変更:アクターオブジェクトに、演出シーケンサを含めました。
typedef struct _ST_ActObj {
	GNode*		node;				//+0
    //	ST_FsmObj	stFsmObj;			//+sizeof(ST_ActObj)
    //	ST_DirSeq	stDirSeq;			//+sizeof(ST_ActObj)+sizeof(ST_FsmObj)
    //	ST_DirSeqCh	_TBL_DirSeqCh[nDirSeqCh];	//+sizeof(ST_ActObj)+sizeof(ST_FsmObj)+sizeof(ST_DirSeq)
    //	ST_PrpHdr	stPrpHdr;			//+sizeof(ST_ActObj)+sizeof(ST_FsmObj)+sizeof(ST_DirSeq)+(sizeof(ST_DirSeqCh)*nDirSeqCh)
    //	int		_aPrpTbl[nPrpTblWords];		//+sizeof(ST_ActObj)+sizeof(ST_FsmObj)+sizeof(ST_DirSeq)+(sizeof(ST_DirSeqCh)*nDirSeqCh)+sizeof(ST_PrpHdr)
    //	int		_aData[nDataWords];		//+sizeof(ST_ActObj)+sizeof(ST_FsmObj)+sizeof(ST_DirSeq)+(sizeof(ST_DirSeqCh)*nDirSeqCh)+sizeof(ST_PrpHdr)+(sizeof(int)*nPrpTblWords)
} ST_ActObj;						//=sizeof(ST_ActObj)+sizeof(ST_FsmObj)+sizeof(ST_DirSeq)+(sizeof(ST_DirSeqCh)*nDirSeqCh)+sizeof(ST_PrpHdr)+(sizeof(int)*nPrpTblWords)+(sizeof(int)*nDataWords)
//}}2016/09/11変更:アクターオブジェクトに、演出シーケンサを含めました。
/*--------------------------------------------------------------------------*/
typedef struct _ST_ActObj_Iter {
	ST_ActObj*	pNext;
} ST_ActObj_Iter;
/****************************************************************************
 *	基本的な関数
 ****************************************************************************/
//{{2016/09/11変更:アクターオブジェクトに、演出シーケンサを含めました。
//ST_ActObj* ActObj_New(ST_ActObj* pParent/*NULL可*/, const void* pFsmKey/*NULL可*/, int iFsmMap, const void* pPrpKey/*NULL可*/, int iPrpTbl, int nDataBytes);
//↓2016/09/11変更:アクターオブジェクトに、演出シーケンサを含めました。
ST_ActObj* ActObj_New(ST_ActObj* pParent/*NULL可*/,
  const void* pFsmKey/*NULL可*/, int iFsmMap/*(pFsmKey=NULL)ならば参照しない*/,
  const void* pPrpKey/*NULL可*/, int iPrpTbl/*(pPrpKey=NULL)ならば参照しない*/,								//┐この引数順序がST_ActObj構造体内での並びとは逆なのですが、この引数順序の方が直観的に判り易いのでこうする事にしました。
  void (*fnAct/*(nDirSeqCh=0)ならば参照しない*/)(struct _ST_DirSeq* pDirSeq, int iCh, int ActNo, int bOverFlow), int nDirSeqCh/*0可*/,	//┘ST_ActObj構造体内での並びがstDirSeq,stPrpHdrの順である理由は、アドレス計算処理の都合だけでやむを得ずそうしただけです。
  int nDataBytes/*0可*/);
//}}2016/09/11変更:アクターオブジェクトに、演出シーケンサを含めました。
void ActObj_Free(ST_ActObj* pActObj);
void ActObj_FreeChildren(ST_ActObj* pActObj);
ST_ActObj* ActObj_GetParent(ST_ActObj* pActObj);
ST_ActObj* ActObj_FirstChild(ST_ActObj* pActObj, ST_ActObj_Iter* pIter);
ST_ActObj* ActObj_NextSibling(ST_ActObj_Iter* pIter);
/*--------------------------------------------------------------------------*/
//{{2016/09/11変更:アクターオブジェクトに、演出シーケンサを含めました。
//void* ActObj_GetData(ST_ActObj* pActObj);
//ST_ActObj* ActObj_FromFsmObj(ST_FsmObj* pFsmObj);
//↓2016/09/11変更:アクターオブジェクトに、演出シーケンサを含めました。
ST_FsmObj* ActObj_GetFsmObj(ST_ActObj* pActObj);	//┐ST_ActObjの先頭アドレスから、stFsmObjフィールドのアドレスを取得する。
ST_ActObj* ActObj_FromFsmObj(ST_FsmObj* pFsmObj);	//┘stFsmObjフィールドのアドレスから、ST_ActObjの先頭アドレスを取得する。
ST_DirSeq* ActObj_GetDirSeq(ST_ActObj* pActObj);	//┐ST_ActObjの先頭アドレスから、stDirSeqフィールドのアドレスを取得する。
ST_ActObj* ActObj_FromDirSeq(ST_DirSeq* pDirSeq);	//┘stDirSeqフィールドのアドレスから、ST_ActObjの先頭アドレスを取得する。
ST_PrpHdr* ActObj_GetPrpHdr(ST_ActObj* pActObj);	//┐ST_ActObjの先頭アドレスから、stPrpHdrフィールドのアドレスを取得する。
//ST_ActObj* ActObj_FromPrpHdr(ST_PrpHdr* pPrpHdr);	//┘stPrpHdrフィールドのアドレスから、ST_ActObjの先頭アドレスを取得する。		×この操作は提供出来ません。stPrpHdrフィールド以降の情報だけでは、stPrpHdrフィールド以前のサイズを計算出来ないからです。
void* ActObj_GetData(ST_ActObj* pActObj);		//┐ST_ActObjの先頭アドレスから、アプリケーション定義のデータのアドレスを取得する。
//ST_ActObj* ActObj_FromData(void* pData);		//┘アプリケーション定義のデータのアドレスから、ST_ActObjの先頭アドレスを取得する。	×この操作は提供出来ません。stPrpHdrフィールド以降の情報だけでは、stPrpHdrフィールド以前のサイズを計算出来ないからです。
//}}2016/09/11変更:アクターオブジェクトに、演出シーケンサを含めました。
/*--------------------------------------------------------------------------*/
void ActObj_ApplyTrans(ST_ActObj* pActObj, int iFsmTrans, void* pParam);				//┐
void ActObj_ApplyTransToChildren(ST_ActObj* pActObj, int iFsmTrans, void* pParam);			//├pParamがそのまま、Act関数へのpParam引数となります。
void ActObj_ApplyTransToTree(ST_ActObj* pActObj, int iFsmTrans, void* pParam);				//┘
/*--------------------------------------------------------------------------*/
//{{2016/09/11追加:アクターオブジェクトに、演出シーケンサを含めました。
void ActObj_ExecDirSeq(ST_ActObj* pActObj);		//┐
void ActObj_ExecDirSeqToChildren(ST_ActObj* pActObj);	//├アプリケーションを簡潔に書けるようツリーに対するDirSeq_Exec()操作のみ実装しました。ツリーに対するそれ以外の操作(DirSeqCh_SetTbl(),DirSeqCh_SendTrig()等)が必要ならばアプリケーションが個別に実装して下さい。
void ActObj_ExecDirSeqToTree(ST_ActObj* pActObj);	//┘
//}}2016/09/11追加:アクターオブジェクトに、演出シーケンサを含めました。
/****************************************************************************
 *	ユーティリティ関数
 ****************************************************************************/
void ActObj_ApplyTrans_l(ST_ActObj* pActObj, int iFsmTrans, int argc, ...);				//┐
void ActObj_ApplyTrans_a(ST_ActObj* pActObj, int iFsmTrans, int argc, va_list ap);			//├可変引数の情報をST_FsmObj_Arg型の構造体に格納して、Act関数へのpParam引数となります。
void ActObj_ApplyTrans_v(ST_ActObj* pActObj, int iFsmTrans, int argc, void* argv[/*argc*/]);		//┘
/*--------------------------------------------------------------------------*/
void ActObj_ApplyTransToChildren_l(ST_ActObj* pActObj, int iFsmTrans, int argc, ...);			//┐
void ActObj_ApplyTransToChildren_a(ST_ActObj* pActObj, int iFsmTrans, int argc, va_list ap);		//├可変引数の情報をST_FsmObj_Arg型の構造体に格納して、Act関数へのpParam引数となります。
void ActObj_ApplyTransToChildren_v(ST_ActObj* pActObj, int iFsmTrans, int argc, void* argv[/*argc*/]);	//┘
/*--------------------------------------------------------------------------*/
void ActObj_ApplyTransToTree_l(ST_ActObj* pActObj, int iFsmTrans, int argc, ...);			//┐
void ActObj_ApplyTransToTree_a(ST_ActObj* pActObj, int iFsmTrans, int argc, va_list ap);		//├可変引数の情報をST_FsmObj_Arg型の構造体に格納して、Act関数へのpParam引数となります。
void ActObj_ApplyTransToTree_v(ST_ActObj* pActObj, int iFsmTrans, int argc, void* argv[/*argc*/]);	//┘
/****************************************************************************
 *	ユーティリティマクロ
 ****************************************************************************/
//ST_ActObj内のST_FsmObjから呼び出される関数(FsmFunc_〜)の実装を容易にするためのユーティリティマクロです。
//関数の最初に行う処理と関数の最後で行う処理の、一般的な処理の共通部分をマクロ定義しました。
//必要に応じて、アプリケーション定義のマクロにマージして、使用して下さい。
//・現在の所、関数の最後で行う共通部分は無いので、下記の定義では空のマクロとしてあります。
//・「ST_FsmObj_Arg* const pArg = (ST_FsmObj_Arg*)pParam;」も含めるか検討しましたが、含めない事にしました。
//  含めなかった理由の一つ目は、pParam引数が有るのはAct関数だけであり、その他のEntry関数等には無いからです。
//  含めなかった理由の二つ目は、pParamが(ST_FsmObj_Arg*)型だとは限らず、遷移の種類毎に判断すべきだからです。
#define ACTOBJ_FSMFUNC_PROLOGUE_BASE				\
	int        const iState  = FsmObj_GetState(  pFsmObj);	\
	ST_ActObj* const pActObj = ActObj_FromFsmObj(pFsmObj);	\
	ST_DirSeq* const pDirSeq = ActObj_GetDirSeq( pActObj);	\
	ST_PrpHdr* const pPrpHdr = ActObj_GetPrpHdr( pActObj);	\
	void*      const pData   = ActObj_GetData(   pActObj);	\
	/* PrpHdr_load( pPrpHdr, 変数名); */			\
	/* PrpHdr_fload(pPrpHdr, 変数名); */
#define ACTOBJ_FSMFUNC_EPILOGUE_BASE				\
	/* PrpHdr_save( pPrpHdr, 変数名); */			\
	/* PrpHdr_fsave(pPrpHdr, 変数名); */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//ST_ActObj内のST_DirSeqから呼び出される演出実行関数(fnAct)の実装を容易にするためのユーティリティマクロです。
//関数の最初に行う処理と関数の最後で行う処理の、一般的な処理の共通部分をマクロ定義しました。
//必要に応じて、アプリケーション定義のマクロにマージして、使用して下さい。
//・現在の所、関数の最後で行う共通部分は無いので、下記の定義では空のマクロとしてあります。
#define ACTOBJ_DIRFUNC_PROLOGUE_BASE				\
	ST_ActObj* const pActObj = ActObj_FromDirSeq(pDirSeq);	\
	ST_FsmObj* const pFsmObj = ActObj_GetFsmObj( pActObj);	\
	int        const iState  = FsmObj_GetState(  pFsmObj);	\
	ST_PrpHdr* const pPrpHdr = ActObj_GetPrpHdr( pActObj);	\
	void*      const pData   = ActObj_GetData(   pActObj);	\
	/* PrpHdr_load( pPrpHdr, 変数名); */			\
	/* PrpHdr_fload(pPrpHdr, 変数名); */
#define ACTOBJ_DIRFUNC_EPILOGUE_BASE				\
	/* PrpHdr_save( pPrpHdr, 変数名); */			\
	/* PrpHdr_fsave(pPrpHdr, 変数名); */
#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus
#endif//__CLIP_ACT_H__
