#ifndef SINGLETON_H
#define SINGLETON_H

#include <cassert>
using namespace std;

/*!
\brief Simplest singleton.
*/
template<typename T>
class Singleton
{
public:

  static T * ptr;

  Singleton(T* ptr_)
    { ptr=ptr_; }
};


/*!
\brief  Singleton smart pointer.

A singleton is a pointer to a unique (only one) object.

I do not generally use this as C++ provides a low tech solution
 with static variables that is simpler or more primitive.

However this does a little more by supporting reference counting deletion,
 if the client so chooses for array and not array objects.

The class can also be used without memory management. References are still
 counted but they can become zero and still have a valid pointer, because
 it is the clients responsibility.  The following is an example of this 
 technique.

\par Example 
\verbatim
  //Initialize the pointer.
  SingletonPtr< A > init(&app);  // Be aware of app object's lifetime
  // Let init die.

  //... Access the object anywhere in the C++ universe.
  SingletonPtr< A >()-> A's methods/data
\endverbatim
*/
template< class T>
class SingletonPtr
{
  static T*  ptr;
public:
  
  /** Count of the ojbects pointed to by ptr. */
  static int count;

  /** Define how the pointer is deleted. */
  typedef enum memoryRelease { never=0, nonarray, array };

  /** No memory management by default, callers responsibility to manage memory. */
  explicit SingletonPtr(T* app);
  /** Specifies how to delete pointer. */
  explicit SingletonPtr(T* app, SingletonPtr<T>::memoryRelease m);

  /** Create a temporary to access the pointer. */
  SingletonPtr();
  /** Cleanup. */
  ~SingletonPtr();

  /** Access the object. */
  T* operator->();
  /** Access the object. */
  T& operator()();

private:
   static memoryRelease memorystate;
};




// ---------------------------------------------------------
// Implementation

template<typename T>
T * Singleton<T>::ptr = 0;

template<class T>
T* SingletonPtr<T>::ptr = 0;
template<class T>
int SingletonPtr<T>::count = 0;

template<class T>
typename SingletonPtr<T>::memoryRelease 
SingletonPtr<T>::memorystate = SingletonPtr<T>::never;


template<class T>
inline SingletonPtr<T>::SingletonPtr(T* app)
{
   assert(ptr==0);

  ptr = app;
  count = 1;
  memorystate = never;
}


template<class T>
inline SingletonPtr<T>::SingletonPtr
  (T* app, SingletonPtr<T>::memoryRelease m)
{

  assert(ptr==0);

  memorystate = m;

  ptr = app;
  count = 1;
}


template<class T>
inline SingletonPtr<T>::SingletonPtr()
{
  assert(ptr!=0);
  assert( (count>=1) || (memorystate==never));

  ++count;
}

template<class T>
inline T* SingletonPtr<T>::operator->()
{
  assert(ptr!=0);

  return ptr;
}

template<class T>
inline T& SingletonPtr<T>::operator()()
{
  assert(ptr!=0);

  return *ptr;
}

template<class T>
inline SingletonPtr<T>::~SingletonPtr()
{
  --count;
  if (count<=0)
  {

assert(count==0);

    switch(memorystate)
    {
      case never: break;
      case array: delete[] ptr; break;
      case nonarray: delete ptr; break;
    }

    if (memorystate!=never)
      ptr=0;
  }
}


#endif




