/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
 * Copyright (c) 2014-2015,  Regents of the University of California,
 *                           Arizona Board of Regents,
 *                           Colorado State University,
 *                           University Pierre & Marie Curie, Sorbonne University,
 *                           Washington University in St. Louis,
 *                           Beijing Institute of Technology,
 *                           The University of Memphis.
 *
 * This file is part of NFD (Named Data Networking Forwarding Daemon).
 * See AUTHORS.md for complete list of NFD authors and contributors.
 *
 * NFD 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 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, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "mgmt/face-manager.hpp"
#include "mgmt/internal-face.hpp"
#include "fw/forwarder.hpp"

#include "tests/test-common.hpp"

#include <boost/property_tree/info_parser.hpp>

namespace nfd {
namespace tests {

BOOST_FIXTURE_TEST_SUITE(MgmtFaceManager, BaseFixture)

BOOST_AUTO_TEST_SUITE(CreateFace)

class FaceManagerNode
{
public:
  FaceManagerNode(ndn::KeyChain& keyChain, const std::string& port = "6363")
    : face(make_shared<InternalFace>())
    , manager(forwarder.getFaceTable(), face, keyChain)
  {
    std::string basicConfig =
      "face_system\n"
      "{\n"
      "  tcp\n"
      "  {\n"
      "    port " + port + "\n"
      "  }\n"
      "  udp\n"
      "  {\n"
      "    port " + port + "\n"
      "  }\n"
      "}\n"
      "authorizations\n"
      "{\n"
      "  authorize\n"
      "  {\n"
      "    certfile any\n"
      "    privileges\n"
      "    {\n"
      "      faces\n"
      "    }\n"
      "  }\n"
      "}\n"
      "\n";
    std::istringstream input(basicConfig);
    nfd::ConfigSection configSection;
    boost::property_tree::read_info(input, configSection);

    ConfigFile config;
    manager.setConfigFile(config);
    face->getValidator().setConfigFile(config);
    config.parse(configSection, false, "dummy-config");
  }

  void
  closeFaces()
  {
    std::vector<shared_ptr<Face>> facesToClose;
    std::copy(forwarder.getFaceTable().begin(), forwarder.getFaceTable().end(),
              std::back_inserter(facesToClose));
    for (auto face : facesToClose) {
      face->close();
    }
  }

public:
  Forwarder forwarder;
  shared_ptr<InternalFace> face;
  FaceManager manager;
};

class FaceManagerFixture : public UnitTestTimeFixture
{
public:
  FaceManagerFixture()
    : node1(keyChain, "16363")
    , node2(keyChain, "26363")
  {
  }

