
#include <learn/Inter__learn__rendezVous.hpp>
#include <learn/ConnT__learn__rendezVous.hpp>

const bitset<3> Inter__learn__rendezVous::predefined(string("111"));

Inter__learn__rendezVous::Inter__learn__rendezVous(const ConnT__learn__rendezVous &connector) : Interaction(connector) {
    involvedPorts.reset();
    port_vector_fresh = true;
    defined = false;
    refresh_defined = false;
    mPorts.reserve(3);
}

Inter__learn__rendezVous::Inter__learn__rendezVous(const ConnT__learn__rendezVous &connector, bool p1, bool p2, bool p3) : Interaction(connector) {
    involvedPorts.reset();

    defined = true;
    refresh_defined = false;
	port_vector_fresh = false;

    involvedPorts.set(0, p1);
    involvedPorts.set(1, p2);
    involvedPorts.set(2, p3);

    defined = p1 && p2 && p3;
    mPorts.reserve(3);
}

Inter__learn__rendezVous::Inter__learn__rendezVous(const ConnT__learn__rendezVous &connector, const vector<Port *> &ports) : Interaction(connector), port_vector_fresh(false) {
    commonRecycle(ports);
    mPorts.reserve(3);
}

Inter__learn__rendezVous::~Inter__learn__rendezVous(){
}

// This one is 'const' but its only role
// is to set mPorts correctly (ie. its only role is to modify the object)
void Inter__learn__rendezVous::refreshPorts() const {
    const vector<QuotedPortReference *> &parent_ports = this->connector().ports();
    mPorts.clear();
    mPorts.reserve(3);

    if (involvedPorts.test(0)) {
         mPorts.push_back(&(parent_ports[0]->port()));
    }
    if (involvedPorts.test(1)) {
         mPorts.push_back(&(parent_ports[1]->port()));
    }
    if (involvedPorts.test(2)) {
         mPorts.push_back(&(parent_ports[2]->port()));
    }
    port_vector_fresh = true;
}

vector<Port*>& Inter__learn__rendezVous::ports() {
    if (!port_vector_fresh){
        refreshPorts();
    }

    return mPorts;
}

const vector<Port *> & Inter__learn__rendezVous::ports() const {
    if (!port_vector_fresh){
        refreshPorts();
    }

    return mPorts;
}

bool Inter__learn__rendezVous::operator==(const Interaction &interaction) const {
    bool ret = false;

    // check if interaction values are from the same connector
    if (&connector() == &interaction.connector()) {
        assert(dynamic_cast<const Inter__learn__rendezVous *>(&interaction) != NULL);
        const Inter__learn__rendezVous *other = static_cast<const Inter__learn__rendezVous *>(&interaction);
        ret = (involvedPorts == other->involvedPorts);
    }
    return ret;
}

bool Inter__learn__rendezVous::operator<=(const Interaction &interaction) const {
    bool ret = false;

    // check if interaction values are from the same connector
    if (&connector() == &interaction.connector()) {
        assert(dynamic_cast<const Inter__learn__rendezVous *>(&interaction) != NULL);
        const Inter__learn__rendezVous *other = static_cast<const Inter__learn__rendezVous *>(&interaction);
        ret = ((involvedPorts & other->involvedPorts) == involvedPorts);
    }

    return ret;
}

bool Inter__learn__rendezVous::operator<(const Interaction &interaction) const {
    bool ret = false;

    // check if interaction values are from the same connector
    if (&connector() == &interaction.connector()) {
        assert(dynamic_cast<const Inter__learn__rendezVous *>(&interaction) != NULL);
        const Inter__learn__rendezVous *other = static_cast<const Inter__learn__rendezVous *>(&interaction);
        ret = (((involvedPorts &  other->involvedPorts) == involvedPorts) &&
                (involvedPorts != other->involvedPorts));
    }

    return ret;
}

void Inter__learn__rendezVous::recycle() {
    Interaction::recycle();
    mPorts.clear();
    port_vector_fresh = true;
    defined = false;
    refresh_defined = false;
    involvedPorts.reset();
}

void Inter__learn__rendezVous::recycle(const vector<Port *> &ports) {
    Interaction::recycle();
    commonRecycle(ports);
}

void Inter__learn__rendezVous::commonRecycle(const vector<Port *> &ports){
    involvedPorts.reset();

    for (vector<Port *>::const_iterator portIt = ports.begin() ;
         portIt != ports.end() ;
         ++portIt) {
        const vector<Port *>::size_type post_shift = findPort(*portIt);

        involvedPorts.set(post_shift);
    }

    port_vector_fresh = false;
    refresh_defined = true;
}
