/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2017 Frederik Heber. 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 .
 */
/*
 * Value_vector.cpp
 *
 *  Created on: Mar 29, 2017
 *      Author: heber
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
//#include "CodePatterns/MemDebug.hpp"
#include "Value_vector.hpp"
#include 
#include 
#include "Geometry/GeometryRegistry.hpp"
#include "World.hpp"
const Vector Value::parseAsVector(const std::string &_value)
{
  Vector temp;
  if (GeometryRegistry::getInstance().isPresentByName(_value)) {
    temp = GeometryRegistry::getInstance().getByName(_value)->getVector();
    LOG(4, "DEBUG: Using stored vector '" << _value << "' from geometry registry.");
  } else {
    // dissect by ","
    typedef boost::tokenizer > tokenizer;
    boost::char_separator value_separator(",)( ");
    bool status = true;
    tokenizer tokens(_value, value_separator);
    if (!_value.empty()) {
      tokenizer::iterator tok_iter = tokens.begin();
      for (size_t i=0;i(*(tok_iter++));
        } catch (boost::bad_lexical_cast &e) {
          throw ParameterValueException();
        }
      }
//      if (tok_iter != tokens.end())
//        ELOG(2, "There are still components left: " << *tok_iter << "?");
    }
    if (!status)
      temp.Zero();
  }
  return temp;
}
const std::string Value::setFromVector(const Vector &_vec)
{
  std::stringstream output;
  for (size_t i=0;i::get() const throw(ParameterValueException)
{
  converted_value = parseAsVector(value);
  if (!ValueSet) throw ParameterValueException();
  if (!isValid(converted_value)) throw ParameterValueException();
  return converted_value;
}
const Vector & Value::getUnvalidated() const throw(ParameterValueException)
{
  converted_value = parseAsVector(value);
  if (!ValueSet) throw ParameterValueException();
  return converted_value;
}
/** Here are the original functions that we simply copied.
 *
 */
Value::Value() :
  ValueSet(false),
  validator(new DummyValidator)
{}
Value::Value(const Validator &_validator) :
  ValueSet(false),
  validator(_validator.clone())
{}
Value::Value(const std::vector &_ValidValues) :
  ValueSet(false),
  validator(NULL)
{
  validator = new DiscreteValidator(_ValidValues);
}
Value::Value(const range &_ValidRange) :
  ValueSet(false),
  validator(NULL)
{
  validator = new RangeValidator(_ValidRange);
}
Value::~Value()
{
  ASSERT(validator,
      "Value::~Value() - validator missing.");
  delete(validator);
}
bool Value::isValid(const Vector & _value) const throw(ParameterValidatorException)
{
  if (validator == NULL) throw ParameterValidatorException();
  return (*validator)(_value);
}
bool Value::operator==(const Value &_instance) const throw(ParameterValidatorException)
{
  if (validator == NULL) throw ParameterValidatorException();
  if (_instance.validator == NULL) throw ParameterValidatorException();
  bool status = true;
  status = status && (*validator == *_instance.validator);
  status = status && (ValueSet == _instance.ValueSet);
  if (ValueSet && _instance.ValueSet)
    status = status && (value == _instance.value);
  return status;
}
void Value::set(const Vector & _value) throw(ParameterException)
{
  // any value may be set, this allows Actions to have invalid parameters
  // (e.g. because the given atom id does not yet exist) that are checked
  // on performCall()
//  if (!isValid(_value)) throw ParameterValueException();
  if (!ValueSet)
    ValueSet = true;
  value = setFromVector(_value);
}
bool Value::isSet() const
{
  return ValueSet;
}
bool Value::isValidAsString(const std::string &_value) const throw(ParameterValidatorException)
{
  const Vector castvalue = parseAsVector(_value);
//  LOG(0, "Converted value reads " << castvalue <<".");
  return isValid(castvalue);
}
const std::string Value::getAsString() const throw(ParameterValueException)
{
  converted_value = parseAsVector(value);
  if (!ValueSet) throw ParameterValueException();
  if (!isValid(converted_value)) throw ParameterValueException();
  return value;
}
const std::string Value::getAsStringUnvalidated() const throw(ParameterValueException)
{
  if (!ValueSet) throw ParameterValueException();
  return value;
}
void Value::setAsString(const std::string &_value) throw(ParameterException)
{
  if (!ValueSet)
    ValueSet = true;
  value = _value;
//  LOG(0, "STATUS: Value is now set to " << value << ".");
}
const Validator &Value::getValidator() const
{
  if (validator == NULL) throw ParameterValidatorException();
  return *validator;
}
Validator &Value::getValidator()
{
  if (validator == NULL) throw ParameterValidatorException();
  return *validator;
}
const range & Value::getValidRange() const throw(ParameterValidatorException)
{
  return dynamic_cast&>(getValidator()).getValidRange();
}
void Value::setValidRange(const range &_range) throw(ParameterValueException)
{
  dynamic_cast&>(getValidator()).setValidRange(_range);
  if (ValueSet) {
      //std::cout << "Checking whether " << value << " is in range " << _range << "." << std::endl;
    if (!isValid(converted_value)){
      //std::cout << "ValueSet to false." << std::endl;
      ValueSet = false;
      // have full check again in assert such that it appears in output, too
      throw ParameterValueException() << ParameterValidValues(toString(_range));
    }
  }
  //  LOG(0, "STATUS: Valid range is now " << ValidRange << ".");
}
void Value::appendValidValue(const Vector &_value) throw(ParameterValidatorException)
{
  dynamic_cast&>(getValidator()).appendValidValue(_value);
}
const std::vector &Value::getValidValues() const throw(ParameterValidatorException)
{
  return dynamic_cast&>(getValidator()).getValidValues();
}