#include <ndn-cpp-dev/face.hpp>
#include <ndn-cpp-dev/security/key-chain.hpp>
#include <ndn-cpp-dev/util/scheduler.hpp>

#include "nlsr.hpp"
#include "nlsr_test.hpp"

namespace nlsr
{

    using namespace std;
    using namespace ndn;

    void
    NlsrTest::schedlueAddingLsas(Nlsr& pnlsr)
    {
        // scheduling adding two name lsas, two Cor Lsas and three Adj LSAs

        //Scheduling Adding LSAs for router altair
        string router("/ndn/memphis.edu/cs/altair");
        string name1("/ndn/memphis.edu/cs/altair/name1");
        string name2("/ndn/memphis.edu/cs/altair/name2");
        string name3("/ndn/memphis.edu/cs/broadcast");
        Adjacent adj1("/ndn/memphis.edu/cs/pollux",7,17,1,0);
        Adjacent adj2("/ndn/memphis.edu/cs/maia",15,27,1,0);

        pnlsr.getScheduler().scheduleEvent(ndn::time::seconds(30),
                                           ndn::bind(&NlsrTest::secheduledAddNameLsa,pnlsr.getNlsrTesting(),
                                                   boost::ref(pnlsr)
                                                   ,router,name1,name2,name3));
        pnlsr.getScheduler().scheduleEvent(ndn::time::seconds(37),
                                           ndn::bind(&NlsrTest::secheduledAddCorLsa,pnlsr.getNlsrTesting(),
                                                   boost::ref(pnlsr)
                                                   ,router,123.098,1.875));
        pnlsr.getScheduler().scheduleEvent(ndn::time::seconds(47),
                                           ndn::bind(&NlsrTest::scheduledAddAdjacentLsa,pnlsr.getNlsrTesting(),
                                                   boost::ref(pnlsr)
                                                   ,router,adj1,adj2));

        //Scheduling Adding LSAs for router Maia
        string routerMaia("/ndn/memphis.edu/cs/maia");
        string maiaName1("/ndn/memphis.edu/maia/name1");
        string maiaName2("/ndn/memphis.edu/maia/name2");
        string maiaName3("/ndn/memphis.edu/cs/broadcast");
        Adjacent maiaAdj1("/ndn/memphis.edu/cs/pollux",8,25,1,0);
        Adjacent maiaAdj2("/ndn/memphis.edu/cs/altair",11,15,1,0);

        pnlsr.getScheduler().scheduleEvent(ndn::time::seconds(55),
                                           ndn::bind(&NlsrTest::secheduledAddNameLsa,pnlsr.getNlsrTesting(),
                                                   boost::ref(pnlsr)
                                                   ,routerMaia,maiaName1,maiaName2,maiaName3));
        pnlsr.getScheduler().scheduleEvent(ndn::time::seconds(65),
                                           ndn::bind(&NlsrTest::secheduledAddCorLsa,pnlsr.getNlsrTesting(),
                                                   boost::ref(pnlsr)
                                                   ,routerMaia,12.098,0.875));
        pnlsr.getScheduler().scheduleEvent(ndn::time::seconds(75),
                                           ndn::bind(&NlsrTest::scheduledAddAdjacentLsa,pnlsr.getNlsrTesting(),
                                                   boost::ref(pnlsr)
                                                   ,routerMaia,maiaAdj1,maiaAdj2));

        //sheduling Adding LSAs for Router itself
        string routerPollux("/ndn/memphis.edu/cs/pollux");
        Adjacent polluxAdj1("/ndn/memphis.edu/cs/maia",9,13,1,0);
        Adjacent polluxAdj2("/ndn/memphis.edu/cs/altair",12,23,1,0);

        pnlsr.getScheduler().scheduleEvent(ndn::time::seconds(90),
                                           ndn::bind(&NlsrTest::scheduledAddAdjacentLsa,pnlsr.getNlsrTesting(),
                                                   boost::ref(pnlsr)
                                                   ,routerPollux,polluxAdj1,polluxAdj2));


    }



    void
    NlsrTest::secheduledAddNameLsa(Nlsr& pnlsr, string router,
                                   string name1, string name2, string name3)
    {
        Npl npl;
        npl.insertIntoNpl(name1);
        npl.insertIntoNpl(name2);
        npl.insertIntoNpl(name3);
        NameLsa nameLsa(router,1,1,3600,npl);
        pnlsr.getLsdb().installNameLsa(pnlsr, nameLsa);

    }

    void
    NlsrTest::secheduledAddCorLsa(Nlsr& pnlsr,string router, double r, double angle)
    {
        CorLsa corLsa(router,3,1,3600,r,angle);
        pnlsr.getLsdb().installCorLsa(pnlsr, corLsa);
    }

    void
    NlsrTest::scheduledAddAdjacentLsa(Nlsr& pnlsr, string router,
                                      Adjacent adj1, Adjacent adj2)
    {
        Adl adl;
        adl.insert(adj1);
        adl.insert(adj2);
        AdjLsa adjLsa(router,2,1,3600,2,adl);
        pnlsr.getLsdb().installAdjLsa(pnlsr, adjLsa);

    }

}//namespace nlsr

