///////////////////////////////////////////////////////////////////////////////
///  @file singleton.h
///  Implementation of the singleton design pattern.
///  There are currently two types of singletons, one with the app cleans up
///  on exit and one the user cleans up.
///
///  @remarks To create a singleton inherit from public 
///  Singleton<class_name,Singleton_scope>, and
///  make "class Singleton<class_name,Singleton_scope>" a friend of the class.\n
///  The reason for this is that the constructor for the class which is 
///  inherting from the singleton should be hidden away from the public
///  interface and therefore not allow a user to create another 
///  instance of this type). Access the class via class_name::ref() or
///  class_name::ptr() function depending upon requirements.
///
///  @License
///  This work is licenced under a Creative Commons Licence.
///  see:
///  http://creativecommons.org/licenses/by-nc-sa/3.0/
///  and:
///  http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode
///  For more details.
///  
///  @author Liam Devine
///  @email: see www.liamdevine.co.uk for contact details.
///////////////////////////////////////////////////////////////////////////////


#ifndef SINGLETON_H_
#	define SINGLETON_H_

#	include <cstdlib>//atexit

namespace LVD
{
	///  enum Singleton_scope
	///  Used to determine the scope of a singleton
	enum Singleton_scope
	{
		///  Singleton_scope APP_EXIT
		///  When the application closes it will clean up the singleton pointer
		///  and therefore call the destructor of the inherited class.
		APP_EXIT,
		///  Singleton_scope USER_DELETES
		///  The user is responsible for cleaning up the pointer to the class
		///  via a call like so:
		///   delete class_name::ptr()
		USER_DELETES
	};
	///  default generate compiler error
	template<typename T,Singleton_scope T1>class Singleton;


	///  Singleton
	///  Singleton that the app cleans up.
	template<typename T>
	class  Singleton<T,APP_EXIT>
	{
	public:
		///  inline public static  ref
		///  getter for singleton class
		///  @return T & reference to the inherited class
		inline static T& ref()
		{
			if( ! m_instance )//check
			{	//create the instance of the derived class
				m_instance = new T;
				//register the static function to be called at exit
				atexit( &Singleton::destroy );	
			}
			return (*m_instance);
		}
		///  inline public static  ptr
		///  getter for singleton class
		///  @return T * Pointer to the inherited class
		inline static T* ptr()
		{
			if( ! m_instance )//check
			{	//create the instance of the derived class
				m_instance = new T;
				//register the static function to be called at exit
				atexit( &Singleton::destroy );	
			}
			return (m_instance);
		}

	protected:
		Singleton(){ }
		virtual ~Singleton(){ }
		///inline protected static destroy
		///called when the app exits
		static void destroy()
		{ 
			if(m_instance){ delete m_instance; m_instance = 0; } 
		}
	private:
		static T* volatile m_instance;
		///declare two other functions so the compiler doesn't auto create
		///them, these are in private so that there is no way of calling them
		Singleton(Singleton const &){}
		Singleton& operator=(Singleton const &){return *this;}//ADDED: to cocinde with Memory_heap
	};




	///  Singleton
	///  Singleton that the user clean up.
	template<typename T>
	class  Singleton<T,USER_DELETES>
	{
	public:
		///  inline public static  ref
		///  getter for singleton class
		///  @return T & reference to the inherited class
		inline static T& ref()
		{
			if( ! m_instance )//check
			{	//create the instance of the derived class
				m_instance = new T;
			}
			return (*m_instance);
		}

		///  inline public static  ptr
		///  getter for singleton class
		///  @return T * Pointer to the inherited class
		inline static T* ptr()
		{
			if( ! m_instance )//check
			{	//create the instance of the derived class
				m_instance = new T;
			}
			return (m_instance);
		}
		static void destroy()
		{ 
			if(m_instance){ delete m_instance; m_instance = 0; } 
		}
	protected:
		Singleton(){ }
		virtual ~Singleton(){ }
	private:
		static T* volatile m_instance;
		///declare two other functions so the compiler doesn't auto create
		///them, these are in private so that there is no way of calling them
		Singleton(Singleton const &){}
		Singleton& operator=(Singleton const &){return *this;}//ADDED:
	};

	template<typename T>T* volatile Singleton<T,APP_EXIT>::m_instance = 0;
	template<typename T>T* volatile Singleton<T,USER_DELETES>::m_instance = 0;


}


#endif //SINGLETON_H_

