#pragma once

#include "PropertyInternal.h"
#include "NDTSEnums.h"

namespace NDTS
{
namespace SCO
{
	// Interface to a class that is SDK specific and can be used instead of function pointers to send 
	// values to and from hardware.
	// The SDK should inherit from this class and the inherited class can store information 
	// about how this property relates to 
	// the hardware, e.g. register address, card number, sequence step, ...
	// The class contains set and get functions that the IntProperty class calls to send values to and from hardware.
	// The set and get functions must be overridden if this class is used in the hardware specific SDK.
	class 	IntPropertyInternal;



	// The PropertyInternal etc. classes follow the same inheritance tree as the Property interface classes
	// The interface classes are all inherited using virtual and the Internal classes using Public
	// This tells the compiler that the implementation is in the Internal classes rather than the interface class
	// However, the compiler throws up a warning which is diabled by the pragma below
	// Ignore warning	'NDTS::SCO::EnumPropertyInternal' : inherits 'NDTS::SCO::PropertyInternal::NDTS::SCO::PropertyInternal::getShortName' via dominance		
	#pragma warning (disable :4250)

	class SCO_API IntPropertyInternal :	public  PropertyInternal, public virtual IntProperty
	{
	public:

		///////////////////////////////////////////////////////
		// Constructors are not available to applications.
		// Applications should only use properties defined by an SDK
		///////////////////////////////////////////////////////

		// Normal "Output" property that sets a value in the SDK, e.g. range etc...
		IntPropertyInternal(char *pShortName, char *pLongName, int flags, int defaultValue, int min, int max, int primaryIndex, NDTS_Boolean (*pSetFunction)(unsigned long, unsigned long));
		// "Input" property that reads a value, e.g. a live encoder or analogue value.  Contains two indices
		IntPropertyInternal(char *pShortName, char *pLongName, int flags, int primaryIndex,  NDTS_Boolean (*pGetFunction)(unsigned long, unsigned long*), bool resultCanBeNegative = false);
		// Property with separate input and output functions, e.g. Digital I/O
		IntPropertyInternal(char *pShortName, char *pLongName, int flags, int defaultValue, int min, int max, int primaryIndex, NDTS_Boolean (*pSetFunction)(unsigned long, unsigned long), NDTS_Boolean (*pGetFunction)(unsigned long, unsigned long*));
		// Property that uses a hardware access class rather than function pointers
		IntPropertyInternal(char *pShortName, char *pLongName, int flags, int defaultValue, int min, int max, HardwareAccessClass *pHardwareAccessObject, HardwareAccessClassUsage hardwareAccessClassUsage = writeToHardwareReadFromCachedValue);
		// As above but uses an enumToValueMap to translate user values into register values.
		IntPropertyInternal(char *pShortName, char *pLongName, int flags, int defaultValue, int min, int max, int *enumToValueMap, int numberOfEnums, HardwareAccessClass *pHardwareAccessObject, HardwareAccessClassUsage hardwareAccessClassUsage = writeToHardwareReadFromCachedValue);
		// Read only property that uses a hardware access class
		IntPropertyInternal(char *pShortName, char *pLongName, int flags, HardwareAccessClass *pHardwareAccessObject);

		virtual ~IntPropertyInternal(void);

		
		///////////////////////////////////////////////////////
		// Functions externally accessible to applications
		///////////////////////////////////////////////////////
		virtual int getValue();
		virtual void setValue(int value);
		virtual int getMin();
		virtual int getMax();

		///////////////////////////////////////////////////////
		// Functions for use inside the SDK and not by an app
		///////////////////////////////////////////////////////
		virtual void initComplete(void);

		// Update and add to change log - for use with pPostSetUpdateHook - not for use with application
		// Returns true if a new change event has been logged.
		void updateValue(int newValue);
		void updateMin(int newMin);
		void updateMax(int newMax);

		bool isVisible; // Is this property visible to the outside world.  Default to true.
		// Only for use by the parent group and postCommit hook
		bool getHaveUncommittedChange();
		int getUncommittedValue();
		HardwareAccessClass *getHardwareAccessObject();

	private:
		int value;
		int defaultValue;
		int min;
		int max;
		int staticMin;
		int staticMax;
		int primaryIndex;
		NDTS_Boolean (*pSetFunction)(unsigned long, unsigned long);
		NDTS_Boolean (*pGetFunction)(unsigned long, unsigned long*);
		int uncommittedValue;
		bool haveUncommittedChange;
		bool getResultCanBeNegative;
		// Hardware access objects may be used instead of function pointers
		HardwareAccessClass *pHardwareAccessObject;
		HardwareAccessClassUsage hardwareAccessClassUsage;

		// Can be supplied in the constructor to map a list of indices (enums) to SDK values.
		// For example 0 sets 12 in hardware, 1 sets 1, 2 sets 15 etc.
		int numberOfEnums;
		int *enumToValueMap;

	};

}}
