/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  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 .
 */
/*
 * TremoloParser_ElementKeys.cpp
 *
 *  Created on: Mar 12, 2012
 *      Author: heber
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include "CodePatterns/MemDebug.hpp"
#include "TremoloParser_ElementKeys.hpp"
#include 
#include 
#include "CodePatterns/Log.hpp"
#include "Element/element.hpp"
#include "Element/periodentafel.hpp"
#include "Parser/Exceptions.hpp"
#include "World.hpp"
/** Parses a .potentials file and creates from it the knownTypes file.
 *
 * @param file input stream of .potentials file
 */
void ElementKeys::parseKnownTypes(std::istream &file)
{
  const periodentafel *periode = World::getInstance().getPeriode();
  // remove old mapping
  clear();
//  LOG(3, "INFO: additionalAtomData contains: " << additionalAtomData);
  // parse in file
  typedef boost::tokenizer >
      tokenizer;
  boost::char_separator tokensep(":\t ,;");
  boost::char_separator equalitysep("\t =");
  std::string line;
  while (file.good()) {
    std::getline( file, line );
    LOG(4, "INFO: full line of parameters is '" << line << "'");
    if (line.find("particle:") != string::npos) {
      LOG(3, "INFO: found line '" << line << "' containing keyword 'particle:'.");
      tokenizer tokens(line, tokensep);
      ASSERT(tokens.begin() != tokens.end(),
          "FormatParser< tremolo >::parseKnownTypes() - line with 'particle:' but no particles separated by comma.");
      // look for particle_type
      std::string particle_type("NULL");
      std::string element_type("NULL");
      for (tokenizer::iterator tok_iter = tokens.begin();
          tok_iter != tokens.end();
          ++tok_iter) {
        if ((*tok_iter).find("particle_type") != string::npos) {
          LOG(3, "INFO: found token '" << *tok_iter << "' containing keyword 'particle_type'.");
          tokenizer token((*tok_iter), equalitysep);
          ASSERT(token.begin() != token.end(),
                    "FormatParser< tremolo >::parseKnownTypes() - could not split particle_type by equality sign");
          tokenizer::iterator particle_iter = token.begin();
          particle_iter++;
          particle_type = *particle_iter;
        }
        if ((*tok_iter).find("element_name") != string::npos) {
          LOG(3, "INFO: found token '" << *tok_iter << "' containing keyword 'element_name'.");
          tokenizer token((*tok_iter), equalitysep);
          ASSERT(token.begin() != token.end(),
                    "FormatParser< tremolo >::parseKnownTypes() - could not split particle_type by equality sign");
          tokenizer::iterator element_iter = token.begin();
          element_iter++;
          element_type = *element_iter;
        }
      }
      if ((particle_type != "NULL") && (element_type != "NULL")) {
        if (periode->FindElement(element_type) != NULL) {
          LOG(1, "INFO: Added Type " << particle_type << " as reference to element " << element_type << ".");
          setType(particle_type, element_type);
        } else {
          ELOG(1, "INFO: Either Type " << particle_type << " or " << element_type << " could not be recognized." );
        }
      } else {
        ELOG(3, "Line does not contain both 'particle_type' and 'element_name' as keys." );
      }
    }
  }
}
/** Creates knownTypes as the identity, e.g. H -> H, He -> He, ... .
 *
 */
void ElementKeys::createKnownTypesByIdentity()
{
  // remove old mapping
  clear();
  // make knownTypes the identity mapping
  const periodentafel *periode = World::getInstance().getPeriode();
  for (periodentafel::const_iterator iter = periode->begin();
      iter != periode->end();
      ++iter) {
    setType( iter->second->getSymbol(), iter->second->getSymbol());
  }
}
/** Getter for value indexed by \a type.
 *
 * @param type key for map
 * @return value stored under \a type
 */
const std::string &ElementKeys::getType(const std::string &type) const throw (IllegalParserKeyException)
{
  const_iterator iter = find(type);
  if (iter == end()) {
    throw IllegalParserKeyException() << ParserMapLookup(type);
  } else
    return iter->second;
}
/** Getter for value indexed by \a type.
 *
 * @param type key for map
 * @return value stored under \a type
 */
void ElementKeys::setType(const std::string &type, const std::string &value) throw (IllegalParserKeyException)
{
  const_iterator iter = find(type);
  if (iter != end()) {
    throw IllegalParserKeyException() << ParserMapLookup(type);
  } else {
    insert( make_pair(type,value) );
    LOG(3, "DEBUG: Key " << type << " refers to element " << at(type) << ".");
  }
}