////////////////////////////////////////////////////////////////////////
/// \class RAT::Optimisers::OptimiserFactory
///
/// \brief  Factory for Just In Time creation of Optimisers
///
/// \author Phil G Jones <p.jones22@physics.ox.ac.uk>
/// \author Matt Mottram < m.mottram@qmul.ac.uk> -- contact person
///
/// REVISION HISTORY:\n
///     26/04/2011 : P G Jones - New file \n
///     2014-07-17 : P G Jones - Add register method.\n
///
/// \details Allows optimisers to be newed by string name, when required.
///         This is a singleton class.
///
////////////////////////////////////////////////////////////////////////

#ifndef __RAT_Optimiser_OptimiserFactory_
#define __RAT_Optimiser_OptimiserFactory_

#include <RAT/Factory.hh>
#include <RAT/Optimiser.hh>

#include <string>

namespace RAT
{

namespace Optimisers
{

class OptimiserFactory
{
public:
  /// Returns the only instance of the class
  static OptimiserFactory* GetInstance() { return Get(); }
  inline static OptimiserFactory* Get();

  /// Register a optimiser in the factory
  ///
  /// An example call is Register( MyOptimiser::GetName(), new Alloc<Optimiser, MyOptimiser>())
  ///
  /// @param[in] name of the optimiser
  /// @param[in] allocator instance of an Alloc with the correct optimiser type
  void Register( std::string name, AllocBase<Optimiser>* allocator );

  /// Returns the optimiser by name
  Optimiser* GetOptimiser( const std::string name ); ///< Optimiser name or name-init, init will be passed to the optimiser

private:
  /// Private constructor to prevent instantiation
  OptimiserFactory();

  Factory<Optimiser> fFactory; ///< Optimiser factory, contains allocators for Optimisers
};

inline OptimiserFactory*
OptimiserFactory::Get()
{
  static OptimiserFactory optimiserFactory;
  return &optimiserFactory;
}

} //::Optimiser

} //::RAT

#endif