 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation;
  *
  * This program 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 this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */

#include <fstream>
#include "ns3/core-module.h"
#include "ns3/internet-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-apps-module.h"
#include "ns3/ipv6-static-routing-helper.h"

#include "ns3/ipv6-routing-table-entry.h"
#include "ns3/mobility-module.h"
#include "ns3/netanim-module.h"
#include "ns3/constant-position-mobility-model.h"

using namespace ns3;

NS_LOG_COMPONENT_DEFINE ("Icmpv6");


void printIpAddresses (Ptr<Node>& n)
{
Ptr<Ipv6> ipv6 = n->GetObject<Ipv6> ();
uint32_t nInterfaces = ipv6->GetNInterfaces();

std::cout << "Node: " << ipv6->GetObject<Node> ()->GetId ()
	<< " Time: " << Simulator::Now ().GetSeconds () << "s "
	<< "IPv6 addresses" << std::endl;
std::cout << "(Interface index, Address index)\t" << "IPv6 Address" << std::endl;

for (uint32_t i = 0; i < nInterfaces; i++)
  {
	for (uint32_t j = 0; j < ipv6->GetNAddresses(i); j++)
	  {
		std::cout << "(" << int(i) << "," << int(j) << ")\t" << ipv6->GetAddress(i,j) << std::endl;
	  }
  }
std::cout << std::endl;
}

int main (int argc, char **argv)
{
  Ptr<Node> host0 = CreateObject<Node> ();
  Ptr<Node> router0 = CreateObject<Node> ();
  Ptr<Node> router1 = CreateObject<Node> ();
  Ptr<Node> host1 = CreateObject<Node> ();
  NodeContainer net1 (host0, router0, router1);
  NodeContainer net2 (router1, host1);
  NodeContainer all (host0, router0, router1, host1);

  CsmaHelper csma;
  csma.SetChannelAttribute ("DataRate", DataRateValue (5000000));
  csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2)));

  NetDeviceContainer netDevices_net1 = csma.Install (net1);
  NetDeviceContainer netDevices_net2 = csma.Install (net2);

  InternetStackHelper internetv6;
  internetv6.SetIpv4StackInstall (false);
  internetv6.Install (all);

  //Samostatna cast A - DAD pro stejnou MAC adresu

  //Samostatna cast B - Metoda EUI-64

  /*
   * 	Definovani konfigurace adries
   */
  Ipv6AddressHelper ipv6;
  Ipv6Address net1_address = Ipv6Address ("2001:1::");
  Ipv6Address net2_address = Ipv6Address ("2002:1::");

  /*
   * 	Staticka konfigurace adres pro smerovac router1
   */
  ipv6.SetBase (net1_address, Ipv6Prefix (64));
  NetDeviceContainer device_router1_net1;
  device_router1_net1.Add(netDevices_net1.Get(2));
  Ipv6InterfaceContainer interface_router1_net1 = ipv6.Assign(device_router1_net1);
  interface_router1_net1.SetForwarding(0, true);

  ipv6.SetBase (net2_address, Ipv6Prefix (64));
  NetDeviceContainer device_router1_net2;
  device_router1_net2.Add(netDevices_net2.Get(0));
  Ipv6InterfaceContainer interface_router1_net2 = ipv6.Assign(device_router1_net2);
  interface_router1_net2.SetForwarding(0, true);

  /*
   * 	Vytvoreni rozhrani pro uzly host0, router0 a host1 bez konfigurace globalnych adres
   */
  NetDeviceContainer device_host0;
  device_host0.Add(netDevices_net1.Get(0));
  Ipv6InterfaceContainer interface_host0 = ipv6.AssignWithoutAddress(device_host0);

  NetDeviceContainer device_router0;
  device_router0.Add(netDevices_net1.Get(1));
  Ipv6InterfaceContainer interface_router0 = ipv6.AssignWithoutAddress(device_router0);

  NetDeviceContainer device_host1;
  device_host1.Add(netDevices_net2.Get(1));
  Ipv6InterfaceContainer interface_host1 = ipv6.AssignWithoutAddress(device_host1);

  /*
   * 	Bezstavova konfigurace adres
   */
  RadvdHelper radvdHelper;
  radvdHelper.AddAnnouncedPrefix(interface_router1_net1.GetInterfaceIndex(0), net1_address, 64);
  radvdHelper.AddAnnouncedPrefix(interface_router1_net2.GetInterfaceIndex(0), net2_address, 64);

  radvdHelper.GetRadvdInterface (interface_router1_net1.GetInterfaceIndex(0))->SetSendAdvert (false);

  //Samostatna cast C - RA s vice prefixy:

  ApplicationContainer radvdApps = radvdHelper.Install (router1);
  radvdApps.Start (Seconds (1.0));
  radvdApps.Stop (Seconds (10.0));

  /*
   * 	Vystupy
   */
  csma.EnablePcapAll ("icmpv6");

  Simulator::Schedule (Seconds (0.0), &printIpAddresses, host0);
  Simulator::Schedule (Seconds (0.0), &printIpAddresses, router0);
  Simulator::Schedule (Seconds (0.0), &printIpAddresses, router1);
  Simulator::Schedule (Seconds (0.0), &printIpAddresses, host1);

  Simulator::Schedule (Seconds (2.0), &printIpAddresses, host0);
  Simulator::Schedule (Seconds (2.0), &printIpAddresses, router0);
  Simulator::Schedule (Seconds (2.0), &printIpAddresses, router1);
  Simulator::Schedule (Seconds (2.0), &printIpAddresses, host1);

  NS_LOG_INFO ("Run Simulation.");
  Simulator::Stop(Seconds (30));
  Simulator::Run ();
  Simulator::Destroy ();
  NS_LOG_INFO ("Done.");
}

