// ndn-grid-topo-plugin.cpp

#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/ndnSIM-module.h"

#include <iostream>
#include <ctime>

namespace ns3 {

int
main(int argc, char* argv[])
{
  CommandLine cmd;
  cmd.Parse(argc, argv);

  AnnotatedTopologyReader topologyReader("", 1);
  topologyReader.SetFileName("src/ndnSIM/examples/topologies/topo-line.txt");
  topologyReader.Read();

  Ptr<Node> producer = Names::Find<Node>("0");
  NodeContainer consumerNodes1;
  NodeContainer consumerNodes2;
  NodeContainer consumerNodes3;
  NodeContainer producerNodes;
  NodeContainer routerNodes;


  consumerNodes1.Add(Names::Find<Node>("5"));
  
  consumerNodes2.Add(Names::Find<Node>("6"));

  consumerNodes3.Add(Names::Find<Node>("7"));

  producerNodes.Add(Names::Find<Node>("0"));

  routerNodes.Add(Names::Find<Node>("1"));
  routerNodes.Add(Names::Find<Node>("2"));
  routerNodes.Add(Names::Find<Node>("3"));
  routerNodes.Add(Names::Find<Node>("4"));

  // NodeContainer consumerNodes;
  // consumerNodes.Add(Names::Find<Node>("5"));
  // consumerNodes.Add(Names::Find<Node>("6"));
  // consumerNodes.Add(Names::Find<Node>("7"));


  // Install NDN stack on all nodes
  ndn::StackHelper ndnHelper1;
  ndnHelper1.SetOldContentStore("ns3::ndn::cs::Nocache");
  // ndnHelper.SetOldContentStore("ns3::ndn::cs::Probability::Lru", "MaxSize", "450", "CacheProbability", "0.7");
  ndnHelper1.InstallAll();
  // ndnHelper1.Install(consumerNodes1);
  // ndnHelper1.Install(consumerNodes2);
  // ndnHelper1.Install(consumerNodes3);

  // ndn::StackHelper ndnHelper2;
  // //ndnHelper2.SetOldContentStore("ns3::ndn::cs::Lru", "MaxSize", "150");
  // ndnHelper2.SetOldContentStore("ns3::ndn::cs::Nocache");
  // ndnHelper2.Install(producerNodes);
  // ndnHelper2.Install(routerNodes);


  // Set BestRoute strategy
  ndn::StrategyChoiceHelper::InstallAll("/", "/localhost/nfd/strategy/best-route");
 

  // Installing global routing interface on all nodes
  ndn::GlobalRoutingHelper ndnGlobalRoutingHelper;
  ndnGlobalRoutingHelper.InstallAll();

  std::string prefix1 = "/A1";  //1EF //LD
  std::string prefix2 = "/A2";  //2AF //BE
  std::string prefix3 = "/A3";  //3BE //NC

  // Install NDN applications
  ndn::AppHelper consumerHelper1("ns3::ndn::ConsumerZipfMandelbrot");
  consumerHelper1.SetPrefix(prefix1);
  consumerHelper1.SetAttribute("Frequency", StringValue("100")); // 100 interests a second
  consumerHelper1.SetAttribute("NumberOfContents", StringValue("5000"));
  consumerHelper1.Install(consumerNodes1);

  ndn::AppHelper consumerHelper2("ns3::ndn::ConsumerZipfMandelbrot");
  consumerHelper2.SetPrefix(prefix2);
  consumerHelper2.SetAttribute("Frequency", StringValue("100")); // 100 interests a second
  consumerHelper2.SetAttribute("NumberOfContents", StringValue("5000"));
  consumerHelper2.Install(consumerNodes2);

  ndn::AppHelper consumerHelper3("ns3::ndn::ConsumerZipfMandelbrot");
  consumerHelper3.SetPrefix(prefix3);
  consumerHelper3.SetAttribute("Frequency", StringValue("100")); // 10 interests a second
  consumerHelper3.SetAttribute("NumberOfContents", StringValue("5000"));
  consumerHelper3.Install(consumerNodes3);


  // ndn::AppHelper consumerHelper("ns3::ndn::ConsumerZipfMandelbrot");
  // consumerHelper.SetPrefix(prefix1);
  // consumerHelper.SetAttribute("Frequency", StringValue("100")); // 100 interests a second
  // consumerHelper.SetAttribute("NumberOfContents", StringValue("5000"));
  // consumerHelper.Install(consumerNodes);


  ndn::AppHelper producerHelper("ns3::ndn::Producer");
  producerHelper.SetAttribute("PayloadSize", StringValue("1024"));
  producerHelper.Install(producer);

  // Add /prefix origins to ndn::GlobalRouter
  ndnGlobalRoutingHelper.AddOrigins("/", producer);

  // Calculate and install FIBs
  ndn::GlobalRoutingHelper::CalculateRoutes();

  ndn::CsTracer::InstallAll("cs-trace.txt", Seconds(1));
  ndn::AppDelayTracer::InstallAll("app-delays-trace.txt");
  ndn::L3RateTracer::InstallAll("rate-trace.txt", Seconds(1.0));
  //L2RateTracer::InstallAll("drop-trace.txt", Seconds(0.5));

  Simulator::Stop(Seconds(60.0));

  Simulator::Run();
  Simulator::Destroy();

  return 0;
}

} // namespace ns3

int
main(int argc, char* argv[])
{
  //time_t start = time(0);
  //cout << "start time: " << start << endl;
  int ret = ns3::main(argc, argv);
  //time_t end = time(0);
  //cout << "end time: " << end << endl;
  return ret;
}