#include <stdinc.h>
#include <stdarg.h>

#include "LDT.h"
#include "refs.h"
#include "DynArray.h"
#include "Error.h"

extern LDT_tdst_Link *g_pGetFrom;
extern int g_nInitialized;

LDT_tdst_DSArray g_ArSolvers;

int SortRefs( const void **A, const void **B )
{
	tdst_Ref *pA, *pB;
	pA=(tdst_Ref *)*A;
	pB=(tdst_Ref *)*B;

	if( pA->iType<pB->iType)
		return 1;
	else if( pA->iType>pB->iType)
		return -1;
	return 0;
}

int SortSolvers( const void **A, const void **B )
{
	tdst_Solver *pA, *pB;
	pA=(tdst_Solver *)*A;
	pB=(tdst_Solver *)*B;

	if( pA->iPriority<pB->iPriority)
		return -1;
	else if( pA->iPriority>pB->iPriority)
		return 1;
	return 0;
}

HREF LDT_CreateRefsTable( )
{
	LDT_tdst_DSArray* pRef=LDT_DSAr_new();
	LDT_DSAr_SetGranularity( pRef, 50 );

	LDT_DSAr_SetSortMethod( pRef, SortRefs );
	return (HREF)pRef; 
}

void LDT_AddToRefsTable( HREF hRef, LDT_tdst_Link* pObj,  int iType, short xCount, ... )
{
	LDT_tdst_DSArray* pRef=(LDT_tdst_DSArray *)hRef;
	tdst_Ref *pSt=(tdst_Ref *)malloc( sizeof(tdst_Ref) );
	
	pSt->pObject=pObj;
	pSt->pGetFrom=g_pGetFrom;
	pSt->iType=iType;

	pSt->xCount=xCount;
	if( xCount )
	{
		int i;
		va_list vaList;
		
		pSt->pVal=(long *)malloc( xCount*sizeof( long ) );

		va_start( vaList, xCount );
		for( i=0; i<xCount; i++ )
			pSt->pVal[i]=va_arg( vaList, long );

		va_end( vaList );
	}
	else pSt->pVal=NULL;
	
	pObj->wUnsolvedRefs++;

	LDT_DSAr_SAdd( pRef, (void *)pSt, 1, NULL );
}

long pValues[128];

int LDT_GetRefFromTable( HREF hRef, LDT_tdst_Link **pObj, LDT_tdst_Link **pGetFrom, int *iType, short *xCount, long **pVal )
{
	LDT_tdst_DSArray* pRef=(LDT_tdst_DSArray *)hRef;
	int i=LDT_DSAr_GetUpperBound( pRef ), ii;
	tdst_Ref *pSt;

	if( i==-1 )
		return -1;
	
	for( ii=i; (ii>=0) && (pSt=(tdst_Ref *)LDT_DSAr_GetAt( pRef, ii ))->pGetFrom && pSt->pGetFrom->wUnsolvedRefs; ii--);
	
	if( ii<0 ) /* circular refs - problem ! */
		return -2;

	if( ii!=i ) /* swap */
	{
		void *pTemp=LDT_DSAr_GetAt( pRef, i );
		LDT_DSAr_SetAt( pRef, ii, pTemp );
	}

	LDT_DSAr_SetSize( pRef, i );

	*pObj=pSt->pObject;
	if( pSt->pGetFrom )
	*pGetFrom=pSt->pGetFrom;
	else *pGetFrom=NULL;
	*iType=pSt->iType;
	*xCount=pSt->xCount;
	if(pSt->xCount)
	{
		memcpy(pValues, pSt->pVal, pSt->xCount*sizeof(long));
		*pVal=pValues;
		free(pSt->pVal);
	}
	else
		*pVal = NULL;

	pSt->pObject->wUnsolvedRefs--;

	free( pSt );
	return 0;
}

#pragma warning( disable:4100 )
void LDT_FreeRefValues( long *p )
{
//	free( p ); the function is here only for backwards compatibility
}
#pragma warning( default:4100 )

HREF LDT_RegisterSolver( void(* Solve)(HREF), int iPri )
{
	tdst_Solver *pSolver;
	
	if(!g_nInitialized )
	{
#if defined(LDT_ERROR_TREATMENT)
		ERRoR(0, NULL, 0, "Call LDT_Initialize prior to solver registration !");
#endif
		return NULL;
	}

	pSolver=(tdst_Solver *)malloc( sizeof(tdst_Solver) );

	pSolver->Solve=Solve;
	pSolver->iPriority=iPri;

	if( LDT_DSAr_SAdd( &g_ArSolvers, (void *)pSolver, 0, NULL ) <0 )
	{
#if defined(LDT_ERROR_TREATMENT)
		ERRoR(0, NULL, 0, "Solver registration failed. The priority slot is in use. Please choose a different priority number.");
#endif
		free (pSolver);
		return NULL;
	}
	pSolver->hRef=LDT_CreateRefsTable();

	return pSolver->hRef;
}

