/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2010-2012 University of Bonn. All rights reserved.
 * 
 *
 *   This file is part of MoleCuilder.
 *
 *    MoleCuilder 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, either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    MoleCuilder 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 MoleCuilder.  If not, see .
 */
/*
 * RandomNumberGeneratorFactory.cpp
 *
 *  Created on: Dec 31, 2010
 *      Author: heber
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include "CodePatterns/MemDebug.hpp"
#include 
#include "CodePatterns/Singleton_impl.hpp"
#include "CodePatterns/Assert.hpp"
#include "TemplatePowerSetGenerator.hpp"
#include "EmptyPrototypeTable.hpp"
#include 
#include 
#include 
#include 
#include 
#include 
#include "RandomNumberGenerator_Encapsulation.hpp"
#include "RandomNumberGeneratorFactory.hpp"
#include "RandomNumberGeneratorFactory.def"
RandomNumberDistributionFactory::TypeList RandomNumberGeneratorFactory::distribution = (RandomNumberDistributionFactory::TypeList) 0;
RandomNumberEngineFactory::TypeList RandomNumberGeneratorFactory::engine = (RandomNumberEngineFactory::TypeList) 0;
RandomNumberGeneratorFactory::EngineDistributionTable RandomNumberGeneratorFactory::GeneratorPrototypeTable;
RandomNumberGeneratorFactory::RandomNumberGeneratorFactory()
{
	FillPrototypeTable();
}
RandomNumberGeneratorFactory::~RandomNumberGeneratorFactory()
{
  // clear out factories map to allow boost::shared_ptr to do their work (i.e. to release mem)
  // this is necessary as factories is a object
  for (EngineDistributionTable::iterator iter = GeneratorPrototypeTable.begin();
      !GeneratorPrototypeTable.empty();
      iter = GeneratorPrototypeTable.begin()) {
    EmptyPrototypeTable< std::map > (iter->second);
    GeneratorPrototypeTable.erase(iter);
  }
  GeneratorPrototypeTable.clear();
}
void RandomNumberGeneratorFactory::FillPrototypeTable()
{
  // fill GeneratorPrototypeTable
#define SequenceElementizer(z,data) (data)
#define distributionengine_seqseq \
  BOOST_PP_SEQ_FOR_EACH_PRODUCT(SequenceElementizer, (engine_seq)(distribution_seq))
#define distributionengine_seqseq_a \
  BOOST_PP_SEQ_FOR_EACH_PRODUCT(SequenceElementizer, (engine_seq_a)(distribution_seq))
#define suffixseq ()(<>)
#define tableseq (*EnginePrototypeTable)(*DistributionPrototypeTable)
#define name_spaces_seq (RandomNumberEngineFactory::)(RandomNumberDistributionFactory::)
#define size_tupels BOOST_PP_SEQ_SIZE(tableseq)
#define TableItemPrinter(z,n,sequence) \
  [ \
  BOOST_PP_SEQ_ELEM(n,name_spaces_seq) \
  BOOST_PP_SEQ_ELEM(n,sequence) \
  ]
#define TemplateItemPrinter(z,n,sequence) \
  BOOST_PP_COMMA_IF(n) \
  boost:: \
  BOOST_PP_SEQ_ELEM(n,sequence) \
  BOOST_PP_SEQ_ELEM(n,suffixseq)
#define ParamItemPrinter(z,n,sequence)
#define BOOST_PP_LOCAL_MACRO(n) seqitems_as_enum_key_multidimmap(~, n, size_tupels, distributionengine_seqseq, GeneratorPrototypeTable, TableItemPrinter, new RandomNumberGenerator_Encapsulation , TemplateItemPrinter, ParamItemPrinter)
#define BOOST_PP_LOCAL_LIMITS  (0, BOOST_PP_SEQ_SIZE(distributionengine_seqseq)-1 )
#include BOOST_PP_LOCAL_ITERATE()
#define BOOST_PP_LOCAL_MACRO(n) seqitems_as_enum_key_multidimmap(~, n, size_tupels, distributionengine_seqseq_a, GeneratorPrototypeTable, TableItemPrinter, new RandomNumberGenerator_Encapsulation , TemplateItemPrinter, ParamItemPrinter)
#define BOOST_PP_LOCAL_LIMITS  (0, BOOST_PP_SEQ_SIZE(distributionengine_seqseq_a)-1 )
#include BOOST_PP_LOCAL_ITERATE()
}
RandomNumberGenerator& RandomNumberGeneratorFactory::makeRandomNumberGenerator() const
{
  // Instantiate and return (implicitly creates a copy of the stored prototype)
  RandomNumberEngineFactory::TypeList eng_type =
      RandomNumberEngineFactory::getInstance().getCurrentTypeEnum();
  RandomNumberDistributionFactory::TypeList dis_type =
      RandomNumberDistributionFactory::getInstance().getCurrentTypeEnum();
  return (*GeneratorPrototypeTable[ eng_type ][ dis_type ]);
}
RandomNumberGenerator& RandomNumberGeneratorFactory::makeRandomNumberGenerator(
    std::string engine_type,
    std::string distribution_type
    ) const
{
  RandomNumberEngineFactory::TypeList eng_type;
  RandomNumberDistributionFactory::TypeList dis_type;
  // Instantiate and return (implicitly creates a copy of the stored prototype)
  if (!engine_type.empty()) {
    eng_type = RandomNumberEngineFactory::getInstance().getEnum(engine_type);
  } else
    eng_type = RandomNumberEngineFactory::getInstance().getCurrentTypeEnum();
  if (!distribution_type.empty()) {
    dis_type = RandomNumberDistributionFactory::getInstance().getEnum(distribution_type);
  } else
    dis_type = RandomNumberDistributionFactory::getInstance().getCurrentTypeEnum();
  return (*GeneratorPrototypeTable[ eng_type ][ dis_type ]);
  return (*GeneratorPrototypeTable[ eng_type ][ dis_type ]);
}
void RandomNumberGeneratorFactory::setEngine(std::string engine_type)
{
  RandomNumberEngineFactory::getInstance().setCurrentType(engine_type);
}
const std::string &RandomNumberGeneratorFactory::getEngineName() const
{
  return RandomNumberEngineFactory::getInstance().getCurrentTypeName();
}
void RandomNumberGeneratorFactory::setDistribution(std::string distribution_type)
{
  RandomNumberDistributionFactory::getInstance().setCurrentType(distribution_type);
}
const std::string &RandomNumberGeneratorFactory::getDistributionName() const
{
  return RandomNumberDistributionFactory::getInstance().getCurrentTypeName();
}
CONSTRUCT_SINGLETON(RandomNumberGeneratorFactory)
#include "RandomNumberGeneratorFactory.undef"