//-----------------------------------------------------------------------------
//
//	Node.h
//
//	A node in the Z-Wave network
//
//	Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
//
//	SOFTWARE NOTICE AND LICENSE
//
//	This file is part of OpenZWave.
//
//	OpenZWave is free software: you can redistribute it and/or modify
//	it under the terms of the GNU Lesser General Public License as published
//	by the Free Software Foundation, either version 3 of the License,
//	or (at your option) any later version.
//
//	OpenZWave is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU Lesser General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public License
//	along with OpenZWave.  If not, see <http://www.gnu.org/licenses/>.
//
//-----------------------------------------------------------------------------

#ifndef _Node_H
#define _Node_H

#include <string>
#include <vector>
#include <list>
#include <map>
#include "Defs.h"
#include "value_classes/ValueID.h"
#include "value_classes/ValueList.h"
#include "Msg.h"
#include "platform/TimeStamp.h"
#include "Group.h"

class TiXmlElement;

namespace OpenZWave
{
	class CommandClass;
	class Driver;
	class Group;
	class ValueStore;
	class Value;
	class ValueBool;
	class ValueButton;
	class ValueByte;
	class ValueDecimal;
	class ValueInt;
	class ValueSchedule;
	class ValueShort;
	class ValueString;
	class Mutex;
	class ProductDescriptor;

	/** \brief The Node class describes a Z-Wave node object...typically a device on the
	 *  Z-Wave network.
	 */
	class Node
	{
			friend class Manager;
			friend class Driver;
			friend class Group;
			friend class Value;
			friend class ValueButton;
			friend class Alarm;
			friend class Association;
			friend class AssociationCommandConfiguration;
			friend class Basic;
			friend class Battery;
			friend class ClimateControlSchedule;
			friend class Clock;
			friend class CommandClass;
			friend class ControllerReplication;
			friend class EnergyProduction;
			friend class Hail;
			friend class Indicator;
			friend class Language;
			friend class Lock;
			friend class ManufacturerSpecific;
			friend class ManufacturerSpecificDB;
			friend class Meter;
			friend class MeterPulse;
			friend class MultiInstance;
			friend class MultiChannelAssociation;
			friend class NodeNaming;
			friend class Protection;
			friend class Security;
			friend class SensorAlarm;
			friend class SensorBinary;
			friend class SensorMultilevel;
			friend class SwitchAll;
			friend class SwitchBinary;
			friend class SwitchMultilevel;
			friend class SwitchToggleBinary;
			friend class SwitchToggleMultilevel;
			friend class ThermostatFanMode;
			friend class ThermostatFanState;
			friend class ThermostatMode;
			friend class ThermostatOperatingState;
			friend class ThermostatSetpoint;
			friend class Version;
			friend class WakeUp;
			friend class ZWavePlusInfo;

			//-----------------------------------------------------------------------------
			// Construction
			//-----------------------------------------------------------------------------
		public:
			/** Constructor initializes the node object, associating it with a specific
			 *  network (_homeId) and network node (_nodeId).
			 *  \param _homeId The homeId of the network to which this node is connected.
			 *  \param _nodeId The nodeId of this node.
			 */
			Node( uint32 const _homeId, uint8 const _nodeId );
			/** Destructor cleans up memory allocated to node and its child objects.
			 */
			virtual ~Node();

		private:
			/** Returns a pointer to the driver (interface with a Z-Wave controller)
			 *  associated with this node.
			 */
			Driver* GetDriver()const;

