text: /*
   * Copyright (C) 2006-2013  Music Technology Group - Universitat Pompeu Fabra
   *
   * This file is part of Essentia
   *
   * Essentia is free software: you can redistribute it and/or modify it under
   * the terms of the GNU Affero General Public License as published by the Free
   * Software Foundation (FSF), either version 3 of the License, or (at your
   * option) any later version.
   *
   * This program 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 Affero GNU General Public License
   * version 3 along with this program.  If not, see http://www.gnu.org/licenses/
   */
  
  #ifndef ESSENTIA_ALGORITHMFACTORY_CPP
  #define ESSENTIA_ALGORITHMFACTORY_CPP
  
  namespace essentia {
  
  template <typename BaseAlgorithm>
  EssentiaFactory<BaseAlgorithm>& EssentiaFactory<BaseAlgorithm>::instance() {
    if (!_instance) {
      throw EssentiaException("You haven't initialized the factory yet... Please do it now!");
    }
    return *_instance;
  }
  
  template <typename BaseAlgorithm>
  std::vector<std::string> EssentiaFactory<BaseAlgorithm>::keys() {
    std::vector<std::string> result;
    const CreatorMap& m = instance()._map;
    for (typename CreatorMap::const_iterator it = m.begin(); it != m.end(); ++it) {
      result.push_back(it->first);
    }
    return result;
  }
  
  template <typename BaseAlgorithm>
  BaseAlgorithm* EssentiaFactory<BaseAlgorithm>::create_i(const std::string& id) const {
    E_DEBUG(EFactory, BaseAlgorithm::processingMode << ": Creating algorithm: " << id);
  
    typename CreatorMap::const_iterator it = _map.find(id);
    if (it == _map.end()) {
      std::ostringstream msg;
      msg << "Identifier '" << id << "' not found in registry...\n";
      msg << "Available algorithms:";
      for (it=_map.begin(); it!=_map.end(); ++it) {
        msg << ' ' << it->first;
      }
      throw EssentiaException(msg);
    }
  
    E_DEBUG_INDENT;
    BaseAlgorithm* algo = it->second.create();
    E_DEBUG_OUTDENT;
  
    // adds the name of the algorithm to itself so it knows it.
    algo->setName(id);
  
    // declare the acceptable parameters for this algorithm. It would be nicer to
    // have this automatically done in the Configurable constructor, but we cannot
    // call  abstract virtual functions from the base constructor.
    algo->declareParameters();
  
    // configure with default parameters to ensure we're not in an undefined state.
    // This should never throw an exception. If it does, explain why it should
    // absolutely be fixed.
    try {
      // default parameters should have been filled by the call to declareParameters
      // from the constructor, so there is no need to make a copy of them, just call
      // arg-less version of configure()
      E_DEBUG(EFactory, BaseAlgorithm::processingMode << ": Configuring " << id << " with default parameters");
      algo->configure();
    }
    catch (EssentiaException& e) {
      // We should never arrive here, because it means that we can have algorithms
      // which are not configured at all, hence in an invalid state. This cannot
      // happen, hence the message explaining why and we rethrow the exception.
      std::ostringstream msg;
      msg << "ERROR: Algorithm " << id << " could not be configured using default values.\n"
          << "       If it doesn't make sense for an algorithm to be configured with\n"
          << "       default values, then it should still be able to be instantiated, and\n"
          << "       it is your responsibility to keep track of the fact that it should\n"
          << "       currently be impossible to call it (for example, by checking if the state\n"
          << "       is valid upon entering the process() method).\n\n"
          << e.what();
      throw EssentiaException(msg);
    }
  
    E_DEBUG(EFactory, BaseAlgorithm::processingMode << ": Creating " << id << " ok!");
  
    return algo;
  }
  
  
  #define CREATE_I template <typename BaseAlgorithm> BaseAlgorithm* EssentiaFactory<BaseAlgorithm>::create_i(const std::string& id
  #define P(n) , const std::string& name##n, const Parameter& value##n
  #define AP(n) params.add(name##n, value##n);
  
  #define CREATE_I_BEG ) const {                                                                              \
    E_DEBUG(EFactory, BaseAlgorithm::processingMode << ": Creating algorithm: " << id);                       \
    typename CreatorMap::const_iterator it = _map.find(id);                                                   \
    if (it == _map.end()) {                                                                                   \
      std::ostringstream msg;                                                                                 \
      msg << "Identifier '" << id << "' not found in registry...\n";                                          \
      msg << "Available algorithms:";                                                                         \
      for (it=_map.begin(); it!=_map.end(); ++it) {                                                           \
        msg << ' ' << it->first;                                                                              \
      }                                                                                                       \
      throw EssentiaException(msg);                                                                           \
    }                                                                                                         \
    E_DEBUG_INDENT;                                                                                           \
    BaseAlgorithm* algo = it->second.create();                                                                \
    E_DEBUG_OUTDENT;                                                                                          \
    algo->setName(id);                                                                                        \
    algo->declareParameters();                                                                                \
    ParameterMap params;
  
  #define CREATE_I_END                                                                                        \
    algo->setParameters(params);                                                                              \
    E_DEBUG(EFactory, BaseAlgorithm::processingMode << ": Configuring " << id << " with default parameters"); \
    algo->configure();                                                                                        \
    E_DEBUG(EFactory, BaseAlgorithm::processingMode << ": Creating " << id << " ok!");                        \
    return algo;                                                                                              \
  }
  
  
  CREATE_I P(1) CREATE_I_BEG AP(1) CREATE_I_END
  CREATE_I P(1) P(2) CREATE_I_BEG AP(1) AP(2) CREATE_I_END
  CREATE_I P(1) P(2) P(3) CREATE_I_BEG AP(1) AP(2) AP(3) CREATE_I_END
  CREATE_I P(1) P(2) P(3) P(4) CREATE_I_BEG AP(1) AP(2) AP(3) AP(4) CREATE_I_END
  CREATE_I P(1) P(2) P(3) P(4) P(5) CREATE_I_BEG AP(1) AP(2) AP(3) AP(4) AP(5) CREATE_I_END
  CREATE_I P(1) P(2) P(3) P(4) P(5) P(6) CREATE_I_BEG AP(1) AP(2) AP(3) AP(4) AP(5) AP(6) CREATE_I_END
  CREATE_I P(1) P(2) P(3) P(4) P(5) P(6) P(7)
    CREATE_I_BEG AP(1) AP(2) AP(3) AP(4) AP(5) AP(6) AP(7) CREATE_I_END
  CREATE_I P(1) P(2) P(3) P(4) P(5) P(6) P(7) P(8)
    CREATE_I_BEG AP(1) AP(2) AP(3) AP(4) AP(5) AP(6) AP(7) AP(8) CREATE_I_END
  CREATE_I P(1) P(2) P(3) P(4) P(5) P(6) P(7) P(8) P(9)
    CREATE_I_BEG AP(1) AP(2) AP(3) AP(4) AP(5) AP(6) AP(7) AP(8) AP(9) CREATE_I_END
  CREATE_I P(1) P(2) P(3) P(4) P(5) P(6) P(7) P(8) P(9) P(10)
    CREATE_I_BEG AP(1) AP(2) AP(3) AP(4) AP(5) AP(6) AP(7) AP(8) AP(9) AP(10) CREATE_I_END
  CREATE_I P(1) P(2) P(3) P(4) P(5) P(6) P(7) P(8) P(9) P(10) P(11)
    CREATE_I_BEG AP(1) AP(2) AP(3) AP(4) AP(5) AP(6) AP(7) AP(8) AP(9) AP(10) AP(11) CREATE_I_END
  CREATE_I P(1) P(2) P(3) P(4) P(5) P(6) P(7) P(8) P(9) P(10) P(11) P(12)
    CREATE_I_BEG AP(1) AP(2) AP(3) AP(4) AP(5) AP(6) AP(7) AP(8) AP(9) AP(10) AP(11) AP(12) CREATE_I_END
  CREATE_I P(1) P(2) P(3) P(4) P(5) P(6) P(7) P(8) P(9) P(10) P(11) P(12) P(13)
    CREATE_I_BEG AP(1) AP(2) AP(3) AP(4) AP(5) AP(6) AP(7) AP(8) AP(9) AP(10) AP(11) AP(12) AP(13) CREATE_I_END
  CREATE_I P(1) P(2) P(3) P(4) P(5) P(6) P(7) P(8) P(9) P(10) P(11) P(12) P(13) P(14)
    CREATE_I_BEG AP(1) AP(2) AP(3) AP(4) AP(5) AP(6) AP(7) AP(8) AP(9) AP(10) AP(11) AP(12) AP(13) AP(14) CREATE_I_END
  CREATE_I P(1) P(2) P(3) P(4) P(5) P(6) P(7) P(8) P(9) P(10) P(11) P(12) P(13) P(14) P(15)
    CREATE_I_BEG AP(1) AP(2) AP(3) AP(4) AP(5) AP(6) AP(7) AP(8) AP(9) AP(10) AP(11) AP(12) AP(13) AP(14) AP(15) CREATE_I_END
  CREATE_I P(1) P(2) P(3) P(4) P(5) P(6) P(7) P(8) P(9) P(10) P(11) P(12) P(13) P(14) P(15) P(16)
    CREATE_I_BEG AP(1) AP(2) AP(3) AP(4) AP(5) AP(6) AP(7) AP(8) AP(9) AP(10) AP(11) AP(12) AP(13) AP(14) AP(15) AP(16) CREATE_I_END
  
  
  #undef CREATE_I_END
  #undef CREATE_I_BODY
  #undef AP
  #undef P
  #undef CREATE_I
  
  } // namespace essentia
  
  #endif // ESSENTIA_ALGORITHMFACTORY_CPP
  