/****************************************************************************
** Copyright (c) 2001-2014
**
** This file is part of the QuickFIX FIX Engine
**
** This file may be distributed under the terms of the quickfixengine.org
** license as defined by quickfixengine.org and appearing in the file
** LICENSE included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.quickfixengine.org/LICENSE for licensing information.
**
** Contact ask@quickfixengine.org if any conditions of this licensing are
** not clear to you.
**
****************************************************************************/

#ifdef _MSC_VER
#include "stdafx.h"
#else
#include "config.h"
#endif

#include "Dictionary.h"
#include "FieldConvertors.h"
#include <algorithm>

namespace FIX {
std::string Dictionary::getString(const std::string &key, bool capitalize) const
    EXCEPT(ConfigError, FieldConvertError) {
  Data::const_iterator i = m_data.find(string_toUpper(key));
  if (i == m_data.end()) {
    throw ConfigError(key + " not defined");
  }

  std::string result = i->second;
  if (capitalize) {
    std::transform(result.begin(), result.end(), result.begin(), toupper);
  }

  return result;
}

int Dictionary::getInt(const std::string &key) const EXCEPT(ConfigError, FieldConvertError) {
  try {
    return IntConvertor::convert(getString(key));
  } catch (FieldConvertError &) {
    throw ConfigError("Illegal value " + getString(key) + " for " + key);
  }
}

double Dictionary::getDouble(const std::string &key) const EXCEPT(ConfigError, FieldConvertError) {
  try {
    return DoubleConvertor::convert(getString(key));
  } catch (FieldConvertError &) {
    throw ConfigError("Illegal value " + getString(key) + " for " + key);
  }
}

bool Dictionary::getBool(const std::string &key) const EXCEPT(ConfigError, FieldConvertError) {
  try {
    return BoolConvertor::convert(getString(key));
  } catch (FieldConvertError &) {
    throw ConfigError("Illegal value " + getString(key) + " for " + key);
  }
}

int Dictionary::getDay(const std::string &key) const EXCEPT(ConfigError, FieldConvertError) {
  try {
    std::string value = getString(key);
    if (value.size() < 2) {
      throw FieldConvertError();
    }
    std::string abbr = value.substr(0, 2);
    std::transform(abbr.begin(), abbr.end(), abbr.begin(), tolower);
    if (abbr == "su") {
      return 1;
    }
    if (abbr == "mo") {
      return 2;
    }
    if (abbr == "tu") {
      return 3;
    }
    if (abbr == "we") {
      return 4;
    }
    if (abbr == "th") {
      return 5;
    }
    if (abbr == "fr") {
      return 6;
    }
    if (abbr == "sa") {
      return 7;
    }
  } catch (FieldConvertError &) {
    throw ConfigError("Illegal value " + getString(key) + " for " + key);
  }
  return -1;
}

void Dictionary::setString(const std::string &key, const std::string &value) {
  m_data[string_strip(string_toUpper(key))] = string_strip(value);
}

void Dictionary::setInt(const std::string &key, int value) {
  m_data[string_strip(string_toUpper(key))] = IntConvertor::convert(value);
}

void Dictionary::setDouble(const std::string &key, double value) {
  m_data[string_strip(string_toUpper(key))] = DoubleConvertor::convert(value);
}

void Dictionary::setBool(const std::string &key, bool value) {
  m_data[string_strip(string_toUpper(key))] = BoolConvertor::convert(value);
}

void Dictionary::setDay(const std::string &key, int value) {
  switch (value) {
  case 1:
    setString(key, "SU");
    break;
  case 2:
    setString(key, "MO");
    break;
  case 3:
    setString(key, "TU");
    break;
  case 4:
    setString(key, "WE");
    break;
  case 5:
    setString(key, "TH");
    break;
  case 6:
    setString(key, "FR");
    break;
  case 7:
    setString(key, "SA");
    break;
  }
}

bool Dictionary::has(const std::string &key) const { return m_data.find(string_toUpper(key)) != m_data.end(); }

void Dictionary::merge(const Dictionary &toMerge) {
  Data::const_iterator i = toMerge.m_data.begin();
  for (; i != toMerge.m_data.end(); ++i) {
    if (m_data.find(i->first) == m_data.end()) {
      m_data[i->first] = i->second;
    }
  }
}
} // namespace FIX