			//-----------------------------------------------------------------------------
			// Initialization
			//-----------------------------------------------------------------------------
		public:
			enum QueryStage
			{
				QueryStage_None,							/**< Query process hasn't started for this node */
				QueryStage_ProtocolInfo,					/**< Retrieve protocol information */
				QueryStage_Probe,							/**< Ping device to see if alive */
				QueryStage_WakeUp,							/**< Start wake up process if a sleeping node */
				QueryStage_ManufacturerSpecific1,			/**< Retrieve manufacturer name and product ids if ProtocolInfo lets us */
				QueryStage_NodeInfo,						/**< Retrieve info about supported, controlled command classes */
				QueryStage_NodePlusInfo,					/**< Retrieve ZWave+ info and update device classes */
				QueryStage_SecurityReport,					/**< Retrieve a list of Command Classes that require Security */
				QueryStage_ManufacturerSpecific2,			/**< Retrieve manufacturer name and product ids */
				QueryStage_Versions,						/**< Retrieve version information */
				QueryStage_Instances,						/**< Retrieve information about multiple command class instances */
				QueryStage_Static,							/**< Retrieve static information (doesn't change) */
				QueryStage_CacheLoad,						/**< Ping a device upon restarting with cached config for the device */
				QueryStage_Probe1 = QueryStage_CacheLoad,	/** < Depreciated name. /todo Remove in 2.0 timeframe */
				QueryStage_Associations,					/**< Retrieve information about associations */
				QueryStage_Neighbors,						/**< Retrieve node neighbor list */
				QueryStage_Session,							/**< Retrieve session information (changes infrequently) */
				QueryStage_Dynamic,							/**< Retrieve dynamic information (changes frequently) */
				QueryStage_Configuration,					/**< Retrieve configurable parameter information (only done on request) */
				QueryStage_Complete							/**< Query process is completed for this node */
			};


			/**
			 * This function advances the query process (see Remarks below for more detail on the
			 * process).  It iterates through the various query stages enumerated in Node::QueryStage.
			 *
			 * \remark
			 * For OpenZWave to discover everything about a node, we have to follow a certain
			 * order of queries, because the results of one stage may affect what is requested
			 * in the next stage.  The stage is saved with the node data, so that any incomplete
			 * queries can be restarted the next time the application runs.
			 * <p>
			 * The individual command classes also store some state information as to whether
			 * they have had a response to certain queries.  This state information is
			 * initialized by the SetStaticRequests call in QueryStage_None.  It is also saved,
			 * so we do not need to request state  from every command class if some have previously
			 * responded.
			 */
			void AdvanceQueries();

			/**
			 *  Signal that a specific query stage has been completed for this node.  This will
			 *  only work if the query process for this node is indeed at the specified stage.
			 *  Otherwise, the function returns with no action.
			 *  \param _stage The current stage of the query process.
			 */
			void QueryStageComplete( QueryStage const _stage );

			/**
			 *  Retry the specified query stage (up to _maxAttempts retries).  This will
			 *  only work if the query process for this node is indeed at the specified stage.
			 *  Otherwise, the function returns with no action.
			 *  \param _stage The query stage to retry.
			 *  \param _maxAttempts
			 */
			void QueryStageRetry( QueryStage const _stage, uint8 const _maxAttempts = 0 );	    // maxAttempts of zero means no limit

			/**
			 * This function sets the query stage for the node (but only to an earlier stage).
			 * If a later stage is specified than the current one, it is ignored.
			 * \param _stage The desired query stage.
			 * \see m_queryStage, m_queryPending
			 */
			void SetQueryStage( QueryStage const _stage, bool const _advance = true );

			/**
			 * Returns the current query stage enum.
			 * \return Enum value with the current query stage.
			 * \see m_queryStage
			 */
			Node::QueryStage GetCurrentQueryStage() { return m_queryStage; }

			/**
			 * Returns the specified query stage string.
			 * \param _stage The query stage.
			 * \return Specified query stage string.
			 * \see m_queryStage, m_queryPending
			 */
			string GetQueryStageName( QueryStage const _stage );

			/**
			 * Returns whether the library thinks a node is functioning properly
			 * \return boolean status of node.
			 */
			bool IsNodeAlive()const{ return m_nodeAlive; }

