/*
 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 *  SCR_DyAr.h
 *  Scripts, Beaudet Christophe
 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 *
 */
 
#ifndef __SCR_DyAr_h__Types
#define __SCR_DyAr_h__Types
 
#ifndef __Only_Types__
#define __SCR_DyAr_h__Undef
#define __Only_Types__
#endif /* !__Only_Types__ */
 
/*
 *=================================================================================================
 *  Includes.
 *=================================================================================================
 */
 
#ifdef __SCR_DyAr_h__Undef
#undef __Only_Types__
#undef __SCR_DyAr_h__Undef
#endif /* __SCR_DyAr_h__Undef */
 
/*
 *=================================================================================================
 *  Constants.
 *=================================================================================================
 */
 
/*
 *  To export code.
 */
#undef CPA_EXPORT
#if defined(CPA_WANTS_IMPORT)
#define CPA_EXPORT __declspec(dllimport)
#elif defined(CPA_WANTS_EXPORT)
#define CPA_EXPORT __declspec(dllexport)
#else /* CPA_WANTS_IMPORT */
#define CPA_EXPORT
#endif /* CPA_WANTS_IMPORT */
 
/*
 *  Base allocation (and reallocation) of a dynamic array
 */
#define SCR_C_ui_DyAr_BaseForAllocation     100
 
/*
 *=================================================================================================
 *  Types.
 *=================================================================================================
 */
 
/*
 *	Header of a dynamic element.
 */
typedef struct SCR_tdst_DyAr_Header_
{
#ifdef SCR_DM_ProtectedVersion
    unsigned int					uiSizeOf;		/* Size of this structure for test in debug mod */
#endif /* SCR_DM_ProtectedVersion */
    unsigned int					uiIndexInArray;	/* Index in dynamic array */
	unsigned char					ucMemLevel;		/* Memory level */
} SCR_tdst_DyAr_Header;
 
/*
 * State of an element.
 */
typedef enum SCR_tde_DyAr_State
{
    SCR_EDAS_DyAr_Invalid = 0,      /* Invalid entry : Error */
    SCR_EDAS_DyAr_Free,             /* Entry free */
    SCR_EDAS_DyAr_Occupy,           /* Entry occupy */
}  SCR_tde_DyAr_State;
 
/*
 * Structure that describes an element of a dynamic array.
 */
typedef struct SCR_tdst_DyAr_Element_
{
    void                    *d_vElement;        /* Real element */
    SCR_tde_DyAr_State      eState;             /* State of the element */
} SCR_tdst_DyAr_Element;
 
/*
 * Structure that describes the dynamic array
 */
typedef struct SCR_tdst_DyAr_Description_
{
    SCR_tdst_DyAr_Element   *d_stDynArray;      /* Address of dynamic array */
    unsigned int            uiNumValues;        /* Number of values in array */
    unsigned int            uiMaxValues;        /* Max number of values in array */
} SCR_tdst_DyAr_Description;
 
#endif /* !__SCR_DyAr_h__Types */
 
/*
 *=================================================================================================
 *  Macros.
 *=================================================================================================
 */
 
#if !defined(__SCR_DyAr_h__Macros) && !defined(__Only_Types__)
#define __SCR_DyAr_h__Macros
 
/*
 *  To add a new element of a specific type in a dynamic array.
 *  _Cast       :   Cast of structure to add.
 *  _Pos        :   To receive position of new allocated structure in dynamic array.
 *  _Pointer    :   To receive address of new allocated structure.
 *  _Array      :   Array concerned.
 *	_InitMem	:	Must reset memory allocation ?
 *
 *	ALLOCATION IS IN BLOCK 0 FOR STATIC ELEMENTS.
 */
#define SCR_M_DyAr_AddElementStatic(_Cast, _Pos, _Pointer, _Array)\
{\
	/*
     *  Allocate a place in dynamic array.
     */\
	fn_v_Mem_SetMode(0);\
    _Pos = fn_ui_DyAr_AllocateElement(&_Array, 1);\
    /* 
     *  Allocate a new structure if it's not already here.
     */\
	/* Init current memory level of element */\
    if((_Array).d_stDynArray[_Pos].d_vElement == NULL)\
    {\
		fn_v_Mem_SetMode(0);\
        SCR_M_Mem_AllocAndSet(_Cast, _Pointer, 1);\
        /*
         *  Initialize context in array.
         */\
        (_Array).d_stDynArray[_Pos].d_vElement = _Pointer;\
        SCR_M_Dbg_UpdateSizeOf_P(_Cast, _Pointer);\
    }\
    /*
     *  We initialize _Pointer with already allocated structure.
     */\
    else\
    {\
        _Pointer = (_Cast *) (_Array).d_stDynArray[_Pos].d_vElement;\
        SCR_M_Dbg_AssertStruct_P(_Cast, _Pointer);\
    }\
	/*
	 * It is now occupy...
	 */\
	(_Pointer)->stHeader.uiIndexInArray = _Pos;\
	(_Pointer)->stHeader.ucMemLevel = 0;\
    (_Array).d_stDynArray[_Pos].eState = SCR_EDAS_DyAr_Occupy;\
}
 
