/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *
 * This file is part of NMM. 
 * 
 * NMM is free software; you can redistribute it and/or modify it    
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; only version 2 of the License.      
 * 
 * NMM 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 General Public 
 * License for more details.  
 * 
 * You should have received a copy of the GNU General Public License 
 * along with NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */


#ifndef NMM_SINGLETON_LINUX_HPP
#define NMM_SINGLETON_LINUX_HPP NMM_SINGLETON_LINUX_HPP

#include "nmm/nmm_prefix.hpp"

#include <stdlib.h>

/** Declare a singleton class.
 *
 * This macro must be placed at the beginning of the body of a class declaration
 * if the class is a singleton.
 *
 * @param T The name of the class
 * @param CREATION_POLICY The creation policy
 * @param LIFETIME_POLICY The lifetime policy
 * @param THREADING_MODEL The threading model
 */
#define DECLARE_SINGLETON(T,CREATION_POLICY,LIFETIME_POLICY,THREADING_MODEL) \
public: \
  typedef CREATION_POLICY<T> CreationPolicy; \
  typedef LIFETIME_POLICY<T> LifetimePolicy; \
  typedef THREADING_MODEL<T> ThreadingModel; \
  typedef Singleton<T, CREATION_POLICY, LIFETIME_POLICY, THREADING_MODEL> Singleton; \
private:

/** Define a singleton class.
 *
 * This macro must be placed in the implementation file of a class
 * if the class is a singleton.
 */
#ifdef __CYGWIN__
#define DEFINE_SINGLETON(CLASS) \
  CLASS::Singleton::InstanceType* CLASS::Singleton::_instance = 0; \
  bool CLASS::Singleton::destroyed = false;
#else
#ifdef BUILD_GCC2_SINGLETON
#define DEFINE_SINGLETON(CLASS) \
  CLASS::Singleton::InstanceType* CLASS::Singleton::_instance = 0; \
  bool CLASS::Singleton::destroyed = false;
#else
 #define DEFINE_SINGLETON(CLASS)
#endif
#endif


/* The following source code is based on ideas and source code samples from */

////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2001 by Andrei Alexandrescu
// This code accompanies the book:
// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
//     Patterns Applied". Copyright (c) 2001. Addison-Wesley.
// Permission to use, copy, modify, distribute and sell this software for any
//     purpose is hereby granted without fee, provided that the above copyright
//     notice appear in all copies and that both that copyright notice and this
//     permission notice appear in supporting documentation.
// The author or Addison-Welsey Longman make no representations about the
//     suitability of this software for any purpose. It is provided "as is"
//     without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////

/**  Defines a single threaded threading model 
 *
 * @param T The name of the class
 */
template <class T>
class SingleThreaded {
public:
  typedef  T VolatileType;
};

/**  Defines a multi threaded threading model 
 *
 * @param T The name of the class
 */
template <class T>
class MultiThreaded {
public:
  typedef T VolatileType;
};

/**  Defines a creation plociy using new operator
 *
 * @param T The name of the class
 */
template <class T>
class CreateUsingNew {
public:

 /**  Creates an instance of T using new operator
  *
  * @return pointer to the created object
  */
  static T* create()           {return new T();}

 /**  Destroy an instance of T using delete operator
  * @param obj pinter to the object that should be deleted
  */
  static void destroy(T* obj)  {delete obj;}
};

/**  Defines a lifetime plociy. 
 *
 * @param T The name of the class
 */
template <class T>
class DefaultLifetime {
public:
  typedef void (*deleteMethod)();
  /** Specifies when tho destroy the singelton. 
   * 
   * @param d method pointer to a function that destroys the singleton. The method pointer is registerd at atexit. 
   */
  static void scheduleDestruction( deleteMethod d) { atexit(d); }

  /** Specifies what happens if dead reference occurs
   */
  static void onDeadReference()                   { /*throw std::logic_error("Dead Reference Detected");*/ }
};

/** Singleton class.
 * 
 * This template can be used to create a Singleton from arbitrary objects. 
 * 
 * @param T The name of the class
 * @param CREATION_POLICY The creation policy
 * @param LIFETIME_POLICY The lifetime policy
 * @param THREADING_MODEL The threading model
 */
template <
  class T,
  template <class> class CreationPolicy = CreateUsingNew,
  template <class> class LifetimePolicy = DefaultLifetime,
  template <class> class ThreadingModel = MultiThreaded
>
class Singleton {
public:
  /** Get a reference to a singleton of a specific type. If an instance of the object does not exist it is created
   *
   * @return reference to the sole instance of object with type T
   */
  static T& getInstance();

protected:
  /** Constructor
   */
  Singleton(){};

private:
  /** Method to destroy the singleton 
   */
  static void destroySingleton();
  typedef typename ThreadingModel<T>::VolatileType InstanceType;
  static InstanceType* _instance;
  static  bool destroyed;
};



/** Implementation */

template <
  class T,
  template <class> class CreationPolicy, //creation policy
  template <class> class LifetimePolicy, //Lifetime policy
  template <class> class ThreadingModel  //Threading model
>

T& Singleton<T, CreationPolicy, LifetimePolicy, ThreadingModel>::getInstance() {
  if (!_instance) {
//    typename ThreadingModel::Lock guard;
    if (!_instance) {
      if (destroyed) {
        LifetimePolicy<T>::onDeadReference();
        destroyed = false;
      }
      _instance = CreationPolicy<T>::create();
      LifetimePolicy<T>::scheduleDestruction(&destroySingleton);
    }
  }
  return *_instance;
}

template <
  class T,
  template <class> class CreationPolicy, //creation policy
  template <class> class LifetimePolicy, //Lifetime policy
  template <class> class ThreadingModel  //Threading model
>
void Singleton<T, CreationPolicy, LifetimePolicy, ThreadingModel>::destroySingleton() {
  CreationPolicy<T>::destroy(_instance);
  _instance = 0;
  destroyed = true;
}

#ifndef __CYGWIN__
#ifndef BUILD_GCC2_SINGLETON
template <
  class T,
  template <class> class CreationPolicy, //creation policy
  template <class> class LifetimePolicy, //Lifetime policy
  template <class> class ThreadingModel  //Threading model
>
typename Singleton<T, CreationPolicy, LifetimePolicy, ThreadingModel>::InstanceType*
Singleton<T, CreationPolicy, LifetimePolicy, ThreadingModel>::_instance = 0;

template <
  class T,
  template <class> class CreationPolicy, //creation policy
  template <class> class LifetimePolicy, //Lifetime policy
  template <class> class ThreadingModel  //Threading model
>
bool Singleton<T, CreationPolicy, LifetimePolicy, ThreadingModel>::destroyed = false;
#endif
#endif




#include "nmm/nmm_suffix.hpp"

#endif