			/**
			 *  This function handles a response to the FUNC_ID_ZW_GET_NODE_PROTOCOL_INFO
			 *  command for this node.  If protocol information has already been retrieved
			 *  for the node, the function simply returns.  Otherwise, it populates several
			 *  member variables about the device at this node:
			 *  - m_routing (whether it is a routing node (capable of passing commands along to other nodes in the network) or not
			 *  - m_maxBaudRate (the maximum baud rate at which this device can communicate)
			 *  - m_version (TODO)
			 *  - m_security (whether device supports security features)
			 *  - m_listening (device is powered and listening constantly)
			 *  - m_frequentListening (device can be woken up with a beam)
			 *  - m_beaming (device is beam capable)
			 */
			void UpdateProtocolInfo( uint8 const* _data );
			/**
			 * this function is called when the Node is added via a AddNode request. the ProtocolInfo field contains the
			 * devices classes and the CommandClasses that the node supports, so we can build a pretty good Node out of that
			 * info.
			 * @param _protocolInfo Byte 0 - Basic Device Class Byte 1 - Generic Device Class, Byte 2 - Specific Device Classes Remaining Bytes - Supported Command Classes
			 * @param _length length of the _protocolInfo field.
			 */
			void SetProtocolInfo(uint8 const* _protocolInfo, uint8 const _length);
			void UpdateNodeInfo( uint8 const* _data, uint8 const _length );

			bool ProtocolInfoReceived()const{ return m_protocolInfoReceived; }
			bool NodeInfoReceived()const{ return m_nodeInfoReceived; }
			bool IsNodeZWavePlus()const{ return m_nodePlusInfoReceived; }

			bool AllQueriesCompleted()const{ return( QueryStage_Complete == m_queryStage ); }

			void SetNodePlusInfoReceived(const bool _received){ m_nodePlusInfoReceived = _received; }

			/**
			 * Handle dead node detection tracking.
			 * Use this routine to set state of nodes.
			 * Tracks state as well as send notifications.
			 */
			void SetNodeAlive( bool const _isAlive );

		private:
			void SetStaticRequests();

			QueryStage	m_queryStage;
			bool		m_queryPending;
			bool		m_queryConfiguration;
			uint8		m_queryRetries;
			bool		m_protocolInfoReceived;
			bool		m_basicprotocolInfoReceived;
			bool		m_nodeInfoReceived;
			bool		m_nodePlusInfoReceived;
			bool		m_manufacturerSpecificClassReceived;
			bool		m_nodeInfoSupported;
			bool		m_refreshonNodeInfoFrame;
			bool		m_nodeAlive;

			//-----------------------------------------------------------------------------
			// Capabilities
			//-----------------------------------------------------------------------------
		public:
			// Security flags
			enum
			{
				SecurityFlag_Security				= 0x01,
				SecurityFlag_Controller				= 0x02,
				SecurityFlag_SpecificDevice			= 0x04,
				SecurityFlag_RoutingSlave			= 0x08,
				SecurityFlag_BeamCapability			= 0x10,
				SecurityFlag_Sensor250ms			= 0x20,
				SecurityFlag_Sensor1000ms			= 0x40,
				SecurityFlag_OptionalFunctionality	= 0x80
			};

			// Node Ids
			enum
			{
				NodeBroadcast = 0xff
			};

			bool IsListeningDevice()const{ return m_listening; }
			bool IsFrequentListeningDevice()const{ return m_frequentListening; }
			bool IsBeamingDevice()const{ return m_beaming; }
			bool IsRoutingDevice()const{ return m_routing; }
			bool IsSecurityDevice()const{ return m_security; }
			uint32 GetMaxBaudRate()const{ return m_maxBaudRate; }
			uint8 GetVersion()const{ return m_version; }
			uint8 GetSecurity()const{ return m_security; }

			uint8 GetNodeId()const{ return m_nodeId; }

