#include "RQThreadInternal.h"
#include "RQSnapshotInternal.h"
#include "RQProtected.h"
#include "RQTErrorInternal.h"
#include "RQOfflineInternal.h"

RQ_API NDTS_Boolean RQT_SnapshotInitialise(unsigned long cardIndex)
{
	unsigned long step, bank;
	RQT_State *pThreadState; 

	if (!RQT_Initialise(cardIndex)) return NDTS_BFalse;
	pThreadState = RQT_ReturnThreadStatePointer(cardIndex) ;
	if (!pThreadState) return NDTS_BFalse; 
	RQ_Lock(cardIndex);

	pThreadState->snapshotState.snapshotBeingRead = 0;
	pThreadState->snapshotState.bScansThisSnapshot = 0;
	for (bank=0; bank<NUMBER_OF_SNAPSHOT_BANKS; bank++)
	{
		RQ_InitialiseRawScan(&(pThreadState->snapshotState.pRawScans[bank]));
		pThreadState->snapshotState.pDataBCardBlockDescriptions[bank] = 0;
		pThreadState->snapshotState.numDataBCardBlockDescriptions[bank] = 0;
	}

	for (step=0; step<RQ_MAXIMUM_NUMBER_OF_STEPS; step++)
	{
		pThreadState->snapshotState.selectionParameters[step].gateIndex = 0;
	}
	pThreadState->snapshotState.clearAScanOnUpdate = NDTS_BTrue;
	RQ_Unlock(cardIndex);
	return RQT_SetThreadState(cardIndex, RQT_SMSSnapshot);
}

RQ_API NDTS_Boolean RQT_SnapshotUninitialise(unsigned long cardIndex)
{
	NDTS_Boolean isOK;
	unsigned long bank;
	RQT_State *pThreadState; 
	pThreadState = RQT_ReturnThreadStatePointer(cardIndex) ;
	if (!pThreadState) return NDTS_BFalse; 


	RQ_Lock(cardIndex);
	for (bank=0; bank<NUMBER_OF_SNAPSHOT_BANKS; bank++)
	{
		RQ_RawScan *pRawScan = &(pThreadState->snapshotState.pRawScans[bank]);
		if (!RQ_FreeRawScanData(pRawScan, RQ_FRSOAll)) 
		{
			if (!RQT_HandleRQError())
			{
				RQ_Unlock(cardIndex);
				return NDTS_BFalse;
			}
		}
		RQ_UninitialiseRawScan(pRawScan);
	}

	//TODO: Remove RQT_UpdateSnapshotSampleStorage from UpdateParametes hook 
	RQ_Unlock(cardIndex);

	isOK = RQT_Uninitialise(cardIndex);
	if (!isOK)
	{
		return NDTS_BFalse;
	}

	return NDTS_BTrue;
}


RQ_API NDTS_Boolean RQT_SetAScanSelectionGate(unsigned long cardIndex, unsigned long stepIndex, unsigned long gateIndex)
{
	RQT_State *pThreadState = RQT_ReturnThreadStatePointer(cardIndex) ;
	if (!pThreadState) return NDTS_BFalse; 
	RQ_Lock(cardIndex);

	pThreadState->snapshotState.selectionParameters[stepIndex].gateIndex = gateIndex;

	RQ_Unlock(cardIndex);
	return NDTS_BTrue;
}


RQ_API NDTS_Boolean RQT_GetAScanAndGateDataFromSnapshot(unsigned long cardIndex, unsigned long step, short *pBuffer, unsigned long numberOfBufferValues, short *pAmplitude, short *pDepth) 
{
	RQT_State *pThreadState = RQT_ReturnThreadStatePointer(cardIndex) ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	unsigned long unpackedGate, sample, bank;
	if (!pThreadState) return NDTS_BFalse; 
	RQ_Lock(cardIndex);

	bank = pThreadState->snapshotState.snapshotBeingRead;

	for (unpackedGate = 0; unpackedGate < RQ_ReturnMaximumNumberOfGates(pBoardState->isSequence); unpackedGate++)
	{
		pAmplitude[unpackedGate] = pThreadState->snapshotState.gateAmplitudes[bank][step][unpackedGate];
		pDepth[unpackedGate] = pThreadState->snapshotState.gateDepths[bank][step][unpackedGate];
	}

	for (sample=0; sample<numberOfBufferValues; sample++)
	{
		pBuffer[sample] = pThreadState->snapshotState.aScanSamples[bank][step][sample];
	}

	RQ_Unlock(cardIndex);
	return NDTS_BTrue;
}



