#include "headervaluemap.h"
#include <zypp-core/base/String.h>

namespace zyppng {

  HeaderValueMap::Value HeaderValueMap::InvalidValue;

  HeaderValue::HeaderValue()
    : _val ( new value_type() )
  {}

  HeaderValue::HeaderValue( const HeaderValue &other )
    : _val ( new value_type( *other._val ) )
  {}

  HeaderValue::HeaderValue( HeaderValue &&other ) noexcept
    : _val ( new value_type( std::move(*other._val) ) )
  {}

  HeaderValue::HeaderValue( const bool val )
    : _val ( new value_type(val) )
  {}

  HeaderValue::HeaderValue( const int32_t val )
    : _val ( new value_type(val) )
  {}

  HeaderValue::HeaderValue( const int64_t val )
    : _val ( new value_type(val) )
  {}

  HeaderValue::HeaderValue( const std::string &val )
    : _val ( new value_type(val) )
  {}

  HeaderValue::HeaderValue(const char *val)
    : HeaderValue( zypp::str::asString (val) )
  {}

  HeaderValue::HeaderValue( std::string &&val )
    : _val ( new value_type( std::move(val) ) )
  {}

  bool HeaderValue::valid() const
  {
    return ( _val->index () > 0 );
  }

  bool HeaderValue::isString() const
  {
    return std::holds_alternative<std::string>(*_val);
  }

  bool HeaderValue::isInt() const
  {
    return std::holds_alternative<int32_t>(*_val);
  }

  bool HeaderValue::isInt64() const
  {
    return std::holds_alternative<int64_t>(*_val);
  }

  bool HeaderValue::isBool() const
  {
    return std::holds_alternative<bool>(*_val);
  }

  const std::string &HeaderValue::asString() const
  {
    return std::get<std::string>(*_val);
  }

  int32_t HeaderValue::asInt() const
  {
    return std::get<int32_t>(*_val);
  }

  int64_t HeaderValue::asInt64() const
  {
    if ( std::holds_alternative<int32_t>(*_val) )
      return std::get<int32_t>( *_val );
    return std::get<int64_t>(*_val);
  }

  bool HeaderValue::asBool() const
  {
    return std::get<bool>(*_val);
  }

  HeaderValue::value_type &HeaderValue::asVariant()
  {
    return *_val;
  }

  const HeaderValue::value_type &HeaderValue::asVariant() const
  {
    return *_val;
  }

  HeaderValue &HeaderValue::operator=(const HeaderValue &other)
  {
    *_val = *other._val;
    return *this;
  }

  bool HeaderValue::operator==(const HeaderValue &other) const
  {
    return ( *_val == *other._val );
  }

  HeaderValue &HeaderValue::operator= ( HeaderValue &&other ) noexcept
  {
    *_val = std::move( *other._val );
    return *this;
  }

  HeaderValue &HeaderValue::operator= ( const std::string &val )
  {
    *_val = val;
    return *this;
  }

  HeaderValue &HeaderValue::operator= ( int32_t val )
  {
    *_val = val;
    return *this;
  }

  HeaderValue &HeaderValue::operator= ( int64_t val )
  {
    *_val = val;
    return *this;
  }

  HeaderValue &HeaderValue::operator= ( bool val )
  {
    *_val = val;
    return *this;
  }


  HeaderValueMap::HeaderValueMap( std::initializer_list<HeaderValueMap::ValueMap::value_type> init )
    : _values( std::move(init) )
  { }

  bool HeaderValueMap::contains(const std::string &key) const
  {
    return _values.count (key) > 0 && _values.at(key).size () > 0 ;
  }

  void HeaderValueMap::set(const std::string &key, Value val)
  {
    auto i = _values.find (key);
    if ( i == _values.end() ) {
      _values.insert ( std::make_pair(key, std::vector<Value>{std::move(val)}) );
    } else {
      i->second = std::vector<Value>{std::move(val)};
    }
  }

  void HeaderValueMap::set( const std::string &key, std::vector<Value> val )
  {
    auto i = _values.find (key);
    if ( i == _values.end() ) {
      _values.insert ( std::make_pair(key, std::move(val)) );
    } else {
      i->second = std::move(val);
    }
  }

  void HeaderValueMap::add(const std::string &key, const Value &val)
  {
    auto i = _values.find (key);
    if ( i == _values.end() ) {
      _values.insert ( std::make_pair(key, std::vector<Value>{val}) );
    } else {
      i->second.push_back(val);
    }
  }

  void HeaderValueMap::clear()
  {
    _values.clear();
  }

  HeaderValueMap::ValueMap::size_type HeaderValueMap::size() const noexcept
  {
    return _values.size();
  }

  std::vector<HeaderValueMap::Value> &HeaderValueMap::values(const std::string &key)
  {
    return _values[key];
  }

  const std::vector<HeaderValueMap::Value> &HeaderValueMap::values(const std::string &key) const
  {
    return _values.at(key);
  }

  HeaderValueMap::Value HeaderValueMap::value ( const std::string_view &str, const HeaderValueMap::Value &defaultVal) const
  { return value( std::string(str), defaultVal ); }

  HeaderValueMap::Value HeaderValueMap::value ( const std::string &str, const HeaderValueMap::Value &defaultVal) const
  {
    if ( !contains(str) || !_values.at(str).size() )
      return defaultVal;
    return _values.at(str).back();
  }

  HeaderValueMap::Value &HeaderValueMap::operator[](const std::string &key)
  {
    if ( !contains(key) )
      return InvalidValue;
    return _values[key].back();
  }

  HeaderValueMap::Value &HeaderValueMap::operator[]( const std::string_view &key )
  {
    return (*this)[std::string(key)];
  }

  const HeaderValueMap::Value &HeaderValueMap::operator[]( const std::string &key ) const
  {
    if ( !contains(key) )
      return InvalidValue;
    return _values.at(key).back();
  }

  const HeaderValueMap::Value &HeaderValueMap::operator[]( const std::string_view &key ) const
  {
    return (*this)[std::string(key)];
  }

  HeaderValueMap::const_iterator HeaderValueMap::erase(const const_iterator &i)
  {
    auto yi = _values.erase(i.base());
    return HeaderValueMap::const_iterator(yi);
  }

  bool HeaderValueMap::erase(const std::string &key)
  {
    return ( _values.erase(key) > 0 );
  }

}