			uint8 GetBasic()const{ return m_basic; }
			uint8 GetGeneric()const{ return m_generic; }
			uint8 GetSpecific()const{ return m_specific; }
			string const& GetType()const{ return m_type; }
			uint32 GetNeighbors( uint8** o_associations );
			bool IsController()const{ return ( m_basic == 0x01 || m_basic == 0x02 ) && ( m_generic == 0x01 || m_generic == 0x02 ); }
			bool IsAddingNode() const { return m_addingNode; }	/* These three *AddingNode functions are used to tell if we this node is just being discovered. Currently used by the Security CC to initiate the Network Key Exchange */
			void SetAddingNode() { m_addingNode = true; }
			void ClearAddingNode() { m_addingNode = false; }
			bool IsNodeReset();
		private:
			bool		m_listening;
			bool		m_frequentListening;
			bool		m_beaming;
			bool		m_routing;
			uint32		m_maxBaudRate;
			uint8		m_version;
			bool		m_security;
			uint32		m_homeId;
			uint8		m_nodeId;
			uint8		m_basic;				//*< Basic device class (0x01-Controller, 0x02-Static Controller, 0x03-Slave, 0x04-Routing Slave
			uint8		m_generic;
			uint8		m_specific;
			string		m_type;					// Label representing the specific/generic/basic value
			uint8		m_neighbors[29];		// Bitmask containing the neighboring nodes
			uint8		m_numRouteNodes;		// number of node routes
			uint8		m_routeNodes[5];		// nodes to route to
			map<uint8,uint8>	m_buttonMap;	// Map button IDs into virtual node numbers
			bool		m_addingNode;

			//-----------------------------------------------------------------------------
			// Device Naming
			//-----------------------------------------------------------------------------
		private:
			// Manufacturer, Product and Name are stored here so they can be set by the
			// user even if the device does not support the relevant command classes.
			string GetManufacturerName()const{ return m_manufacturerName; }
			string GetProductName()const{ return m_productName; }
			string GetNodeName()const{ return m_nodeName; }
			string GetLocation()const{ return m_location; }

//			string GetManufacturerId()const{ return std::to_string(m_manufacturerId); }
			uint16 GetManufacturerId()const{ return m_manufacturerId; }
//			string GetProductType()const{ return string(m_productType); }
			uint16 GetProductType()const{ return m_productType; }
//			string GetProductId()const{ return string(m_productId); }
			uint16 GetProductId()const{ return m_productId; }

			void SetManufacturerName( string const& _manufacturerName ){ m_manufacturerName = _manufacturerName; }
			void SetProductName( string const& _productName ){ m_productName = _productName; }
			void SetNodeName( string const& _nodeName );
			void SetLocation( string const& _location );

			void SetManufacturerId( uint16 const& _manufacturerId ){ m_manufacturerId = _manufacturerId; }
			void SetProductType( uint16 const& _productType ){ m_productType = _productType; }
			void SetProductId( uint16 const& _productId ){ m_productId = _productId; }

			string		m_manufacturerName;
			string		m_productName;
			string		m_nodeName;
			string		m_location;

			uint16		m_manufacturerId;
			uint16		m_productType;
			uint16		m_productId;

			// zwave+ info
			uint16 GetDeviceType() const { return m_deviceType; }
			string GetDeviceTypeString();
			uint8 GetRoleType() const { return m_role; }
			string GetRoleTypeString();
			uint8 GetNodeType() const { return m_nodeType; }
			string GetNodeTypeString();

			uint16 m_deviceType;
			uint8 m_role;
			uint8 m_nodeType;

			//-----------------------------------------------------------------------------
			// Command Classes
			//-----------------------------------------------------------------------------
		public:
			/**
			 * This function retrieves a pointer to the requested command class object (if supported by this node).
			 * \param _commandClassId Class ID (a single byte value) identifying the command class requested.
			 * \return Pointer to the requested CommandClass object if supported, otherwise NULL.
			 * \see CommandClass, m_commandClassMap
			 */
			CommandClass* GetCommandClass( uint8 const _commandClassId, bool advertised = false )const;
			void ApplicationCommandHandler( uint8 const* _data, bool encrypted );

			/**
			 * This function sets up Secured Command Classes. It iterates over the existing command classes marking them
			 * as Secured if they exist, and if they don't, it creates new Command Classes and sets them up as Secured
			 * @param _data a list of Command Classes that are Secured by the Device
			 * @param _length the length of the _data string
			 * @param _instance the instance of the Class thats Secured.
			 */
			void SetSecuredClasses( uint8 const* _data, uint8 const _length, uint32 const _instance = 1);
			void SetSecured(bool secure);
			bool IsSecured();
			/**
			 * This function sets a Global Instance Label for all CommandClasses that don't define their
			 * own labels
			 */
			void SetInstanceLabel(uint8 const _instance, char *label);
			/** This function gets a Instance Label for a ValueID. It either users the Global Instance Label
			 * above, or a Label for a Specific CC
			 */
			string GetInstanceLabel(uint8 const _ccid, uint8 const _instance);

