#include <crtdbg.h>
#include "RQSnapshotInternal.h"
#include "RQThreadInternal.h"
#include "RQTErrorInternal.h"
#include "RQRawScanProtected.h"

// Called on data available.  RQ_Lock and threadCriticalSection lock are already held.
NDTS_Boolean RQT_UpdateSnapshot(unsigned long cardIndex)
{
	unsigned long numberOfBScansInBank, maxBScansInBank, step, bank, numberOfDescriptions;
	RQT_State *pThreadState = RQT_ReturnThreadStatePointer(cardIndex) ;
	RQ_RawScan tempRawScan ;
	RQ_RawScan *pRawScan = &tempRawScan;
	RQ_CardBlockDescription *pDataBCardBlockDescriptions  = 0 ; 
	NDTS_Boolean isOk = NDTS_BTrue;
	if (!pThreadState) return NDTS_BFalse; 

	bank = (pThreadState->snapshotState.snapshotBeingRead) ? 0 : 1 ;
	if (pThreadState->snapshotState.pRawScans[bank].numberOfAScansInBScan == 0) return NDTS_BTrue; // Not got valid sample parameters yet.

	isOk = RQ_GetNumberOfBScansInSRAM(cardIndex, &numberOfBScansInBank);
	if (!isOk && !RQT_HandleRQError())
		goto breakout2;

	isOk = RQ_GetNumberOfBScansPerBank(cardIndex, &maxBScansInBank);
	if (!isOk && !RQT_HandleRQError())
		goto breakout2;

	pThreadState->snapshotState.bScansThisSnapshot += numberOfBScansInBank;

	// Get the gate data in a temporary pRawScan.
	RQ_InitialiseRawScan(pRawScan) ;

	isOk = RQ_CopyStateToRawScan(cardIndex, pRawScan, NDTS_BTrue);
	if (!isOk && !RQT_HandleRQError())
		goto breakout1;

	// Create descriptions of raw gate result data. 
	isOk = RQ_CreateRawGateValueDescriptions(pRawScan, &pDataBCardBlockDescriptions, &numberOfDescriptions);
	if (!isOk && !RQT_HandleRQError())
		goto breakout1;

	isOk = RQ_AllocRawScanDataBMemoryBlockNode(pRawScan);
	if (!isOk && !RQT_HandleRQError())
		goto breakout1;

	isOk = RQ_ReadRawScanGateValues(cardIndex, pRawScan, pDataBCardBlockDescriptions, numberOfDescriptions);
	if (!isOk && !RQT_HandleRQError())
		goto breakout1;

#ifdef _DEBUG
	RQ_ValidateRawScan(pRawScan);
#endif

	RQ_FreeRawDescriptions(pDataBCardBlockDescriptions) ;

	// Update the selected data for this bank using only the new gate data
	for (step=0; step<pRawScan->numberOfAScansInBScan; step++)
	{
		unsigned long aScanSelectionGateIndex = pThreadState->snapshotState.selectionParameters[step].gateIndex;
		short *pBuffer = pThreadState->snapshotState.aScanSamples[bank][step];
		short *pAmplitude = pThreadState->snapshotState.gateAmplitudes[bank][step];
		short *pDepth = pThreadState->snapshotState.gateDepths[bank][step];
		isOk = RQ_ExtractSnapshotOutput(cardIndex, pRawScan, step, aScanSelectionGateIndex, pBuffer, RQ_SRAM_MAXIMUM_NUMBER_OF_SAMPLES, pAmplitude, pDepth);
		if (!isOk && !RQT_HandleRQError())
			goto breakout1;
	}

	// Append the new gate / encoder data to the current bank's raw scan
	RQ_MoveRawScanDataToRawScan(&(pThreadState->snapshotState.pRawScans[bank]), pRawScan) ;
	_ASSERTE(pThreadState->snapshotState.bScansThisSnapshot == pThreadState->snapshotState.pRawScans[bank].numberOfBScans);

	// Finished with the temporary raw scan
breakout1:
	RQ_UninitialiseRawScan(pRawScan) ;

breakout2:
	isOk &= RQ_IndicateSampleDataDownloaded(cardIndex);

	return isOk;
}


NDTS_Boolean RQT_InitSnapshotDataBank(unsigned long cardIndex, unsigned long bank, NDTS_Boolean full)
{
	unsigned long numSteps, step, gate, sample ;
	RQT_State *pThreadState = RQT_ReturnThreadStatePointer(cardIndex) ;
	RQ_State *pBoardState = RQ_ReturnBoardStatePointer(cardIndex) ;
	if (!pThreadState) return NDTS_BFalse; 

	numSteps = (full) ? RQ_MAXIMUM_NUMBER_OF_STEPS : pBoardState->numberOfAScansPerBScan;

	for (step=0; step<numSteps; step++)
	{
		for(gate=0; gate< RQ_ReturnMaximumNumberOfGates(pBoardState->isSequence); gate++)
		{
			pThreadState->snapshotState.gateAmplitudes[bank][step][gate] = 0;
			pThreadState->snapshotState.gateDepths[bank][step][gate] = 0;

			switch(pBoardState->gates[step][gate].snapshotSelection)
			{
			case RQ_PDSMin:
				// Set to max so first scan to arrive will trigger a new min
				pThreadState->snapshotState.gateAmplitudes[bank][step][gate] = 0xfff;
				break;
			case RQ_PDSNearest:
				pThreadState->snapshotState.gateDepths[bank][step][gate] = 0x7fff;
				break;
			}
		}
		if (full && pThreadState->snapshotState.clearAScanOnUpdate)
		{
			// Clear down the sample array so if changing range, get zeros at end or if 
			// something goes wrong return flat line rather than garbage.
			short *pSamples = pThreadState->snapshotState.aScanSamples[bank][step];

			for (sample = 0 ; sample < RQ_SRAM_MAXIMUM_NUMBER_OF_SAMPLES ; sample++)
			{
				pSamples[sample] = 0;
			}
		}
	}

	{
		RQ_RawScan *pRawScan = &(pThreadState->snapshotState.pRawScans[bank]);

		// Free the raw scan data at the start of each new snapshot
		if (pRawScan->numberOfAScansInBScan != 0)
			RQ_FreeRawScanData(pRawScan, RQ_FRSOAll);
	}
	pThreadState->snapshotState.bScansThisSnapshot = 0;

	return NDTS_BTrue;
}


// Called from UpdateSampleParameters in rq.dll.  RQ_Lock() will be on before this is called.
// Does not set the last error because the fuction is called via RQ.dll.
void RQT_UpdateSnapshotSampleStorage(unsigned long cardIndex)
{
	unsigned long bank;
	RQ_RawScan *pRawScan;
	RQT_State *pThreadState = RQT_ReturnThreadStatePointer(cardIndex);
	if (!pThreadState) return ;
	
	for (bank=0; bank<NUMBER_OF_SNAPSHOT_BANKS; bank++)
	{
		pRawScan = &(pThreadState->snapshotState.pRawScans[bank]);

		if (!RQ_CopyStateToRawScan(cardIndex, pRawScan, NDTS_BFalse)) 
			return ;

		if (bank == 0)
		{
			// Only need to allocate the memory pools once
//			if (!RQ_AllocRawScanMemoryPools(pRawScan)) 
			if (!RQ_AllocCardMemoryPools(cardIndex)) 
				return;
		}
	 ;

		if (!RQT_InitSnapshotDataBank(cardIndex, bank, NDTS_BTrue)) 
			return ;
	}
}