RQ_API NDTS_Boolean RQT_GetGateDataFromSnapshot(unsigned long cardIndex, unsigned long bScanIndex, RQ_GateOutput *pGateData, int nSteps, int nGates)
{
	RQT_State *pThreadState = RQT_ReturnThreadStatePointer(cardIndex) ;
	RQ_RawScan *pRawScan;
	unsigned long bank;
	if (!pThreadState) return NDTS_BFalse; 

	bank = (pThreadState->snapshotState.snapshotBeingRead);
	pRawScan = &(pThreadState->snapshotState.pRawScans[bank]);

	return RQ_ExtractGateValuesSequenced(bScanIndex, pRawScan, pGateData, nSteps, nGates);
}

RQ_API NDTS_Boolean RQT_GetEncoderDataFromSnapshot(unsigned long cardIndex, unsigned long bScanIndex, long *pEncoders, int nEncoders)
{
	RQT_State *pThreadState = RQT_ReturnThreadStatePointer(cardIndex) ;
	RQ_RawScan *pRawScan;
	unsigned long bank;
	if (!pThreadState) return NDTS_BFalse; 

	bank = (pThreadState->snapshotState.snapshotBeingRead);
	pRawScan = &(pThreadState->snapshotState.pRawScans[bank]);
	return RQ_ExtractEncoderValuesProtected(bScanIndex, pRawScan, pEncoders, nEncoders);
}

RQ_API NDTS_Boolean RQT_SwapSnapshotDataBank(unsigned long cardIndex, unsigned long *numberOfBScans)
{
	RQT_State *pThreadState = RQT_ReturnThreadStatePointer(cardIndex) ;
	unsigned long samplingStatus;
	if (!pThreadState) return NDTS_BFalse; 

	if (!RQ_GetDataSamplingStatus(cardIndex, &samplingStatus))
		return NDTS_BFalse;
	if (samplingStatus != 0)
	{
		// Must be called outside RQ_Lock so thread can run
		if (!RQT_BankSwapAndUpdate(cardIndex))
			return NDTS_BFalse;
	} 

	RQ_Lock(cardIndex);

	if (numberOfBScans) *numberOfBScans = pThreadState->snapshotState.bScansThisSnapshot;

	if (!RQT_InitSnapshotDataBank(cardIndex, pThreadState->snapshotState.snapshotBeingRead, NDTS_BFalse))
	{
		RQ_Unlock(cardIndex);
		return NDTS_BFalse;
	}
	pThreadState->snapshotState.snapshotBeingRead = (pThreadState->snapshotState.snapshotBeingRead) ? 0 : 1;

	RQ_Unlock(cardIndex);
	return NDTS_BTrue;
}

RQ_API unsigned long RQT_ReturnNumberOfBScansInSnapshot(unsigned long cardIndex)
{
	RQT_State *pThreadState = RQT_ReturnThreadStatePointer(cardIndex) ;
	int bank = (pThreadState->snapshotState.snapshotBeingRead);
	return (pThreadState->snapshotState.pRawScans[bank].numberOfBScans);

}

RQ_API NDTS_Boolean RQT_SetClearAScanOnUpdate(unsigned long cardIndex, NDTS_Boolean clearAScanOnUpdate)
{
	RQT_State *pThreadState = RQT_ReturnThreadStatePointer(cardIndex) ;
	pThreadState->snapshotState.clearAScanOnUpdate = clearAScanOnUpdate;
	return NDTS_BTrue;
}