			/** Get The Number of Instances on this node
			 *
			 */
			uint8 GetNumInstances(uint8 const _ccid);
		private:
			/**
			 * Creates the specified command class object and adds it to the node (via the
			 * m_commandClassMap) if it doesn't exist.
			 * No new object is created if it already exists for this node.
			 * \param _commandClassId Class ID (a single byte value) identifying the command class requested.
			 * \param advertised if the CommandClass is Advertised by this node
			 * \return Pointer to the CommandClass object just added to the map (NULL if the object
			 * was already there or if the CommandClass object creation failed).
			 * \see CommandClass, CommandClasses::CreateCommandClass, m_commandClassMap
			 */
			CommandClass* AddCommandClass( uint8 const _commandClassId, bool advertised = false);
			/**
			 * Removes a command class object from the node (via the m_commandClassMap).  Before removing the
			 * object, this function also removes any values stored in the object's ValueStore.
			 * \param _commandClassId Class ID (a single byte value) identifying the command class to be removed.
			 * \see m_commandClassMap, ValueStore, GetValueStore, ValueStore::RemoveCommandClassValues
			 */
			void RemoveCommandClass( uint8 const _commandClassId );
			void ReadXML( TiXmlElement const* _nodeElement );
			void ReadDeviceProtocolXML( TiXmlElement const* _ccsElement );
			void ReadCommandClassesXML( TiXmlElement const* _ccsElement );
			void WriteXML( TiXmlElement* _nodeElement );

			map<uint8,CommandClass*>		m_commandClassMap;	/**< Map of command class ids and pointers to associated command class objects */
			map<uint8,CommandClass*>		m_advertisedCommandClassMap; /**< Map of Command Class Id's and Pointers to the Class for Advertised CommandClasses */
			bool							m_secured; /**< Is this Node added Securely */
			map<uint8, string>				m_globalInstanceLabel; /** < The Global Labels for Instances for CC that dont define their own labels */
			//-----------------------------------------------------------------------------
			// Configuration Revision Related Classes
			//-----------------------------------------------------------------------------
		public:
			void SetProductDetails(ProductDescriptor *product);
			/** Get a path to the config file for this device
			 *
			 * @return a path relative to the config directory for the config file. returns a empty string if a config file is not present.
			 */
			string getConfigPath();
			/** Get the latest local revision of the config file for this node
			 *
			 * @return a revision number
			 */
			uint32 getFileConfigRevision() { return m_fileConfigRevision; };
			/** Get the Revision number of the config that is laoded for this Node
			 *
			 * @return the revision number currently loaded.
			 */
			uint32 getLoadedConfigRevision() { return m_loadedConfigRevision; };
			/** Get the Latest Config File revision available at openzwave.com
			 *
			 * @return The latest revision number available
			 */
			uint32 getLatestConfigRevision() { return m_latestConfigRevision; };
			/** Set the revision number of the Config File for this device
			 *
			 * @param rev the revision number
			 */
			void setFileConfigRevision(uint32 rev);
			/** Set the revision number of the config that is loaded for this device
			 *
			 * @param rev the revision number
			 */
			void setLoadedConfigRevision(uint32 rev);
			/** Set the revision number of the latest available config file for this device
			 *
			 * @param rev the revision number
			 */
			void setLatestConfigRevision(uint32 rev);
			/** Check the latest available revision number for this device.
			 *
			 */
			void checkLatestConfigRevision( );

		private:


			ProductDescriptor *m_Product;


			uint32 m_fileConfigRevision;
			uint32 m_loadedConfigRevision;
			uint32 m_latestConfigRevision;
			//-----------------------------------------------------------------------------
			// Basic commands (helpers that go through the basic command class)
			//-----------------------------------------------------------------------------
		public:
			void SetLevel( uint8 const _level );