#define SCR_M_DyAr_AddElement(_Cast, _Pos, _Pointer, _Array)\
{\
    /*
     *  Allocate a place in dynamic array.
     */\
	fn_v_Mem_SetMode(0);\
    _Pos = fn_ui_DyAr_AllocateElement(&_Array, 0);\
    /* 
     *  Allocate a new structure.
	 *	Allocation depend on current memory level.
     */\
	fn_v_Mem_SetMode(g_uc_Mem_CurrentMemLevel);\
    SCR_M_Mem_Alloc(_Cast, _Pointer, 1);\
    /*
     *  Initialize context in array.
     */\
    (_Array).d_stDynArray[_Pos].d_vElement = (_Pointer);\
    SCR_M_Dbg_UpdateSizeOf_P(_Cast, _Pointer);\
	/*
	 * It is now occupy...
	 */\
	(_Pointer)->stHeader.uiIndexInArray = _Pos;\
	(_Pointer)->stHeader.ucMemLevel = g_uc_Mem_CurrentMemLevel;\
    (_Array).d_stDynArray[_Pos].eState = SCR_EDAS_DyAr_Occupy;\
}
 
#define SCR_M_DyAr_AddElementNoAlloc(_Pos, _Pointer, _Array)\
{\
    /*
     *  Allocate a place in dynamic array.
     */\
	fn_v_Mem_SetMode(0);\
    _Pos = fn_ui_DyAr_AllocateElement(&_Array, 0);\
    /*
     *  Initialize context in array.
     */\
    (_Array).d_stDynArray[_Pos].d_vElement = (_Pointer);\
	/*
	 * It is now occupy...
	 */\
	(_Pointer)->stHeader.uiIndexInArray = _Pos;\
    (_Array).d_stDynArray[_Pos].eState = SCR_EDAS_DyAr_Occupy;\
}
 
/*
 *  To delete an element.
 *  _Cast       :   Cast of an element in array.
 *  _Pos        :   Position of element to delete.
 *  _Array      :   Array to delete the element.
 *  _Code       :   Code to free inside the element.
 */
#define SCR_M_DyAr_DeleteElement(_Cast, _Pos, _Array, _Code)\
{\
    SCR_tdst_DyAr_Element   *_p_stElement_;\
    _Cast					*_p_stPointer_;\
	unsigned int			_uiDPos_ = _Pos;\
    /*
     *  Mark the element to be free.
     */\
    _p_stElement_ = &(_Array)->d_stDynArray[_uiDPos_];\
    _p_stElement_->eState = SCR_EDAS_DyAr_Free;\
	_p_stPointer_ = (_Cast *) _p_stElement_->d_vElement;\
    /* 
     *  Really delete element if we can.
     */\
    {_Code}\
	fn_v_Mem_SetMode(_p_stPointer_->stHeader.ucMemLevel);\
    SCR_M_Mem_Free(_p_stElement_->d_vElement);\
    /* 
     *  Reduce num of values if we delete last one.
     */\
    if(_uiDPos_ == (_Array)->uiNumValues - 1)\
        (_Array)->uiNumValues--;\
}
 
#define SCR_M_DyAr_DeleteElementNoAlloc(_Pos, _Array, _Code)\
{\
    SCR_tdst_DyAr_Element   *_p_stElement_;\
	unsigned int			_uiDPos_ = _Pos;\
    /*
     *  Mark the element to be free.
     */\
    _p_stElement_ = &(_Array)->d_stDynArray[_uiDPos_];\
    _p_stElement_->eState = SCR_EDAS_DyAr_Free;\
	{_Code}\
	_p_stElement_->d_vElement = NULL;\
    /* 
     *  Reduce num of values if we delete last one.
     */\
    if(_uiDPos_ == (_Array)->uiNumValues - 1)\
        (_Array)->uiNumValues--;\
}
 
/*
 *  To delete all elements of a dynamic array.
 *  _Cast   :   Cast of element to delete.
 *  _Array  :   Array to delete the element.
 *  _Code   :   Code to free inside the element.
 *	_Borne	:	Borne to stop deletion.
 *
 *	_Code MUST SET ALLOCATION MODE FOR ELEMENT !!!
 */
