#ifndef CSE_H_
#define CSE_H_

#include <stdio.h>
#include <string.h>
#include <omnetpp.h>
#include "discoveryMessage_m.h"
#include "AEMessage_m.h"
#include "pingMessage_m.h"
#include <list>
#include "utils.h"
#include "types.h"



#define EXPIRATION_TIME  300

using namespace omnetpp;

//using namespace std;



class CSE: public cSimpleModule {
public:
    RoutingTable SemanticRoutingTable;

protected:
    // by default in omnet methods
    virtual void initialize() override;
    virtual void handleMessage(cMessage *msg) override;
    // application specific  method
    virtual discoveryMessage* generateMessage(int op_code);
private:

    bool seenQuery(discoveryMessage *msg);

    // application specific for exploring and updating  the local database
    URI DBLookup(discoveryMessage *msg);
    void updateDatabase(AEMessage *msg, int op_code);
    // this method forward the initial query to CSEs
    // MAPchg void parseRouting(AEMessage *msg);
    void generateDiscoveryMessage(AEMessage *msg);
    void generateResponseMessage(discoveryMessage *discoveryMsg, ResultCode result = ResultCode::SUCCESS);
    // not yet used
    // TODO this function organize the map by value-ordering
    void orderingMap(std::map<int, int>);

    // Routing table update
    RoutingEntry getOrCreateRoutingEntry(std::string feature_type);
    RoutingEntry mustGetRoutingEntry(std::string feature_type);
    void registerAE(std::string feature_type, URI uri);
    void deregisterAE(std::string feature_type, URI uri);

    void notifyCSE(std::string feature_type, int delta);
    void notifyNeighbors(discoveryMessage *msg);
    bool multicast(std::string gateName, discoveryMessage *msg, int maxMessages = INT_MAX);
    void broadcast(std::string gateName, discoveryMessage *msg);

    // Save AE data

    void saveAEData(std::string feature_type, URI uri, int data);

    //Messages handling
    void handleAEMessage(cMessage *msg);
    void handleAERegistration(AEMessage *msg);
    void handleAEQuery(AEMessage *msg);
    void handleAECancellation(AEMessage *msg);

    void handleDiscoveryMessage(cMessage *msg);
    void handleNotify(discoveryMessage *msg);

    void handleQuery(discoveryMessage *msg);
    void fallbackRouteQuery(discoveryMessage *msg);

    void processQuery(discoveryMessage *msg);

    void returnResponse(discoveryMessage * msg);

    std::vector<URI> routeQuery(discoveryMessage *msg);
    std::vector<URI> UpdateBucket(discoveryMessage*msg);


    /*     WE ARE IN THE NOTIFY SWITCH CASE
     before orderingMap
     <(1,30),(2,40),(5,33),(6,12)>
     call orderingMap
     <(2,40),(5,33),(1,30),(6,12)>
     notify +5 1
     <(2,40),(5,33),(1,35),(6,12)>
     call orderingMap
     <(2,40),(1,35),(5,33),(6,12)>
     notify +22 6
     <(2,40),(5,33),(1,35),(6,34)>
     call orderingMap (will take log(n)
     <(6,34),(2,40),(5,33),(1,35)>*/

/// DATA structures definitions
    // this is the omnet++ ledger
    // that collect some data useful for measuring experiments
    // and is also useful for replying the query.
    // this is composed as follow
    // <URI ,<gateIndex,simTime,direction>>
    std::map<URI, std::tuple<int, simtime_t, int>> schedulerMap;


    std::map<std::string,std::map<URI,int>> database;

    GateMapping Gates;

    URI Uri;

    // How many times to retransmit `Notify`
    int NotificationDepth;

    // Alpha - is the multicast parameter for customer;
    int multicastAlpha;
    // Beta - is the multicast parameter for provider
    int multicastBeta;
    //Gamma - is the multicast parameter for sibling
    int multicastGamma;
    //Delta - is the multicast parameter for peer
    int multicastDelta;

    // Max hops for message/query
    int maxHops;

    simtime_t queryBufferTTL;

    std::map<queryKey, int64_t> processedQueries;

    int number_of_packets;
    int number_of_hops;
    simtime_t delay;
    int number_of_messages;
    int success;
protected:
    simsignal_t totalpacketsSignal;
    simsignal_t latency;
    simsignal_t flood;
    simsignal_t success_rate;




};
Define_Module(CSE);

#endif /* CSE_H_ */