			//-----------------------------------------------------------------------------
			// On/Off commands (helpers that go through the basic or switchall command class)
			//-----------------------------------------------------------------------------
		public:
			void SetNodeOn();
			void SetNodeOff();

			//-----------------------------------------------------------------------------
			// Values (handled by the command classes)
			//-----------------------------------------------------------------------------
		public:
			ValueID CreateValueID( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, ValueID::ValueType const _type );

			Value* GetValue( ValueID const& _id );
			Value* GetValue( uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex );
			bool RemoveValue( uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex );

			// Helpers for creating values
			bool CreateValueBitSet( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int32 const _default, uint8 const _pollIntensity );
			bool CreateValueBool( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, bool const _default, uint8 const _pollIntensity );
			bool CreateValueButton( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, uint8 const _pollIntensity );
			bool CreateValueByte( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _default, uint8 const _pollIntensity );
			bool CreateValueDecimal( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, string const& _default, uint8 const _pollIntensity );
			bool CreateValueInt( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int32 const _default, uint8 const _pollIntensity );
			bool CreateValueList( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _size, vector<ValueList::Item> const& _items, int32 const _default, uint8 const _pollIntensity );
			bool CreateValueRaw( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const* _default, uint8 const _length, uint8 const _pollIntensity );
			bool CreateValueSchedule( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, uint8 const _pollIntensity );
			bool CreateValueShort( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, int16 const _default, uint8 const _pollIntensity );
			bool CreateValueString( ValueID::ValueGenre const _genre, uint8 const _commandClassId, uint8 const _instance, uint16 const _valueIndex, string const& _label, string const& _units, bool const _readOnly, bool const _writeOnly, string const& _default, uint8 const _pollIntensity );

			// helpers for removing values
			void RemoveValueList( ValueList* _value );

			void ReadValueFromXML( uint8 const _commandClassId, TiXmlElement const* _valueElement );
			bool CreateValueFromXML( uint8 const _commandClassId, TiXmlElement const* _valueElement );

		private:
			ValueStore* GetValueStore()const{ return m_values; }

			ValueStore*	m_values;			// Values reported via command classes

			//-----------------------------------------------------------------------------
			// Configuration Parameters (handled by the Configuration command class)
			//-----------------------------------------------------------------------------
		private:
			bool SetConfigParam( uint8 const _param, int32 _value, uint8 const _size );
			void RequestConfigParam( uint8 const _param );
			bool RequestAllConfigParams( uint32 const _requestFlags );

			//-----------------------------------------------------------------------------
			// Dynamic Values (used by query and other command classes for updating)
			//-----------------------------------------------------------------------------
		private:
			bool RequestDynamicValues();
		public:
			//-----------------------------------------------------------------------------
			// Refresh Dynamic Values from CommandClasses on Wakeup
			//-----------------------------------------------------------------------------
			void RefreshValuesOnWakeup();
			//-----------------------------------------------------------------------------
			// Groups
			//-----------------------------------------------------------------------------
		private:
			// The public interface is provided via the wrappers in the Manager class
			uint8 GetNumGroups();
			uint32 GetAssociations( uint8 const _groupIdx, uint8** o_associations );
			uint32 GetAssociations( uint8 const _groupIdx, InstanceAssociation** o_associations );
			uint8 GetMaxAssociations( uint8 const _groupIdx );
			bool IsMultiInstance( uint8 const _groupIdx );
			string GetGroupLabel( uint8 const _groupIdx );
			void AddAssociation( uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _instance = 0x00 );
			void RemoveAssociation( uint8 const _groupIdx, uint8 const _targetNodeId, uint8 const _instance = 0x00 );
			void AutoAssociate();

			// The following methods are not exposed
			Group* GetGroup( uint8 const _groupIdx );							// Get a pointer to a Group object.  This must only be called while holding the node Lock.
			void AddGroup( Group* _group );										// The groups are fixed properties of a device, so there is no need for a matching RemoveGroup.
			void WriteGroups( TiXmlElement* _associationsElement );				// Write the group data out to XNL

