#include <windows.h>

#include "RQ.h"
#include "RQCollect.h"
#include "NDTSRS2AConstants.h"

#include "NDTSRS2A.h"
#include "NDTSRS2AInternal.h"


// Turn off warning C4100 : unreferenced formal parameter for this function
#pragma warning(push)
#pragma warning(disable : 4100) 
 
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{ 
	switch (ul_reason_for_call)
	{ 
		case DLL_PROCESS_ATTACH :
			break ;
		case DLL_PROCESS_DETACH :
			break ;
		case DLL_THREAD_ATTACH :
			break ;
		case DLL_THREAD_DETACH :
			break ;
    }

    return TRUE ;
}

#pragma warning(pop)


RS2A_API NDTS_Boolean CALL_CONV RS2A_Initialise()
{
	NDTS_Boolean isOK ;

	rs2aGlobalState.cardIndex = 0 ;
	rs2aGlobalState.pRawScan = 0 ;

	isOK = RQ_InitialiseNonSequenced(rs2aGlobalState.cardIndex) ;
	if (!isOK)
		return NDTS_BFalse ;

	//*** check RapidScan 2 to see what it initialises and stick in RQ_InitialiseNonSequenced

	return isOK ;
}

RS2A_API NDTS_Boolean CALL_CONV RS2A_Uninitialise()
{
	return NDTS_BTrue ;
}

RS2A_API NDTS_Boolean CALL_CONV RS2A_TakeSnapshot(unsigned long *pNumberOfBScans)
{
	NDTS_Boolean isOK ;
	RQ_Trigger trigger ;

	// Clear this down so we can drop out later if there's any problem
	*pNumberOfBScans = 0 ;

	// Get trigger mode
	isOK = RQ_GetTriggerSelect(rs2aGlobalState.cardIndex, &trigger) ;
	if (!isOK)
		return NDTS_BFalse ;

	// We only support software and encoder triggers at the moment
	if (trigger != RQ_TInternal && trigger != RQ_TEncoder)
	{
		RS2A_HandleRS2AError(RS2A_TakeSnapshot_UnsupportedTriggerMode) ;
		return NDTS_BFalse ;
	}

	// Free up the old raw-scan
	isOK = RQ_FreeRawScanData(rs2aGlobalState.pRawScan, RQ_FRSOAll) ;
	if (!isOK)
		return NDTS_BFalse ;

	// If software triggered, do the trigger and poll until we have data
	if (trigger == RQ_TInternal)
	{
		isOK = RQ_SetForceBScanTrigger(rs2aGlobalState.cardIndex) ;
		if (!isOK)
			return NDTS_BFalse ;

		// Poll RQ_GetIsSomeDataSampled until we have samples or we get a time-out
		{
			DWORD startTime = timeGetTime() ;
			NDTS_Boolean isTimeOut = NDTS_BFalse,
						isSomeDataSampled = NDTS_BFalse ;

			do
			{
				isOK = RQ_GetIsSomeDataSampled(rs2aGlobalState.cardIndex, &isSomeDataSampled) ;
				if (isOK && !isSomeDataSampled)
					isTimeOut = timeGetTime() - startTime > RS2A_WAIT_FOR_SAMPLES_TIMEOUT_MILLIS ? NDTS_BTrue : NDTS_BFalse ;
			}
			while (isOK && !isSomeDataSampled && !isTimeOut) ;

			if (isTimeOut)
			{
				RS2A_HandleRS2AError(RS2A_TakeSnapshot_TimeoutWaitingForSamples) ;
				isOK = NDTS_BFalse ;
			}
		}
		if (!isOK)
			return NDTS_BFalse ;
	}

	// Finally, get the raw-scan and store it in the global state
	isOK = RQT_GetRawScan(rs2aGlobalState.cardIndex, rs2aGlobalState.pRawScan) ;

	// If everything is OK, return the number of B-scans
	*pNumberOfBScans = isOK ? rs2aGlobalState.pRawScan->numberOfBScans : 0 ;

	return isOK ;
}

RS2A_API NDTS_Boolean CALL_CONV RS2A_GetAScan(unsigned long bScanIndex, unsigned long aScanIndex, short *pSamples, unsigned long numberOfBufferValues)
{
	// Just pass this through to the RQ SDK with our raw-scan
	return RQ_ExtractAScan(bScanIndex, aScanIndex, rs2aGlobalState.pRawScan, pSamples, numberOfBufferValues) ;
}

RS2A_API NDTS_Boolean CALL_CONV RS2A_GetGateData(unsigned long bScanIndex, unsigned long aScanIndex, RQ_GateOutput *pGateOutputs, unsigned long numberOfBufferValues)
{
	// Just pass this through to the RQ SDK with our raw-scan
	return RQ_ExtractGateValues(bScanIndex, aScanIndex, rs2aGlobalState.pRawScan, pGateOutputs, numberOfBufferValues) ;
}

RS2A_API NDTS_Boolean CALL_CONV RS2A_GetEncoderData(unsigned long bScanIndex, long *pEncoderValues, unsigned long numberOfBufferValues)
{
	unsigned long numberOfValidEncoderValues = numberOfBufferValues < RQ_NUMBER_OF_ENCODERS ? numberOfBufferValues : RQ_NUMBER_OF_ENCODERS,
		          i = 0 ;
	NDTS_Boolean isOK ;

	// Use RQ SDK to extract each value
	do
	{
		isOK = RQ_ExtractEncoderValue(bScanIndex, i, rs2aGlobalState.pRawScan, &pEncoderValues[i]) ;
		i++ ;
	}
	while (isOK && i < numberOfValidEncoderValues) ;
	if (!isOK)
		return NDTS_BFalse ;

	// Fill in any remaining part of input array with zeros. That'll teach anyone to set numberOfBufferValues == -1
	for (i = numberOfValidEncoderValues ; i < numberOfBufferValues ; i++)
		pEncoderValues[i] = 0 ;

	return isOK ;
}
