/******************************************************************************
*
* Internal definitions - not for inclusion by application code.
*
******************************************************************************/
#pragma once


#define WAIT_FOR_SAMPLES_TIMEOUT_MILLIS 1000

#include <windows.h>
#include <limits.h>

#include "NDTS2100Sdk.h"
#include "NDTSEnums.h"
#include "NDTS2100Errors.h"
//#include "RQRawScan.h"
//#include "RQProtected.h"
#include "PropertiesInterface.h"
#include "TCG.h"
#include "PropertiesCollection.h"
#include "HardwareInitialise.h"
#include "RawScanProtected.h"

NDTS_Boolean CALL_CONV NDTS2100_DLLInitialise() ;
NDTS_Boolean CALL_CONV NDTS2100_DLLUninitialise() ;
NDTS_Boolean NDTS2100_InitialiseInternal();
void NDTS2100_HardwareInitialiseFailed();

// Functions that are callbacks from the data collection.dll
NDTS2100_API void CALL_CONV NDTS2100_Lock(unsigned long cardIndex);
NDTS2100_API void CALL_CONV NDTS2100_Unlock(unsigned long cardIndex);
NDTS2100_API NDTS_Boolean CALL_CONV NDTS2100_GetNumberOfBScansInSRAM(unsigned long cardIndex, unsigned long *numberOfScans);

namespace NDTS
{
	namespace NDTS2100
	{
		
		// Internal constants that are used within the SDK but not exposed to applications
		// Constants that are available to applications are defined in NDTS2100SDK.h

		// Note that the sampleFrequencyHz here is the physical sample freqeuncy of the card whilst the SampleFrequency property
		// is scaled by the drop samples.

		// Spartan 3 firmware runs at 100Mhz
		static const int baseSampleFrequencyHz = 100000000;
		// May not need this to be so high for 2100 (was 50 on rs2A)
		static const int repSafetySamples = 100;

		// This all needs sorting out - the RAM is bank switched and
		// these addresses have been set to use just one 4MB bank.
		// The DataCollection.dll will need to be modified to work with bank switching.

		// keep C Scan memory in the same RAM Window 4M memory bank as the A Scan data for now as DataCollection hasn't got code for window switching
		// The total memory bank size (aScanMemoryBankSize + cScanMemoryBankSize) must be 0x00400000 - see NDTS2100_SetRAMWindow
		static const int aScanBaseAddress =    0x00400000;
		static const int aScanMemoryBankSize = 0x00300000; 
		static const int cScanMemoryBankSize = 0x00100000;

		static const int stepRegisterIncrement = 0x200;
		static const int gateRegisterIncrement = 0x04;

		static const NDTS_SampleSize sampleSize =  NDTS_SS12Bit;
		static const int bytesPerSample = 2;

		static const NDTS_ScanStorage scanStorage =  NDTS_SSMultipleAScanMultipleCScan;  // See comment in NDTS2100_ResetFirmware

		static const int gateResultBytes = 8;  // Gates are 8 bytes on NDTS2100

		static const NDTS_Boolean isCRCCheckPresent = NDTS_BTrue;
		static const int crcBytes = (isCRCCheckPresent) ? 4 : 0;

		static const unsigned long	numberToCheckEitherSide = 0;  // If noise filtering is required, move these inside DataCollectionValues and create properties for them.
		static const float			proportionToTriggerOff = 1.0;
		static const NDTS_SnapshotDataSelection snapshotSelection = NDTS_PDSLatest;   // Move this to a per gate setting if snapshot selection is required

		// Variables that are used by the data collection.dll and RawScan.dll
		// via C callback functions
		// They are updated in the postSetHook
		typedef struct
		{
			bool isSoftwareTriggered;
			bool isFullACapture;

			unsigned long aScanSampleValuesThisStep[maxSteps];
			unsigned long aScanOffsetThisStep[maxSteps];
			unsigned long aScanBytesPerBScan;

			unsigned long gateOffsetThisStep[maxSteps];
			unsigned char gateCountThisStep[maxSteps]; // initialise all to 1
			unsigned long gateBytesPerBScan;

			RawScanGateSettings  ppGateSettings[maxSteps][maxGates];

		} DataCollectionValues;

		// Variables that need to be used in C code as well as C++
		typedef struct
		{
			int numberOfCards;
			bool isRealHardwareFound;
			bool isInitialised;
			TCGInternal *pTcg;
			int numberOfSteps[maxCards];  
			unsigned long bScansInSnapshot[maxCards];

			// Multicard - see comment in NDTS2100_Lock
			CRITICAL_SECTION criticalSection ;
			unsigned long lockEntryCount;

			DataCollectionValues dataCollectionValues[maxCards];

			void (*pUpdateSampleParametersHook)(unsigned long cardIndex);
		} NDTS2100_GlobalState ;

		extern NDTS2100_GlobalState globalState ;

		// Implementations of the classes that provide the non property side of the interface to the app
		class SnapshotInternal : public Snapshot
		{
		public:
			SnapshotInternal() {};
			virtual ~SnapshotInternal() {};
			virtual bool getAScan(int cardIndex, int sequenceIndex, int bScanIndex, short *pSamples, int numberOfBufferValues) ;
			virtual int returnNumberOfAScanSamples(int cardIndex, int sequenceIndex) ;
			virtual bool getPackedGateData(int cardIndex, int sequenceIndex, int bScanIndex, GateOutput *pGateOutputs, int numberOfBufferValues) ;
			virtual bool getUnPackedGateData(int cardIndex, int sequenceIndex, int bScanIndex, GateOutput *pGateOutputs, int numberOfBufferValues) ;
			virtual bool getEncoderValues(int cardIndex, int bScanIndex, int *pEncoderValues, int numberOfBufferValues);
			void takeSnapshot(int cardIndex);
			int GetNumberOfBScansInSnapshot(int cardIndex);
		};

		class ErrorLogInternal : public ErrorLog
		{
		public:
			ErrorLogInternal() {};
			virtual ~ErrorLogInternal() {};
			virtual bool getErrorLogLine(int lineNumber, char *pMessageBuffer, int numberOfBytesInMessageBuffer);
		};

		// The TCGInternal class is declared in tcg.h / tcg.cpp
		class FactoryInternal : public Factory
		{
		public:
			FactoryInternal();
			virtual ~FactoryInternal();

		public:
			virtual Snapshot *getSnapshot();
			virtual ErrorLog *getErrorLog();
			virtual TCG *getTcg();
			virtual NDTS::SCO::Property *getRootProperty();
			virtual bool initialise();
			virtual void uninitialise();

			// For use by the SDKPropertiesCollection class
			SnapshotInternal *getSnapshotInternal();
			TCGInternal *getTCGInternal();
			
		private:
			SnapshotInternal snapshot;
			ErrorLogInternal errorLog;
			TCGInternal tcg;
			SDKPropertiesCollection *pPropertiesCollection;
			HardwareInitialise hardwareInitialise;
		};

		class StackBasedLock 
		{	
		public:
			StackBasedLock(unsigned long cardIndex);
			virtual ~StackBasedLock();
			void unlockEarly();
		private:
			unsigned long 	cardIndex;
			bool unlockedEarly;
		};
	}
}