			map<uint8,Group*> m_groups;											// Maps group indices to Group objects.

			//-----------------------------------------------------------------------------
			// Device Classes (static data read from the device_classes.xml file)
			//-----------------------------------------------------------------------------
		private:
			// Container for device class info
			class DeviceClass
			{
				public:
				DeviceClass( TiXmlElement const* _el );
				~DeviceClass(){ delete [] m_mandatoryCommandClasses; }

				uint8 const*	GetMandatoryCommandClasses(){ return m_mandatoryCommandClasses; }
				uint8			GetBasicMapping(){ return m_basicMapping; }
				string const&	GetLabel(){ return m_label; }

				private:
				uint8*			m_mandatoryCommandClasses;						// Zero terminated array of mandatory command classes for this device type.
				uint8			m_basicMapping;									// Command class that COMMAND_CLASS_BASIC maps on to, or zero if there is no mapping.
				string			m_label;										// Descriptive label for the device.
			};

			// Container for generic device class info
			class GenericDeviceClass : public DeviceClass
			{
				public:
					GenericDeviceClass( TiXmlElement const* _el );
					~GenericDeviceClass();

					DeviceClass* GetSpecificDeviceClass( uint8 const& _specific );

				private:
					map<uint8,DeviceClass*>	m_specificDeviceClasses;
			};


			bool SetDeviceClasses( uint8 const _basic, uint8 const _generic, uint8 const _specific );	// Set the device class data for the node
			bool SetPlusDeviceClasses( uint8 const _role, uint8 const _nodeType, uint16 const _deviceType );	// Set the device class data for the node based on the Zwave+ info report
			bool AddMandatoryCommandClasses( uint8 const* _commandClasses );							// Add mandatory command classes as specified in the device_classes.xml to the node.
			void ReadDeviceClasses();																	// Read the static device class data from the device_classes.xml file
			string GetEndPointDeviceClassLabel( uint8 const _generic, uint8 const _specific );

			static bool								s_deviceClassesLoaded;		// True if the xml file has already been loaded
			static map<uint8,string>				s_basicDeviceClasses;		// Map of basic device classes.
			static map<uint8,GenericDeviceClass*>	s_genericDeviceClasses;		// Map of generic device classes.
			static map<uint8,DeviceClass*> 			s_roleDeviceClasses;		// Map of Zwave+ role device classes.
			static map<uint16,DeviceClass*> 		s_deviceTypeClasses;		// Map of Zwave+ device type device classes.
			static map<uint8, DeviceClass*>			s_nodeTypes;				// Map of ZWave+ Node Types


			//-----------------------------------------------------------------------------
			//	Statistics
			//-----------------------------------------------------------------------------
			public:
			struct CommandClassData
			{
				uint8 m_commandClassId;
				uint32 m_sentCnt;
				uint32 m_receivedCnt;
			};

			struct NodeData
			{
					uint32 m_sentCnt;
					uint32 m_sentFailed;
					uint32 m_retries;
					uint32 m_receivedCnt;
					uint32 m_receivedDups;
					uint32 m_receivedUnsolicited;
					string m_sentTS;
					string m_receivedTS;
					uint32 m_lastRequestRTT;
					uint32 m_averageRequestRTT;				// ms
					uint32 m_lastResponseRTT;
					uint32 m_averageResponseRTT;
					uint8 m_quality;					// Node quality measure
					uint8 m_lastReceivedMessage[254];
					list<CommandClassData> m_ccData;
					bool m_txStatusReportSupported;
					uint16 m_txTime;
					uint8 m_hops;
					char m_rssi_1[8];
					char m_rssi_2[8];
					char m_rssi_3[8];
					char m_rssi_4[8];
					char m_rssi_5[8];
					uint8 m_ackChannel;
					uint8 m_lastTxChannel;
					TXSTATUS_ROUTING_SCHEME m_routeScheme;
					char m_routeUsed[9];
					TXSTATUS_ROUTE_SPEED m_routeSpeed;
					uint8 m_routeTries;
					uint8 m_lastFailedLinkFrom;
					uint8 m_lastFailedLinkTo;
			};