#define _SCR_M_DyAr_DeleteAllElements(_Cast, _Array, _Code, _Borne)\
{\
    unsigned int    _uiIndex_;\
    /* 
     *  Delete all elements.
     */\
    for(_uiIndex_ = 0; _uiIndex_ < (_Array)->##_Borne; _uiIndex_++)\
        if((_Array)->d_stDynArray[_uiIndex_].d_vElement != NULL)\
            SCR_M_DyAr_DeleteElement(_Cast, _uiIndex_, _Array, _Code);\
    /*
     *  Free array.
     */\
    if((_Array)->d_stDynArray)\
	{\
        fn_v_Mem_SetMode(0);\
		SCR_M_Mem_Free((_Array)->d_stDynArray);\
	}\
    (_Array)->uiNumValues = (_Array)->uiMaxValues = 0;\
}
 
#define SCR_M_DyAr_DeleteAllElements(_Cast, _Array, _Code)\
	_SCR_M_DyAr_DeleteAllElements(_Cast, _Array, _Code, uiNumValues);
#define SCR_M_DyAr_DeleteAllElementsStatic(_Cast, _Array, _Code)\
	_SCR_M_DyAr_DeleteAllElements(_Cast, _Array, _Code, uiMaxValues);
 
/*
 *	A macro to delete an element depending on its priority.
 *	For a static allocation, element is not deleted but is erased from the dynamic array.
 *	So we assume that static block will be destroyed later.
 */
#define SCR_M_DyAr_DeleteElementWithMemLevel(_Cast, _Array, _Code, _PrioMin, _PrioMax)\
{\
    _Cast			*_p_stPointer_;\
    unsigned int	_uiPos_;\
	char			_cMode_;\
    _uiPos_ = 0;\
    SCR_M_DyAr_GetNextElement(_Cast, _uiPos_, _p_stPointer_, _Array);\
    while(_p_stPointer_)\
    {\
		if\
		(\
			((_p_stPointer_)->stHeader.ucMemLevel >= (_PrioMin))\
		&&	((_p_stPointer_)->stHeader.ucMemLevel <= (_PrioMax))\
		)\
		{\
			if\
			(\
				((_p_stPointer_)->stHeader.ucMemLevel >= E_ucScrMaxBlocksNb)\
			||	(g_a_ul_Mem_BlocAllocationSize[(_p_stPointer_)->stHeader.ucMemLevel] == 0)\
			)\
			{\
				_cMode_ = 0;\
				SCR_M_DyAr_DeleteElement(_Cast, _uiPos_, &(_Array), _Code);\
			}\
			else\
			{\
				_cMode_ = 1;\
				SCR_M_DyAr_DeleteElementNoAlloc(_uiPos_, &(_Array), _Code);\
			}\
		}\
        _uiPos_++;\
	    SCR_M_DyAr_GetNextElement(_Cast, _uiPos_, _p_stPointer_, _Array);\
    }\
}
 
/*
 *  A macro to get an element.
 *  _Cast       :   Cast of structure to get.
 *  _Pos        :   Position of element to get.
 *  _Pointer    :   To receive address of element.
 *  _Array      :   Array concerned.
 */
#define SCR_M_DyAr_GetElement(_Cast, _Pos, _Pointer, _Array)\
{\
    _Pointer = ((_Cast *) (_Array.d_stDynArray[_Pos].d_vElement));\
    SCR_M_Dbg_AssertStruct_P(_Cast, _Pointer);\
}
 
/*
 *  A macro to search the first valid element of a dynamic array.
 *  _Cast       :   Cast of element to return.
 *  _Pos        :   Pos of found element and current position to search.
 *  _Pointer    :   To receive address of element (NULL if not).
 *  _Array      :   Array to search.
 */
#define SCR_M_DyAr_GetNextElement(_Cast, _Pos, _Pointer, _Array)\
{\
    while((_Pos) < (_Array).uiNumValues)\
    {\
        if((_Array).d_stDynArray[_Pos].eState != SCR_EDAS_DyAr_Free)\
        {\
            SCR_M_DyAr_GetElement(_Cast, _Pos, _Pointer, _Array);\
            break;\
        }\
        (_Pos)++;\
    }\
    if((_Pos) >= (_Array).uiNumValues)\
        _Pointer = NULL;\
}
 
/*
 *  A macro to search an element in an array.
 *  _Cast       :   Cast of structure to get.
 *  _Pos        :   Position of element to get.
 *  _Pointer    :   To receive address of element.
 *  _Array      :   Array concerned.
 *  _Test       :   Lines to test if this is the good element.
 */
#define SCR_M_DyAr_SearchElement(_Cast, _Pos, _Pointer, _Array, _Test)\
{\
    _Pos = 0;\
    SCR_M_DyAr_GetNextElement(_Cast, _Pos, _Pointer, _Array);\
    while((_Pointer) != NULL)\
    {\
        if(_Test)\
            break;\
        (_Pos)++;\
        SCR_M_DyAr_GetNextElement(_Cast, _Pos, _Pointer, _Array);\
    }\
}
 
/*
 *	Simply pack an array by just adjusting its size.
 *	_Cast	:	Cast of an element in array.
 *	_Array	:	Array to realloc.
 */
#define SCR_M_DyAr_SimplePackArray(_Cast, _Array)\
{\
	/* Realloc array */\
	if((_Array).uiNumValues != (_Array).uiMaxValues)\
	{\
		if((_Array).uiNumValues == 0)\
		{\
			fn_v_Mem_SetMode(0);\
			SCR_M_Mem_Free((_Array).d_stDynArray);\
		}\
		else\
		{\
			fn_v_Mem_SetMode(0);\
			SCR_M_Mem_Realloc(SCR_tdst_DyAr_Element, (_Array).d_stDynArray, (_Array).d_stDynArray, (_Array).uiNumValues, 0);\
		}\
		(_Array).uiMaxValues = (_Array).uiNumValues;\
	}\
}
 
/*
 *	To reduce the size of a dynamic array by filliing the free places.
 *	_Cast	:	Cast of an element.
 *	_Array	:	Dynamic array to reduce.
 *	_Code	:	Eventual code to execute.
 */
#define SCR_M_DyAr_PackArray(_Cast, _Array, _Code)\
{\
	_Cast	*_p_stPointer_;\
	int		_DyAr_iEndPos_;\
	int		_DyAr_iBegPos_ = (_Array).uiNumValues - 1;\
	if(_Array.uiNumValues)\
	{\
		/* Search the last non free place of array */\
		while\
		(\
			(_DyAr_iBegPos_ >= 0)\
		&&	((_Array).d_stDynArray[_DyAr_iBegPos_].eState == SCR_EDAS_DyAr_Free)\
		)\
		{\
			_DyAr_iBegPos_--;\
			(_Array).uiNumValues--;\
		}\
		_DyAr_iEndPos_ = _DyAr_iBegPos_;\
		while(_DyAr_iBegPos_ >= 0)\
		{\
			/* Search the last free place in array */\
			while\
			(\
				(_DyAr_iBegPos_ >= 0)\
			&&	((_Array).d_stDynArray[_DyAr_iBegPos_].eState != SCR_EDAS_DyAr_Free)\
			)\
			{\
				_DyAr_iBegPos_--;\
			}\
			/* We find a home and must fill it with the last non free of array */\
			if(_DyAr_iBegPos_ >= 0)\
			{\
				memcpy\
				(\
					&((_Array).d_stDynArray[_DyAr_iBegPos_]),\
					&((_Array).d_stDynArray[_DyAr_iEndPos_]),\
					sizeof(SCR_tdst_DyAr_Element)\
				);\
				(_Array).uiNumValues--;\
				{_Code;}\
				_DyAr_iBegPos_--;\
				_DyAr_iEndPos_--;\
			}\
		}\
	}\
	if(_Array.uiMaxValues)\
	{\
		/* Simple pack array */\
		SCR_M_DyAr_SimplePackArray(_Cast, _Array);\
		/* Recompute "uiIndexInArray" field */\
		for(_DyAr_iBegPos_ = 0; (unsigned int) _DyAr_iBegPos_ < (_Array).uiNumValues; _DyAr_iBegPos_++)\
		{\
			SCR_M_DyAr_GetElement(_Cast, _DyAr_iBegPos_, _p_stPointer_, _Array);\
			_p_stPointer_->stHeader.uiIndexInArray = _DyAr_iBegPos_;\
		}\
	}\
}
 
#endif /* !__SCR_DyAr_h__Macros && !__Only_Types__ */
 
/*
 *=================================================================================================
 *  Protos.
 *=================================================================================================
 */
 
#if !defined(__SCR_DyAr_h__Protos) && !defined(__Only_Types__)
#define __SCR_DyAr_h__Protos
 
extern void         fn_v_DyAr_InitArray(SCR_tdst_DyAr_Description *);
 
extern unsigned int fn_ui_DyAr_AllocateElement(SCR_tdst_DyAr_Description *, char);
 
#endif /* !__SCR_DyAr_h__Protos && !__Only_Types__ */
