/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
 * Copyright (c) 2014-2015,  Regents of the University of California
 *
 * This file is part of ndn-group-encrypt (Group-based Encryption Protocol for NDN).
 * See AUTHORS.md for complete list of ndn-group-encrypt authors and contributors.
 *
 * ndn-group-encrypt 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.
 *
 * ndn-group-encrypt 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
 * ndn-group-encrypt, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author Zhiyi Zhang <dreamerbarrychang@gmail.com>
 */

#include "group-manager.hpp"
#include "encryptor.hpp"
#include "encrypted-content.hpp"

#include <map>

namespace ndn {
namespace gep {

static const std::string E_KEY_COMPONENT = "E-KEY";
static const std::string D_KEY_COMPONENT = "D-KEY";

GroupManager::GroupManager(const Name& managedNamespace, const std::string& dbDir,
                           const int paramLength, const int freshPeriod)
  : m_namespace(managedNamespace)
  , m_db(dbDir)
  , m_paramLength(paramLength)
  , m_freshPeriod(freshPeriod)
{
}

std::list<Data>
GroupManager::getGroupKey(const TimeStamp& timeslot)
{
  std::map<Name, Buffer> memberKeys;
  std::list<Data> result;

  // get time interval
  Interval finalInterval = calculateInterval(timeslot, memberKeys);
  if (finalInterval.isValid() == false)
    return result;

  std::string startTs = boost::posix_time::to_iso_string(finalInterval.getStartTime());
  std::string endTs = boost::posix_time::to_iso_string(finalInterval.getEndTime());

  // generate the pri key and pub key
  Buffer priKeyBuf, pubKeyBuf;
  generateKeyPairs(priKeyBuf, pubKeyBuf);

  // add the first element to the result
  // E-KEY (public key) data packet name convention:
  // /<data_type>/E-KEY/[start-ts]/[end-ts]
  Data data = createEKeyData(startTs, endTs, pubKeyBuf);
  result.push_back(data);

  // encrypt pri key with pub key from certificate
  for (const auto& entry : memberKeys) {
    const Name& keyName = entry.first;
    const Buffer& certKey = entry.second;

    // generate the name of the packet
    // D-KEY (private key) data packet name convention:
    // /<data_type>/D-KEY/[start-ts]/[end-ts]/[member-name]
    data = createDKeyData(startTs, endTs, keyName, priKeyBuf, certKey);
    result.push_back(data);
  }
  return result;
}

void
GroupManager::addSchedule(const std::string& scheduleName, const Schedule& schedule)
{
  m_db.addSchedule(scheduleName, schedule);
}

void
GroupManager::deleteSchedule(const std::string& scheduleName)
{
  m_db.deleteSchedule(scheduleName);
}

void
GroupManager::updateSchedule(const std::string& scheduleName, const Schedule& schedule)
{
  m_db.updateSchedule(scheduleName, schedule);
}

void
GroupManager::addMember(const std::string& scheduleName, const Data& memCert)
{
  IdentityCertificate cert(memCert);
  m_db.addMember(scheduleName, cert.getPublicKeyName(), cert.getPublicKeyInfo().get());
}

void
GroupManager::removeMember(const Name& identity)
{
  m_db.deleteMember(identity);
}

void
GroupManager::updateMemberSchedule(const Name& identity, const std::string& scheduleName)
{
  m_db.updateMemberSchedule(identity, scheduleName);
}

Interval
GroupManager::calculateInterval(const TimeStamp& timeslot, std::map<Name, Buffer>& memberKeys)
{
  // prepare
  Interval positiveResult;
  Interval negativeResult;
  Interval tempInterval;
  Interval finalInterval;
  bool isPositive;
  memberKeys.clear();

  // get the all intervals from schedules
  for (const std::string& scheduleName : m_db.listAllScheduleNames()) {

    const Schedule& schedule = m_db.getSchedule(scheduleName);
    std::tie(isPositive, tempInterval) = schedule.getCoveringInterval(timeslot);

    if (isPositive) {
      if (!positiveResult.isValid())
        positiveResult = tempInterval;
      positiveResult && tempInterval;

      std::map<Name, Buffer> m = m_db.getScheduleMembers(scheduleName);
      memberKeys.insert(m.begin(), m.end());
    }
    else {
      if (!negativeResult.isValid())
        negativeResult = tempInterval;
      negativeResult && tempInterval;
    }
  }
  if (!positiveResult.isValid()) {
    // return invalid interval when there is no member has interval covering the time slot
    return Interval(false);
  }

  // get the final interval result
  if (negativeResult.isValid())
    finalInterval = positiveResult && negativeResult;
  else
    finalInterval = positiveResult;

  return finalInterval;
}

void
GroupManager::generateKeyPairs(Buffer& priKeyBuf, Buffer& pubKeyBuf) const
{
  RandomNumberGenerator rng;
  RsaKeyParams params(m_paramLength);
  algo::EncryptParams eparams(tlv::AlgorithmRsaPkcs);
  DecryptKey<algo::Rsa> privateKey = algo::Rsa::generateKey(rng, params);
  priKeyBuf = privateKey.getKeyBits();
  EncryptKey<algo::Rsa> publicKey = algo::Rsa::deriveEncryptKey(priKeyBuf);
  pubKeyBuf = publicKey.getKeyBits();
}


Data
GroupManager::createEKeyData(const std::string& startTs, const std::string& endTs,
                             const Buffer& pubKeyBuf)
{
  Name dataName(m_namespace);
  dataName.append(E_KEY_COMPONENT).append(startTs).append(endTs);
  Data data(dataName);
  data.setFreshnessPeriod(time::hours(m_freshPeriod));
  data.setContent(pubKeyBuf.get(), pubKeyBuf.size());
  m_keyChain.sign(data);
  return data;
}

Data
GroupManager::createDKeyData(const std::string& startTs, const std::string& endTs,
                             const Name& keyName, const Buffer& priKeyBuf,
                             const Buffer& certKey)
{
  Name dataName(m_namespace);
  dataName.append(D_KEY_COMPONENT);
  dataName.append(startTs).append(endTs).append(keyName.getPrefix(-1));
  Data data = Data(dataName);
  data.setFreshnessPeriod(time::hours(m_freshPeriod));
  algo::EncryptParams eparams(tlv::AlgorithmRsaPkcs);
  algo::encryptData(data, priKeyBuf.buf(), priKeyBuf.size(), keyName,
                    certKey.buf(), certKey.size(), eparams);
  m_keyChain.sign(data);
  return data;
}

} // namespace ndn
} // namespace ndn