			private:
			void GetNodeStatistics( NodeData* _data );

			uint32 m_sentCnt;					// Number of messages sent from this node.
			uint32 m_sentFailed;				// Number of sent messages failed
			uint32 m_retries;					// Number of message retries
			uint32 m_receivedCnt;				// Number of messages received from this node.
			uint32 m_receivedDups;				// Number of duplicated messages received;
			uint32 m_receivedUnsolicited;		// Number of messages received unsolicited
			uint32 m_lastRequestRTT;			// Last message request RTT
			uint32 m_lastResponseRTT;			// Last message response RTT
			TimeStamp m_sentTS;					// Last message sent time
			TimeStamp m_receivedTS;				// Last message received time
			uint32 m_averageRequestRTT;			// Average Request round trip time.
			uint32 m_averageResponseRTT;		// Average Response round trip time.
			uint8 m_quality;					// Node quality measure
			uint8 m_lastReceivedMessage[254];	// Place to hold last received message
			uint8 m_errors;
			bool m_txStatusReportSupported;		// if Extended Status Reports are available
			uint16 m_txTime;					// Time Taken to Transmit the last frame
			uint8 m_hops;						// Hops taken in transmitting last frame
			char m_rssi_1[8];					// RSSI Level of last transmission
			char m_rssi_2[8];					// RSSI Level of last transmission
			char m_rssi_3[8];					// RSSI Level of last transmission
			char m_rssi_4[8];					// RSSI Level of last transmission
			char m_rssi_5[8];					// RSSI Level of last transmission
			uint8 m_ackChannel;					// Channel we received the last ACK on
			uint8 m_lastTxChannel;				// Channel we transmitted the last frame on
			TXSTATUS_ROUTING_SCHEME m_routeScheme;				// The Scheme used to route the last frame
			uint8 m_routeUsed[4];				// The Route Taken in the last frame
			TXSTATUS_ROUTE_SPEED m_routeSpeed;					// Baud Rate of the last frame
			uint8 m_routeTries;					// The number of attempts to route the last frame
			uint8 m_lastFailedLinkFrom;			// The last failed link from
			uint8 m_lastFailedLinkTo;			// The last failed link to


			//-----------------------------------------------------------------------------
			//	Encryption Related
			//-----------------------------------------------------------------------------
			public:

			uint8 *GenerateNonceKey();
			uint8 *GetNonceKey(uint32 nonceid);

			private:
			uint8 m_lastnonce;
			uint8 m_nonces[8][8];

			//-----------------------------------------------------------------------------
			//	MetaData Related
			//-----------------------------------------------------------------------------

			public:
			/**
			 * MetaData Fields.
			 * Available Fields that contain metadata about a device.
			 * \see Manager::AddWatcher
			 * \see Manager::BeginControllerCommand
			 */
			enum MetaDataFields
			{
				MetaData_OzwInfoPage_URL,
				MetaData_ZWProductPage_URL,
				MetaData_ProductPic,
				MetaData_Description,
				MetaData_ProductManual_URL,
				MetaData_ProductPage_URL,
				MetaData_InclusionHelp,
				MetaData_ExclusionHelp,
				MetaData_ResetHelp,
				MetaData_WakeupHelp,
				MetaData_ProductSupport_URL,
				MetaData_Frequency,
				MetaData_Name,
				MetaData_Identifier,
				MetaData_Invalid = 255
			};

			struct ChangeLogEntry {
				string author;
				string date;
				int revision;
				string description;
			};
			string const GetMetaData(MetaDataFields);
			MetaDataFields const GetMetaDataId(string);
			string const GetMetaDataString(MetaDataFields);
			ChangeLogEntry const GetChangeLog(uint32_t);


			private:
			void ReadMetaDataFromXML(TiXmlElement const* _valueElement);
			void WriteMetaDataXML(TiXmlElement*);
			map<MetaDataFields, string> m_metadata;
			map<uint32_t, ChangeLogEntry> m_changeLog;
	};


} //namespace OpenZWave

#endif //_Node_H
