// $Header$

/**************** Changes ******************
Date			Edit				Bug					Description
10-Aug-21	bjw0431a								Added public 64-bit property methods.
02-Aug-21	bjw0431                 RGBA color property support for JS client.
********************************************/

#pragma once
#include <unordered_map>
#include "basics.h"
#include "extcomp.he"


class AutoPropertyValues
{
private:
	std::unordered_map<attnumber, ECOproperty*>* mPropDefs;

	std::unordered_map<attnumber, qlong>* mLongProps = 0;
	std::unordered_map<attnumber, qlong64>* mLong64Props = 0; // bjw0431
	std::unordered_map<attnumber, qbool>* mBoolProps = 0;
	std::unordered_map<attnumber, std::string>* mStringProps = 0;
	std::unordered_map<attnumber, qreal>* mRealProps = 0;

	// Generic setter method to initialise the property map for this type, if it has not yet been done:
	template <typename T>
	qbool setProperty(attnumber propNumber, T propValue, std::unordered_map<attnumber, T>*& propMap) {
		if (!propMap)
			propMap = new std::unordered_map<attnumber, T>();

		(*propMap)[propNumber] = propValue;
		return qtrue;
	}

	// Generic getter method to handle the case where the property map for this type has not yet been initialised:
	template <typename T>
	T* getPropertyPtr(attnumber propNumber, std::unordered_map<attnumber, T>*& propMap) {
		if (!propMap)
			return NULL;

		return &(*propMap)[propNumber];
	}

	template <typename T>
	T getProperty(attnumber propNumber, std::unordered_map<attnumber, T>*& propMap, T defaultValue) {
		if (propMap && propMap->count(propNumber))
			return (*propMap)[propNumber];

		return defaultValue;
	}
	
	// Use the property's mEnumStart & mEnumEnd members to specify min and max values
	static inline void limitLongRange(qlong& longValue, ECOproperty* propDef) {
		if (longValue < propDef->mEnumStart) longValue = propDef->mEnumStart;
		else if (longValue > propDef->mEnumEnd) longValue = propDef->mEnumEnd;
	}
	// Use the property's mEnumStart & mEnumEnd members to specify min and max values
	static inline void limitRealRange(qreal& realValue, ECOproperty* propDef) {
		if (realValue < propDef->mEnumStart) realValue = propDef->mEnumStart;
		else if (realValue > propDef->mEnumEnd) realValue = propDef->mEnumEnd;
	}


	qbool setLongProperty(ECOproperty* propDef, qlong newValue);
	qbool setLong64Property(ECOproperty* propDef, qlong64 newValue); // bjw0431
	qbool setRealProperty(ECOproperty* propDef, qreal newValue);
	qbool setStringProperty(ECOproperty* propDef, std::string newValue);


public:
	AutoPropertyValues(std::unordered_map<attnumber, ECOproperty*>* propDefs);
	~AutoPropertyValues();

	// Generic Getter & Setter, using EXTfldval:
	qbool setProperty(ECOproperty* propDef, EXTfldval* newValue);
	qbool getProperty(ECOproperty* propDef, EXTfldval* returnValue);

	// Public Getters & Setters for the supported types
	qbool setLongProperty(attnumber propNumber, qlong newValue) {
		return setLongProperty((*mPropDefs)[propNumber], newValue);
	}
	qlong getLongProperty(attnumber propNumber, qlong defaultValue = 0) {
		return getProperty(propNumber, mLongProps, defaultValue);
	}

	// Start bjw0431a
	qbool setLong64Property(attnumber propNumber, qlong64 newValue) {
		return setLong64Property((*mPropDefs)[propNumber], newValue);
	}
	qlong64 getLong64Property(attnumber propNumber, qlong64 defaultValue = 0) {
		return getProperty(propNumber, mLong64Props, defaultValue);
	}
	// End bjw0431a

	qbool setBoolProperty(attnumber propNumber, qbool newValue) {
		return setProperty(propNumber, newValue, mBoolProps);
	}
	qbool getBoolProperty(attnumber propNumber, qbool defaultValue = qfalse) {
		return getProperty(propNumber, mBoolProps, defaultValue);
	}

	qbool setRealProperty(attnumber propNumber, qreal newValue) {
		return setRealProperty((*mPropDefs)[propNumber], newValue);
	}
	qreal getRealProperty(attnumber propNumber, qreal defaultValue = 0) {
		return getProperty(propNumber, mRealProps, defaultValue);
	}

	qbool setStringProperty(attnumber propNumber, std::string newValue) {
		return setStringProperty((*mPropDefs)[propNumber], newValue);
	}
	std::string getStringProperty(attnumber propNumber, std::string defaultValue = std::string()) {
		return getProperty(propNumber, mStringProps, defaultValue);
	}
};