  ~FaceManagerFixture()
  {
    node1.closeFaces();
    node2.closeFaces();
    advanceClocks(time::milliseconds(1), 100);
  }

public:
  ndn::KeyChain keyChain;
  FaceManagerNode node1; // used to test FaceManager
  FaceManagerNode node2; // acts as a remote endpoint
};

class TcpFaceOnDemand
{
public:
  ControlParameters
  getParameters()
  {
    return ControlParameters()
      .setUri("tcp4://127.0.0.1:26363")
      .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
  }
};

class TcpFacePersistent
{
public:
  ControlParameters
  getParameters()
  {
    return ControlParameters()
      .setUri("tcp4://127.0.0.1:26363")
      .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
  }
};

class TcpFacePermanent
{
public:
  ControlParameters
  getParameters()
  {
    return ControlParameters()
      .setUri("tcp4://127.0.0.1:26363")
      .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
  }
};

class UdpFaceOnDemand
{
public:
  ControlParameters
  getParameters()
  {
    return ControlParameters()
      .setUri("udp4://127.0.0.1:26363")
      .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
  }
};

class UdpFacePersistent
{
public:
  ControlParameters
  getParameters()
  {
    return ControlParameters()
      .setUri("udp4://127.0.0.1:26363")
      .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
  }
};

class UdpFacePermanent
{
public:
  ControlParameters
  getParameters()
  {
    return ControlParameters()
      .setUri("udp4://127.0.0.1:26363")
      .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
  }
};

class Success
{
public:
  ControlResponse
  getExpected()
  {
    return ControlResponse()
      .setCode(200)
      .setText("Success");
  }
};

template<int CODE>
class Failure
{
public:
  ControlResponse
  getExpected()
  {
    return ControlResponse()
      .setCode(CODE)
      .setText("Error"); // error description should not be checked
  }
};

namespace mpl = boost::mpl;

// pairs of CreateCommand and Success status
typedef mpl::vector<mpl::pair<TcpFaceOnDemand, Failure<500>>,
                    mpl::pair<TcpFacePersistent, Success>,
                    mpl::pair<TcpFacePermanent, Failure<500>>,
                    mpl::pair<UdpFaceOnDemand, Failure<500>>,
                    mpl::pair<UdpFacePersistent, Success>,
                    mpl::pair<UdpFacePermanent, Success>> Faces;

BOOST_FIXTURE_TEST_CASE_TEMPLATE(NewFace, T, Faces, FaceManagerFixture)
{
  typedef typename T::first FaceType;
  typedef typename T::second CreateResult;

  Name commandName("/localhost/nfd/faces");
  commandName.append("create");
  commandName.append(FaceType().getParameters().wireEncode());

  shared_ptr<Interest> command(make_shared<Interest>(commandName));
  this->keyChain.sign(*command);

  bool hasCallbackFired = false;
  this->node1.face->onReceiveData.connect([this, command, &hasCallbackFired] (const Data& response) {
      if (!command->getName().isPrefixOf(response.getName())) {
        return;
      }

      ControlResponse actual(response.getContent().blockFromValue());
      ControlResponse expected(CreateResult().getExpected());
      BOOST_CHECK_EQUAL(expected.getCode(), actual.getCode());
      BOOST_MESSAGE(actual.getText());

      if (actual.getBody().hasWire()) {
        ControlParameters expectedParams(FaceType().getParameters());
        ControlParameters actualParams(actual.getBody());

        BOOST_CHECK_EQUAL(expectedParams.getUri(), actualParams.getUri());
        BOOST_CHECK_EQUAL(expectedParams.getFacePersistency(), actualParams.getFacePersistency());
      }
      hasCallbackFired = true;
    });

  this->node1.face->sendInterest(*command);
  this->advanceClocks(time::milliseconds(1), 10);

  BOOST_CHECK(hasCallbackFired);
}


typedef mpl::vector<// mpl::pair<mpl::pair<TcpFacePersistent, TcpFacePermanent>, TcpFacePermanent>, // no need to check now
                    // mpl::pair<mpl::pair<TcpFacePermanent, TcpFacePersistent>, TcpFacePermanent>, // no need to check now
                    mpl::pair<mpl::pair<UdpFacePersistent, UdpFacePermanent>, UdpFacePermanent>,
                    mpl::pair<mpl::pair<UdpFacePermanent, UdpFacePersistent>, UdpFacePermanent>> FaceTransitions;


BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExistingFace, T, FaceTransitions, FaceManagerFixture)
{
  typedef typename T::first::first FaceType1;
  typedef typename T::first::second FaceType2;
  typedef typename T::second FinalFaceType;

  {
    // create face

    Name commandName("/localhost/nfd/faces");
    commandName.append("create");
    commandName.append(FaceType1().getParameters().wireEncode());

    shared_ptr<Interest> command(make_shared<Interest>(commandName));
    this->keyChain.sign(*command);

    this->node1.face->sendInterest(*command);
    this->advanceClocks(time::milliseconds(1), 10);
  }

  //
  {
    // re-create face (= change face persistency)

    Name commandName("/localhost/nfd/faces");
    commandName.append("create");
    commandName.append(FaceType2().getParameters().wireEncode());

    shared_ptr<Interest> command(make_shared<Interest>(commandName));
    this->keyChain.sign(*command);

    bool hasCallbackFired = false;
    this->node1.face->onReceiveData.connect([this, command, &hasCallbackFired] (const Data& response) {
        if (!command->getName().isPrefixOf(response.getName())) {
          return;
        }

        ControlResponse actual(response.getContent().blockFromValue());
        BOOST_REQUIRE_EQUAL(actual.getCode(), 200);

        ControlParameters expectedParams(FinalFaceType().getParameters());
        ControlParameters actualParams(actual.getBody());
        BOOST_CHECK_EQUAL(expectedParams.getFacePersistency(), actualParams.getFacePersistency());

        hasCallbackFired = true;
      });

    this->node1.face->sendInterest(*command);
    this->advanceClocks(time::milliseconds(1), 10);

    BOOST_CHECK(hasCallbackFired);
  }
}


// class TcpFace
// {
// public:
//   ControlParameters
//   getParameters()
//   {
//     return ControlParameters()
//       .setUri("tcp4://127.0.0.1:16363")
//       .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
//   }
// };

class UdpFace
{
public:
  ControlParameters
  getParameters()
  {
    return ControlParameters()
      .setUri("udp4://127.0.0.1:16363")
      .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
  }
};


// Note that the transitions from on-demand TcpFace are intentionally not tested.
// On-demand TcpFace has a remote endpoint with a randomized port number.  Normal face
// creation operations will not need to create a face toward a remote port not listened by
// a channel.

typedef mpl::vector<mpl::pair<UdpFace, UdpFacePersistent>,
                    mpl::pair<UdpFace, UdpFacePermanent>> OnDemandFaceTransitions;

// need a slightly different logic to test transitions from OnDemand state
BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExistingFaceOnDemand, T, OnDemandFaceTransitions, FaceManagerFixture)
{
  typedef typename T::first  OtherNodeFace;
  typedef typename T::second FaceType;

  {
    // create on-demand face

    Name commandName("/localhost/nfd/faces");
    commandName.append("create");
    commandName.append(OtherNodeFace().getParameters().wireEncode());

    shared_ptr<Interest> command(make_shared<Interest>(commandName));
    this->keyChain.sign(*command);

    ndn::util::signal::ScopedConnection connection =
      this->node2.face->onReceiveData.connect([this, command] (const Data& response) {
          if (!command->getName().isPrefixOf(response.getName())) {
            return;
          }

          ControlResponse controlResponse(response.getContent().blockFromValue());
          BOOST_REQUIRE_EQUAL(controlResponse.getText(), "Success");
          BOOST_REQUIRE_EQUAL(controlResponse.getCode(), 200);
          uint64_t faceId = ControlParameters(controlResponse.getBody()).getFaceId();
          auto face = this->node2.forwarder.getFace(static_cast<FaceId>(faceId));

          // to force creation of on-demand face
          auto dummyInterest = make_shared<Interest>("/hello/world");
          face->sendInterest(*dummyInterest);
        });

    this->node2.face->sendInterest(*command);
    this->advanceClocks(time::milliseconds(1), 10);
  }

  // make sure there is on-demand face
  bool onDemandFaceFound = false;
  FaceUri onDemandFaceUri(FaceType().getParameters().getUri());
  for (auto face : this->node1.forwarder.getFaceTable()) {
    if (face->getRemoteUri() == onDemandFaceUri) {
      onDemandFaceFound = true;
      break;
    }
  }
  BOOST_REQUIRE(onDemandFaceFound);

  //
  {
    // re-create face (= change face persistency)

    Name commandName("/localhost/nfd/faces");
    commandName.append("create");
    commandName.append(FaceType().getParameters().wireEncode());

    shared_ptr<Interest> command(make_shared<Interest>(commandName));
    this->keyChain.sign(*command);

    bool hasCallbackFired = false;
    this->node1.face->onReceiveData.connect([this, command, &hasCallbackFired] (const Data& response) {
        if (!command->getName().isPrefixOf(response.getName())) {
          return;
        }

        ControlResponse actual(response.getContent().blockFromValue());
        BOOST_REQUIRE_EQUAL(actual.getCode(), 200);

        ControlParameters expectedParams(FaceType().getParameters());
        ControlParameters actualParams(actual.getBody());
        BOOST_CHECK_EQUAL(expectedParams.getFacePersistency(), actualParams.getFacePersistency());

        hasCallbackFired = true;
      });

    this->node1.face->sendInterest(*command);
    this->advanceClocks(time::milliseconds(1), 10);

    BOOST_CHECK(hasCallbackFired);
  }
}

BOOST_AUTO_TEST_SUITE_END() // CreateFace

BOOST_AUTO_TEST_SUITE_END() // MgmtFaceManager

} // tests
} // nfd
