/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
 * Copyright (c) 2014, Regents of the University of California.
 *
 * This file is part of NDNS (Named Data Networking Domain Name Service).
 * See AUTHORS.md for complete list of NDNS authors and contributors.
 *
 * NDNS 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 3 of the License, or (at your option) any later version.
 *
 * NDNS 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
 * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "name-server.hpp"
#include "logger.hpp"
#include "clients/response.hpp"
#include <ndn-cxx/encoding/encoding-buffer.hpp>

namespace ndn {
namespace ndns {
NDNS_LOG_INIT("NameServer")

const time::milliseconds NAME_SERVER_DEFAULT_CONTENT_FRESHNESS(4000);

NameServer::NameServer(const Name& zoneName, const Name& certName, Face& face, DbMgr& dbMgr,
                       KeyChain& keyChain, Validator& validator)
  : m_zone(zoneName)
  , m_dbMgr(dbMgr)
  , m_ndnsPrefix(zoneName)
  , m_keyPrefix(zoneName)
  , m_certName(certName)
  , m_contentFreshness(NAME_SERVER_DEFAULT_CONTENT_FRESHNESS)
  , m_face(face)
  , m_keyChain(keyChain)
  , m_validator(validator)
{
  if (!m_keyChain.doesCertificateExist(m_certName)) {
    NDNS_LOG_FATAL("Certificate: " << m_certName << " does not exist");
    throw Error("certificate does not exist in the KeyChain: " + m_certName.toUri());
  }

  m_dbMgr.find(m_zone);

  if (m_zone.getId() == 0) {
    NDNS_LOG_FATAL("m_zone does not exist: " << zoneName);
    throw Error("Zone " + zoneName.toUri() + " does not exist in the database");
  }

  m_ndnsPrefix.append(ndns::label::NDNS_ITERATIVE_QUERY);
  m_keyPrefix.append(ndns::label::NDNS_CERT_QUERY);

  m_face.setInterestFilter(m_ndnsPrefix,
                           bind(&NameServer::onInterest, this, _1, _2),
                           bind(&NameServer::onRegisterFailed, this, _1, _2)
                           );

  m_face.setInterestFilter(m_keyPrefix,
                           bind(&NameServer::onInterest, this, _1, _2),
                           bind(&NameServer::onRegisterFailed, this, _1, _2)
                           );

  NDNS_LOG_INFO("Zone: " << m_zone.getName() << " binds "
                << "Prefix: " << m_ndnsPrefix << " and " << m_keyPrefix
                << " with Certificate: " << m_certName
                );
}

void
NameServer::onInterest(const Name& prefix, const Interest& interest)
{
  label::MatchResult re;
  if (!label::matchName(interest, "", m_zone.getName(), re))
    return;

  if (re.rrType == ndns::label::NDNS_UPDATE_LABEL) {
    this->handleUpdate(prefix, interest, re); // NDNS Update
  }
  else {
    this->handleQuery(prefix, interest, re);  // NDNS Iterative query
  }
}

void
NameServer::handleQuery(const Name& prefix, const Interest& interest, const label::MatchResult& re)
{
  Rrset rrset(&m_zone);
  rrset.setLabel(re.rrLabel);
  rrset.setType(re.rrType);

  NDNS_LOG_TRACE("query record: " << interest.getName());

  if (m_dbMgr.find(rrset)) {
    // find the record: NDNS-RESP, NDNS-AUTH, NDNS-RAW, or NDNS-NACK
    shared_ptr<Data> answer = make_shared<Data>(rrset.getData());
    NDNS_LOG_TRACE("answer query with existing Data: " << answer->getName());
    m_face.put(*answer);
  }
  else {
    // no record, construct NACK
    Block block = nonNegativeIntegerBlock(::ndn::ndns::tlv::NdnsType, NDNS_NACK);
    MetaInfo info;
    info.addAppMetaInfo(block);
    info.setFreshnessPeriod(this->getContentFreshness());
    Name name = interest.getName();
    name.appendVersion();
    shared_ptr<Data> answer = make_shared<Data>(name);
    answer->setMetaInfo(info);

    m_keyChain.sign(*answer, m_certName);
    NDNS_LOG_TRACE("answer query with NDNS-NACK: " << answer->getName());
    m_face.put(*answer);
  }
}

void
NameServer::handleUpdate(const Name& prefix, const Interest& interest, const label::MatchResult& re)
{
  if (re.rrLabel.size() == 1) {
    // for current, we only allow Update message contains one Data, and ignore others
    auto it = re.rrLabel.begin();
    shared_ptr<Data> data;
    try {
      // blockFromValue may throw exception, which should not lead to failure of name server
      const Block& block = it->blockFromValue();
      data = make_shared<Data>(block);
    }
    catch (std::exception& e) {
      NDNS_LOG_WARN("exception when getting update info: " << e.what());
      return;
    }
    m_validator.validate(*data,
                         bind(&NameServer::doUpdate, this, interest.shared_from_this(), data),
                         [this] (const shared_ptr<const Data>& data, const std::string& msg) {
                           NDNS_LOG_WARN("Ignoring update that did not pass the verification");
                         });
  }
}

void
NameServer::onRegisterFailed(const ndn::Name& prefix, const std::string& reason)
{
  NDNS_LOG_FATAL("fail to register prefix=" << prefix << ". Due to: " << reason);
  throw Error("zone " + m_zone.getName().toUri() + " register prefix: " +
              prefix.toUri() + " fails. due to: " + reason);
}

void
NameServer::doUpdate(const shared_ptr<const Interest>& interest,
                     const shared_ptr<const Data>& data)
{
  label::MatchResult re;
  try {
    if (!label::matchName(*data, "", m_zone.getName(), re))
      return;
  }
  catch (std::exception& e) {
    NDNS_LOG_INFO("Error while name/certificate matching: " << e.what());
  }

  Rrset rrset(&m_zone);
  rrset.setLabel(re.rrLabel);
  rrset.setType(re.rrType);

  Block ndnsType = nonNegativeIntegerBlock(::ndn::ndns::tlv::NdnsType, NDNS_RESP);
  MetaInfo info;
  info.addAppMetaInfo(ndnsType);
  info.setFreshnessPeriod(this->getContentFreshness());
  Name name = interest->getName();
  name.appendVersion();
  shared_ptr<Data> answer = make_shared<Data>(name);
  answer->setMetaInfo(info);

  Block blk(ndn::ndns::tlv::RrData);
  try {
    if (m_dbMgr.find(rrset)) {
      const name::Component& newVersion = re.version;
      if (newVersion > rrset.getVersion()) {
        // update existing record
        rrset.setVersion(newVersion);
        rrset.setData(data->wireEncode());
        m_dbMgr.update(rrset);
        blk.push_back(nonNegativeIntegerBlock(ndn::ndns::tlv::UpdateReturnCode, UPDATE_OK));
        blk.encode(); // must
        answer->setContent(blk);
        NDNS_LOG_TRACE("replace old record and answer update with UPDATE_OK");
      }
      else {
        blk.push_back(nonNegativeIntegerBlock(ndn::ndns::tlv::UpdateReturnCode, UPDATE_FAILURE));
        blk.encode();
        answer->setContent(blk);
        NDNS_LOG_TRACE("answer update with UPDATE_FAILURE");
      }
    }
    else {
      // insert new record
      rrset.setVersion(re.version);
      rrset.setData(data->wireEncode());
      rrset.setTtl(m_zone.getTtl());
      m_dbMgr.insert(rrset);
      blk.push_back(nonNegativeIntegerBlock(ndn::ndns::tlv::UpdateReturnCode, UPDATE_OK));
      blk.encode();
      answer->setContent(blk);
      NDNS_LOG_TRACE("insert new record and answer update with UPDATE_OK");
    }
  }
  catch (std::exception& e) {
    blk.push_back(nonNegativeIntegerBlock(ndn::ndns::tlv::UpdateReturnCode, UPDATE_FAILURE));
    blk.encode(); // must
    answer->setContent(blk);
    NDNS_LOG_INFO("Error processing the update: " << e.what());
    NDNS_LOG_TRACE("exception happens and answer update with UPDATE_FAILURE");
  }
  m_keyChain.sign(*answer, m_certName);
  m_face.put(*answer);
}

} // namespace ndns
} // namespace ndn
