// DWBS ------------------------------------------------------------------ DWBS
//
// PLATFORM		: ALL
// PRODUCT		: BIT_DEMON
// VISIBILITY	: PUBLIC
//
// DWBS ------------------------------------------------------------------ DWBS

// PURPOSE: A singleton that tracks the bandwidth utilization of a network adapter.

#ifndef BD_BANDWIDTH_MONITOR_H
#define BD_BANDWIDTH_MONITOR_H

#include <bdCore/bdCore.h>
#include <bdNet/bdBandwidthMonitor/bdBandwidthListener.h>
#include <bdNet/bdDispatch/bdDispatchInterceptor.h>
#include <bdConnection/bdConnectionListener.h>

/// The default upstream bandwidth in bytes per second. (64kbps)
#define BD_DEFAULT_UPSTREAM_BW_BPS	(8192u)
/// The default downstream bandwidth in bytes per second. (64kbps)
#define BD_DEFAULT_DOWNSTREAM_BW_BPS	(8192u)

/// A singleton that tracks the bandwidth utilization of a network adapter.
/// See tutorial "Bandwidth Monitoring and Bandwidth Arbitration Tutorial" for usage.
class bdBandwidthMonitorImpl : public bdDispatchInterceptor, public bdConnectionListener
{
	public:
		
		BD_DECLARE_NEW_AND_DELETE_OPERATORS

		void setAvailableUpstreamBandwidth(const bdUInt bytesPerSecond);

		void setAvailableDownstreamBandwidth(const bdUInt bytesPerSecond);

		/// Recalculates the current bandwidth usage statistics
		void update();

		/// Gets the number of bytes sent per second
		/// \return The number of bytes sent during the last second.
		bdUInt32 getBytesPerSecondSent() const;

		/// Gets the number of bytes received per second
		/// \return The number of bytes received during the last second.
		bdUInt32 getBytesPerSecondReceived() const;

		/// Specifies the upper outgoing bandwidth limit. If the sending rate exceeds
		/// this limit, the onSendHighWaterMark() callback of the registered
		/// bandwith listener will be called in order to perform counter measures.
		/// \param bytesPerSecond [in] : The maximum number of bytes we are allowed 
		/// to send per second
		void setSendHighWaterMark(bdUInt32 bytesPerSecond);

		/// Specifies the lower outgoing bandwidth limit. If the sending rate has previously exceeded
		/// the upper limit, and has fallen again below this lower level, the 
		/// onSendLowWaterMark() callback of the registered
		/// bandwith listener will be called.
		/// \param bytesPerSecond [in] : The number of bytes we are allowed 
		/// to send per second
		void setSendLowWaterMark(bdUInt32 bytesPerSecond);

		/// Retrieves the upper outgoing bandwidth limit.
		/// \return The high water mark for the monitored bandwidth usage.
		bdUInt32 getSendHighWaterMark() const;

		/// Retrieves the lower outgoing bandwidth limit.
		/// \return The low water mark for the monitored bandwidth usage.
		bdUInt32 getSendLowWaterMark() const;

		/// Register a bandwidth listener with the monitor.
		/// \param listener[in]	A pointer to the listener that is to be
		///  registered.
		void registerListener(bdBandwidthListener *const listener);

		/// Unregisters a previously registered listener.
		/// \param listener[in]	A pointer to the listener to be unregistered.
		void unregisterListener(bdBandwidthListener *const listener);

		// see base class description.
		virtual bdBool accept(const bdReceivedMessage& receivedMsg);

		// see base class description.
		virtual void onConnect(bdConnectionRef connection);

		// see base class description.
		virtual void onDisconnect(bdConnectionRef connection);

	protected:

		/// The singleton access point is a friend so that this class can 
		/// be automatically instantiated.
		friend class bdSingleton<bdBandwidthMonitorImpl>;

		/// Constructor.
		bdBandwidthMonitorImpl();

		bdUInt m_upstreamBwInBytesPerSecond;

		bdUInt m_downstreamBwInBytesPerSecond;

		bdLinkedList<bdConnectionRef> m_connections;

		bdUInt64 m_prevBytesSent;
		bdUInt32 m_avgBytesSent;
		bdUInt32 m_bytesSentLastSecond;

		bdUInt64 m_prevBytesReceived;
		bdUInt32 m_avgBytesReceived;
		bdUInt32 m_bytesReceivedLastSecond;
		
		bdUInt32 m_sendHWMark;
		bdUInt32 m_sendLWMark;
		
		bdBool   m_toggleSendWM;

		bdFastArray<bdBandwidthListener *> m_listeners;

		/// This is used to time the period between calls to update().
		bdStopwatch m_timer;

};

/// This class provides a point of access to the singleton instance.
/// Implementation details can be found in bdBandwidthMonitorImpl.
class bdBandwidthMonitor : public bdSingleton<bdBandwidthMonitorImpl>
{
	BD_DECLARE_NEW_AND_DELETE_OPERATORS

	protected:

		bdBandwidthMonitor();
};


#endif //BD_BANDWIDTH_MONITOR_H
