/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
 * Copyright (c) 2013-2017, Regents of the University of California,
 *
 * This file is part of NFD Control Center.  See AUTHORS.md for complete list of NFD
 * authors and contributors.
 *
 * NFD Control Center 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.
 *
 * NFD Control Center 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 NFD
 * Control Center, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "fib-status.hpp"
#include "fib-status.moc"

#include <ndn-cxx/face.hpp>
#include <ndn-cxx/name.hpp>
#include <ndn-cxx/interest.hpp>
#include <ndn-cxx/encoding/buffer-stream.hpp>
#include <ndn-cxx/management/nfd-fib-entry.hpp>
#include <ndn-cxx/management/nfd-face-status.hpp>
#include <ndn-cxx/management/nfd-forwarder-status.hpp>

namespace ndn {

FibStatusModel::FibStatusModel(Face& face, QObject *parent/* = 0*/)
  : QAbstractListModel(parent)
  // , m_face(face)
{
}

int
FibStatusModel::rowCount(const QModelIndex &parent/* = QModelIndex()*/) const
{
  return m_items.count();
}

void
FibStatusModel::addItem(const FibStatusItem &item)
{
  beginInsertRows(QModelIndex(), rowCount(), rowCount());
  m_items << item;
  endInsertRows();
}

QVariant
FibStatusModel::data(const QModelIndex & index, int role) const
{
  if (index.row() < 0 || index.row() >= m_items.count()) {
    return QVariant();
  }

  const FibStatusItem &item = m_items.at(index.row());
  if (role == PrefixRole) {
    return item.prefix();
  } else if (role == FaceIdRole) {
    return static_cast<uint>(item.faceId());
  } else if (role == CostRole) {
    return static_cast<uint>(item.cost());
  }

  return QVariant();
}

QHash<int, QByteArray>
FibStatusModel::roleNames() const
{
  QHash<int, QByteArray> roles;
  roles[PrefixRole] = "prefix";
  roles[FaceIdRole] = "faceId";
  roles[CostRole] = "cost";
  return roles;
}

void
FibStatusModel::clear()
{
  beginResetModel();
  m_items.clear();
  endResetModel();
}

Q_INVOKABLE void
FibStatusModel::fetchFibInformation()
{
  // m_buffer = make_shared<OBufferStream>();

  // Interest interest("/localhost/nfd/fib/list");
  // interest.setChildSelector(1);
  // interest.setMustBeFresh(true);
  // m_face.expressInterest(interest,
  //                        bind(&FibStatusModel::fetchSegments, this, _2,
  //                             &FibStatusModel::afterFetchedFibEnumerationInformation),
  //                        bind(&FibStatusModel::onTimeout, this));
  // try {
  //   m_face.processEvents();
  // } catch (Tlv::Error e) {
  //   std::cerr << e.what() << std::endl;
  //   clear();
  // }
}

void
FibStatusModel::afterFetchedFibEnumerationInformation()
{
//   beginResetModel();
//   m_items.clear();
//   ConstBufferPtr buf = m_buffer->buf();

//   Block block;
//   size_t offset = 0;
//   while (offset < buf->size()) {
//     bool ok = Block::fromBuffer(buf, offset, block);
//     if (!ok) {
//       std::cerr << "ERROR: cannot decode FibEntry TLV" << std::endl;
//       break;
//     }
//     offset += block.size();

//     nfd::FibEntry fibEntry(block);

//     for (std::list<nfd::NextHopRecord>::const_iterator
//            nextHop = fibEntry.getNextHopRecords().begin();
//          nextHop != fibEntry.getNextHopRecords().end();
//          ++nextHop) {
//       addItem(FibStatusItem(QString::fromStdString(fibEntry.getPrefix().toUri()),
//                             nextHop->getFaceId(), nextHop->getCost()));
//     }
//   }
//   endResetModel();
}


void
FibStatusModel::fetchSegments(const Data& data, void (FibStatusModel::*onDone)())
{
  // m_buffer->write(reinterpret_cast<const char*>(data.getContent().value()),
  //                 data.getContent().value_size());

  // uint64_t currentSegment = data.getName().get(-1).toSegment();

  // const name::Component& finalBlockId = data.getMetaInfo().getFinalBlockId();
  // if (finalBlockId.empty() ||
  //     finalBlockId.toSegment() > currentSegment) {
  //   m_face.expressInterest(data.getName().getPrefix(-1).appendSegment(currentSegment+1),
  //                          bind(&FibStatusModel::fetchSegments, this, _2, onDone),
  //                          bind(&FibStatusModel::onTimeout, this));
  // } else {
  //   return (this->*onDone)();
  // }
}

void
FibStatusModel::onTimeout()
{
  std::cerr << "Request timed out" << std::endl;
}

} // namespace ndn
