/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2013-2018 Regents of the University of California.
 *
 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
 *
 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * ndn-cxx library 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 Lesser General Public License for more details.
 *
 * You should have received copies of the GNU General Public License and GNU Lesser
 * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
 */

#include "ndn-cxx/security/pib/key-container.hpp"
#include "ndn-cxx/security/pib/pib-impl.hpp"
#include "ndn-cxx/security/pib/detail/key-impl.hpp"
#include "ndn-cxx/util/concepts.hpp"

namespace ndn {
namespace security {
namespace pib {

NDN_CXX_ASSERT_FORWARD_ITERATOR(KeyContainer::const_iterator);

KeyContainer::const_iterator::const_iterator()
  : m_container(nullptr)
{
}

KeyContainer::const_iterator::const_iterator(std::set<Name>::const_iterator it,
                                             const KeyContainer& container)
  : m_it(it)
  , m_container(&container)
{
}

Key
KeyContainer::const_iterator::operator*()
{
  BOOST_ASSERT(m_container != nullptr);
  return m_container->get(*m_it);
}

KeyContainer::const_iterator&
KeyContainer::const_iterator::operator++()
{
  ++m_it;
  return *this;
}

KeyContainer::const_iterator
KeyContainer::const_iterator::operator++(int)
{
  const_iterator it(*this);
  ++m_it;
  return it;
}

bool
KeyContainer::const_iterator::operator==(const const_iterator& other)
{
  bool isThisEnd = m_container == nullptr || m_it == m_container->m_keyNames.end();
  bool isOtherEnd = other.m_container == nullptr || other.m_it == other.m_container->m_keyNames.end();
  return ((isThisEnd || isOtherEnd) ?
          (isThisEnd == isOtherEnd) :
          m_container->m_pib == other.m_container->m_pib && m_it == other.m_it);
}

bool
KeyContainer::const_iterator::operator!=(const const_iterator& other)
{
  return !(*this == other);
}

KeyContainer::KeyContainer(const Name& identity, shared_ptr<PibImpl> pibImpl)
  : m_identity(identity)
  , m_pib(std::move(pibImpl))
{
  BOOST_ASSERT(m_pib != nullptr);
  m_keyNames = m_pib->getKeysOfIdentity(identity);
}

KeyContainer::const_iterator
KeyContainer::begin() const
{
  return const_iterator(m_keyNames.begin(), *this);
}

KeyContainer::const_iterator
KeyContainer::end() const
{
  return const_iterator();
}

KeyContainer::const_iterator
KeyContainer::find(const Name& keyName) const
{
  return const_iterator(m_keyNames.find(keyName), *this);
}

size_t
KeyContainer::size() const
{
  return m_keyNames.size();
}

Key
KeyContainer::add(const uint8_t* key, size_t keyLen, const Name& keyName)
{
  if (m_identity != v2::extractIdentityFromKeyName(keyName)) {
    BOOST_THROW_EXCEPTION(std::invalid_argument("Key name `" + keyName.toUri() + "` does not match identity "
                                                "`" + m_identity.toUri() + "`"));
  }

  m_keyNames.insert(keyName);
  m_keys[keyName] = make_shared<detail::KeyImpl>(keyName, key, keyLen, m_pib);

  return get(keyName);
}

void
KeyContainer::remove(const Name& keyName)
{
  if (m_identity != v2::extractIdentityFromKeyName(keyName)) {
    BOOST_THROW_EXCEPTION(std::invalid_argument("Key name `" + keyName.toUri() + "` does not match identity "
                                                "`" + m_identity.toUri() + "`"));
  }

  m_keyNames.erase(keyName);
  m_keys.erase(keyName);
  m_pib->removeKey(keyName);
}

Key
KeyContainer::get(const Name& keyName) const
{
  if (m_identity != v2::extractIdentityFromKeyName(keyName)) {
    BOOST_THROW_EXCEPTION(std::invalid_argument("Key name `" + keyName.toUri() + "` does not match identity "
                                                "`" + m_identity.toUri() + "`"));
  }

  shared_ptr<detail::KeyImpl> key;
  auto it = m_keys.find(keyName);

  if (it != m_keys.end()) {
    key = it->second;
  }
  else {
    key = make_shared<detail::KeyImpl>(keyName, m_pib);
    m_keys[keyName] = key;
  }

  return Key(key);
}

bool
KeyContainer::isConsistent() const
{
  return m_keyNames == m_pib->getKeysOfIdentity(m_identity);
}

} // namespace pib
} // namespace security
} // namespace ndn
