#include "AE.h"
#include "discoveryMessage_m.h"
#include "utils.h"
#include "types.h"

AE::AE()
{
    // Set the pointer to nullptr, so that the destructor won't crash
    // even if initialize() doesn't get called because of a runtime
    // error or user cancellation during the startup process.
//    canMsg = regMsg = queryMsg = nullptr;
}

AE::~AE()
{
    // Dispose of dynamically allocated the objects
//    delete canMsg;
//    delete regMsg;
//    delete queryMsg;
}


int AE::numInitStages() const {
    return 2;
}


void AE::initialize(int stage) {

    numOfFound = 0;
    canMsg = regMsg = queryMsg = nullptr;
    switch (stage) {
    case InitStage::INIT_REGISTRATION:
        registration();
        break;

    case InitStage::INIT_QUERY:
        sendQuery();
        break;
    default:
        EV_FATAL << "Unknown initialization phase!\n";
        break;

    }
} // end of initialize



void AE::registration() {
//    this->queryIndex = 0;
    // get the id of the AE
    URI = getId(); // this is the omnet id which is given when creating the module in the NED file (sequential numbering)
    // assigning randomly the data and feature type
    data = uniform(0, 100);
    int ran_number = std::rand() % 100;
    EV << "Random Number" << ran_number << "\n";

    for (auto it : resourceFrequency) {
        auto ft = it.first;
        auto range = it.second;
        if (ran_number >= range.first && ran_number < range.second) {
            feature_type = ft;
            break;
        }
    }

    EV << "AE with Id number " << URI << " is " << feature_type << endl;
    // send an AE message with op_code Registration
        sendAEMessage(REGISTRATION);

}

void AE::sendQuery() {
    // getIndex is an omnet function that select in  a vector of AE (in this case ) the index in the vector table.
    if (getIndex() == 10) {
        // send the AE message with op_code QUERY
        EV << "AE of URI 28 is Searching for waterValve" << "\n";
        sendAEMessage(QUERY);
    }
}



void AE::sendAEMessage(int op_code) {
    // this function we set the fields of an AEMessage with respect to op_code
    switch (op_code) {
    case CANCELLATION: {
        canMsg = new AEMessage("C");
        // set the message fields
        canMsg->setURI(URI);
        canMsg->setData(data);
        canMsg->setOp_code(CANCELLATION);
        canMsg->setFeature_type(feature_type.c_str());
        sendDelayed(canMsg, simTime() + 5, "cse$o");
        break;
    }

    case REGISTRATION: {
        regMsg = new AEMessage("Reg");
        // set the message fields
        regMsg->setURI(URI);
        regMsg->setFeature_type(feature_type.c_str());
//        regMsg->setFeature_type("waterValve");
        regMsg->setData(data);
        regMsg->setOp_code(REGISTRATION);
        send(regMsg, "cse$o");
        break;


    }
    case QUERY: {
        queryMsg = new AEMessage("Q");
        queryMsg->setURI(URI);
//        queryMsg->setQueryID(queryIndex++);
        queryMsg->setFeature_type("waterValve");
        queryMsg->setOp_code(QUERY);
        sendDelayed(queryMsg, simTime() + 2, "cse$o");
        break;
    }

    default:
        break;
    }
}

void AE::handleMessage(cMessage *msg) {

        //AE will receive the response
        //AEMessage *responseMsg = check_and_cast<AEMessage *>(msg);
        discoveryMessage *responseMsg = check_and_cast<discoveryMessage*>(msg);
        EV << "AE receives a response" << "\n";

        if (responseMsg->getReturnCode() == ResultCode::SUCCESS) {
//        NumOfReplies++;
        numOfFound++;
        EV << "Resource of type " << responseMsg->getFeature_type()
                  << " found in URI " << responseMsg->getURI_init() << "\n";

        }

        if (responseMsg->getReturnCode() == ResultCode::NOT_FOUND) {

            EV << "Resource of type " << responseMsg->getFeature_type()
                  << " not found in URI " << responseMsg->getURI_init() << "\n";
        }
//    EV << "Number of Resource of type found: " << NumOfReplies << "\n";

        delete responseMsg;
}



void AE::finish()
{
    if(getIndex()==10){
        EV << "The number of requested Resources are found is: " << numOfFound << endl;
    }
}
