#include <limits.h>
#include <crtdbg.h>
#include "EventPropertyInternal.h"
#include "GroupPropertyInternal.h"
#include "Log.h"
#include "NdtsError.h"

namespace NDTS
{
	namespace SCO
	{
	SCO_API EventPropertyInternal::EventPropertyInternal(char *pShortName, char *pLongName, int flags, int primaryIndex, NDTS_Boolean (*pSetFunction)(unsigned long)): PropertyInternal(pShortName, pLongName, flags)
	{
		this->pSetFunction = pSetFunction;
		this->primaryIndex = primaryIndex;
		pHardwareAccessObject = 0;
		haveUncommittedChange = false;
	}
	SCO_API EventPropertyInternal::EventPropertyInternal(char *pShortName, char *pLongName, int flags,  HardwareAccessClass *pHardwareAccessObject): PropertyInternal(pShortName, pLongName, flags)
	{
		this->pHardwareAccessObject = pHardwareAccessObject;
		this->pHardwareAccessObject->pAssociatedProperty = this;
		this->pSetFunction = 0;
		this->primaryIndex = 0;
		haveUncommittedChange = false;
	}

	SCO_API EventPropertyInternal::~EventPropertyInternal(void)
	{
	}

	SCO_API void EventPropertyInternal::initComplete(void)
	{
		PropertyInternal::initComplete();
		if (pSetFunction || pHardwareAccessObject)
			doEvent();
	}

	bool EventPropertyInternal::getHaveUncommittedChange()
	{
		return haveUncommittedChange;
	}

	// Return true if the value has been set to the value requested with no additions to the change or error logs.
	void EventPropertyInternal::doEvent()
	{
		// If in a group of changes, remember the value but don't range check or apply it
		// Events commit to the SDK like an Int and so can be applied at the same stage of a group commit
		if (pParent->isInIntGroupChange())
		{
			haveUncommittedChange = true;
			return;
		}
		haveUncommittedChange = false;

		// Null set function pointer means the property is read only
		if (pSetFunction == 0 && pHardwareAccessObject == 0)
		{
			pLog->addError(SCO_PropertyIsReadOnly);	
			return;
		}

		if (!pParent->isOkToSet(this))
			return;


		if (pSetFunction && !pSetFunction(primaryIndex))
		{
			pLog->addMessageToLog(NDTS_LLDebug, "doEvent call failed in %s", pShortName);
			return;
		}

		if (pHardwareAccessObject && !pHardwareAccessObject->setValue(0))
		{
			pLog->addMessageToLog(NDTS_LLDebug, "doEvent call failed in %s", pShortName);
			return;
		}

		pParent->postEventUpdate(this);
	}

	HardwareAccessClass *EventPropertyInternal::getHardwareAccessObject()
	{
		return pHardwareAccessObject;
	}

}};