// /home/siemens/bip/examples/sync_lec/learn.bip:71:1

#include <learn/AT__learn__Controller.hpp>

#include <iostream>
#include <sstream>

#include <CycleInAtomPrioritiesError.hpp>
#include <NonDeterministicPetriNetError.hpp>
#include <NonOneSafePetriNetError.hpp>
#include <AtomInvariantViolationError.hpp>
#include <Variables.hpp>


bool AT__learn__Controller::atIdle () const {
    return __statesbv[ 0/(8*sizeof(int))] & 1<< (0%(8*sizeof(int)));
}

bool AT__learn__Controller::toIdle () {
    if (atIdle()) return false;
    __statesbv[ 0/(8*sizeof(int))] |= 1<< (0%(8*sizeof(int)));
    return true;
}

bool AT__learn__Controller::fromIdle () {
    if (!atIdle()) return false;
    __statesbv[ 0/(8*sizeof(int))] &= ~(1<< (0%(8*sizeof(int))));
    return true;
}

bool AT__learn__Controller::atGet () const {
    return __statesbv[ 1/(8*sizeof(int))] & 1<< (1%(8*sizeof(int)));
}

bool AT__learn__Controller::toGet () {
    if (atGet()) return false;
    __statesbv[ 1/(8*sizeof(int))] |= 1<< (1%(8*sizeof(int)));
    return true;
}

bool AT__learn__Controller::fromGet () {
    if (!atGet()) return false;
    __statesbv[ 1/(8*sizeof(int))] &= ~(1<< (1%(8*sizeof(int))));
    return true;
}

bool AT__learn__Controller::atCompare () const {
    return __statesbv[ 2/(8*sizeof(int))] & 1<< (2%(8*sizeof(int)));
}

bool AT__learn__Controller::toCompare () {
    if (atCompare()) return false;
    __statesbv[ 2/(8*sizeof(int))] |= 1<< (2%(8*sizeof(int)));
    return true;
}

bool AT__learn__Controller::fromCompare () {
    if (!atCompare()) return false;
    __statesbv[ 2/(8*sizeof(int))] &= ~(1<< (2%(8*sizeof(int))));
    return true;
}

AT__learn__Controller::AT__learn__Controller(const string &name , AtomIPort__learn__intPort &_iport_decl__getSpeedLimit, AtomIPort__learn__intPort &_iport_decl__getSpeed, AtomIPort__learn__intPort &_iport_decl__brake, AtomIPort__learn__intPort &_iport_decl__throttle, AtomIPort__learn__intPort &_iport_decl__noSpeedChange
                         
                         , AtomEPort__learn__intPort &_eport_decl__getSpeedLimit, AtomEPort__learn__intPort &_eport_decl__getSpeed, AtomEPort__learn__intPort &_eport_decl__brake, AtomEPort__learn__intPort &_eport_decl__throttle, AtomEPort__learn__intPort &_eport_decl__noSpeedChange
                         
                         ) :  ComponentItf(name, ATOM), Atom(name) , _iport_decl__getSpeedLimit(_iport_decl__getSpeedLimit), _iport_decl_pv__getSpeedLimit(_id__speedLimit, this->fullName()+"._id__speedLimit"), _iport_decl__getSpeed(_iport_decl__getSpeed), _iport_decl_pv__getSpeed(_id__speed, this->fullName()+"._id__speed"), _iport_decl__brake(_iport_decl__brake), _iport_decl_pv__brake(_id__deltaSpeed, this->fullName()+"._id__deltaSpeed"), _iport_decl__throttle(_iport_decl__throttle), _iport_decl_pv__throttle(_id__deltaSpeed, this->fullName()+"._id__deltaSpeed"), _iport_decl__noSpeedChange(_iport_decl__noSpeedChange), _iport_decl_pv__noSpeedChange(_id__zero, this->fullName()+"._id__zero"), _eport_decl__getSpeedLimit(_eport_decl__getSpeedLimit), _eport_decl__getSpeed(_eport_decl__getSpeed), _eport_decl__brake(_eport_decl__brake), _eport_decl__throttle(_eport_decl__throttle), _eport_decl__noSpeedChange(_eport_decl__noSpeedChange), _id__zero(0), _transguard__1(false), _transguard__2(false), _transguard__3(false), _transguard__4(false), _transguard__5(false), __previous(-1) {
    this->addInternalPort(_iport_decl__getSpeedLimit);

    // link data internal to internal port
    this->addInternalPort(_iport_decl__getSpeed);

    // link data internal to internal port
    this->addInternalPort(_iport_decl__brake);

    // link data internal to internal port
    this->addInternalPort(_iport_decl__throttle);

    // link data internal to internal port
    this->addInternalPort(_iport_decl__noSpeedChange);
    // export port
    this->addPort(_eport_decl__getSpeedLimit);
    this->addPort(_eport_decl__getSpeed);
    this->addPort(_eport_decl__brake);
    this->addPort(_eport_decl__throttle);
    this->addPort(_eport_decl__noSpeedChange);
}

BipError& AT__learn__Controller::execute(PortValue &portValue) {
    BipError *ret = &BipError::NoError;

#ifndef NDEBUG
    bool something_happened = false;
#endif

    // find the right transitions to execute
    if ((&_iport_decl_pv__getSpeedLimit == &portValue) && _transguard__1) {
        // check consistency (enabledness, port values, ...)
        assert(_iport_decl__getSpeedLimit.hasPortValue());
        assert(&_iport_decl__getSpeedLimit.portValue() == &portValue);

        // check at most one transitions is executed
        assert(!something_happened);

        // the transition should be enabled by places
        assert(atIdle());

        // update input places
        fromIdle();

        // check one-safetyness
        if (atGet()) {
            NonOneSafePetriNetError *r = new NonOneSafePetriNetError(*this);
            r->setPort(_iport_decl__getSpeedLimit);
            return *r;
        }

        // update output places
        toGet();

        // record the index of the latest executed transition
        __previous = 1;
// /home/siemens/bip/examples/sync_lec/learn.bip:85:2



        
#ifndef NDEBUG
        something_happened = true;
#endif
    } else if ((&_iport_decl_pv__getSpeed == &portValue) && _transguard__2) {
        // check consistency (enabledness, port values, ...)
        assert(_iport_decl__getSpeed.hasPortValue());
        assert(&_iport_decl__getSpeed.portValue() == &portValue);

        // check at most one transitions is executed
        assert(!something_happened);

        // the transition should be enabled by places
        assert(atGet());

        // update input places
        fromGet();

        // check one-safetyness
        if (atCompare()) {
            NonOneSafePetriNetError *r = new NonOneSafePetriNetError(*this);
            r->setPort(_iport_decl__getSpeed);
            return *r;
        }

        // update output places
        toCompare();

        // record the index of the latest executed transition
        __previous = 2;

        // execute transition actions
// /home/siemens/bip/examples/sync_lec/learn.bip:88:2
        printf("\n\033[30;47m Current speed: %d km/h\033[0m\n", int_variables[this->fullName()+"._id__speed"]);
// /home/siemens/bip/examples/sync_lec/learn.bip:89:2
        printf("\033[01;33m Speed limit: %d km/h\033[0m\n", int_variables[this->fullName()+"._id__speedLimit"]);
// /home/siemens/bip/examples/sync_lec/learn.bip:89:78
        int_variables[this->fullName()+"._id__deltaSpeed"] = (int_variables[this->fullName()+"._id__speedLimit"])  -  (int_variables[this->fullName()+"._id__speed"]);

        // end of execute transition actions
// /home/siemens/bip/examples/sync_lec/learn.bip:86:2



        
#ifndef NDEBUG
        something_happened = true;
#endif
    } else if ((&_iport_decl_pv__noSpeedChange == &portValue) && _transguard__3) {
        // check consistency (enabledness, port values, ...)
        assert(_iport_decl__noSpeedChange.hasPortValue());
        assert(&_iport_decl__noSpeedChange.portValue() == &portValue);

        // check at most one transitions is executed
        assert(!something_happened);

        // the transition should be enabled by places
        assert(atCompare());

        // update input places
        fromCompare();

        // check one-safetyness
        if (atIdle()) {
            NonOneSafePetriNetError *r = new NonOneSafePetriNetError(*this);
            r->setPort(_iport_decl__noSpeedChange);
            return *r;
        }

        // update output places
        toIdle();

        // record the index of the latest executed transition
        __previous = 3;
// /home/siemens/bip/examples/sync_lec/learn.bip:90:2



        
#ifndef NDEBUG
        something_happened = true;
#endif
    } else if ((&_iport_decl_pv__brake == &portValue) && _transguard__4) {
        // check consistency (enabledness, port values, ...)
        assert(_iport_decl__brake.hasPortValue());
        assert(&_iport_decl__brake.portValue() == &portValue);

        // check at most one transitions is executed
        assert(!something_happened);

        // the transition should be enabled by places
        assert(atCompare());

        // update input places
        fromCompare();

        // check one-safetyness
        if (atIdle()) {
            NonOneSafePetriNetError *r = new NonOneSafePetriNetError(*this);
            r->setPort(_iport_decl__brake);
            return *r;
        }

        // update output places
        toIdle();

        // record the index of the latest executed transition
        __previous = 4;

        // execute transition actions
// /home/siemens/bip/examples/sync_lec/learn.bip:92:7
        printf("\033[01;31m Depress brake!\033[0m\n");

        // end of execute transition actions
// /home/siemens/bip/examples/sync_lec/learn.bip:91:2



        
#ifndef NDEBUG
        something_happened = true;
#endif
    } else if ((&_iport_decl_pv__throttle == &portValue) && _transguard__5) {
        // check consistency (enabledness, port values, ...)
        assert(_iport_decl__throttle.hasPortValue());
        assert(&_iport_decl__throttle.portValue() == &portValue);

        // check at most one transitions is executed
        assert(!something_happened);

        // the transition should be enabled by places
        assert(atCompare());

        // update input places
        fromCompare();

        // check one-safetyness
        if (atIdle()) {
            NonOneSafePetriNetError *r = new NonOneSafePetriNetError(*this);
            r->setPort(_iport_decl__throttle);
            return *r;
        }

        // update output places
        toIdle();

        // record the index of the latest executed transition
        __previous = 5;

        // execute transition actions
// /home/siemens/bip/examples/sync_lec/learn.bip:94:7
        printf("\033[01;32m Depress throttle!\033[0m\n");

        // end of execute transition actions
// /home/siemens/bip/examples/sync_lec/learn.bip:93:2



        
#ifndef NDEBUG
        something_happened = true;
#endif
    }
    if (ret->type() != NO_ERROR) return *ret;

    // check that at least one transition has been executed
    assert(something_happened);

    // execute internal transitions
    ret = &executeInternalTransitions();

    if (ret->type() != NO_ERROR) return *ret;

    return update();
}

BipError& AT__learn__Controller::execute(AtomExternalPort &port) {
   BipError *ret = &BipError::NoError;

#ifndef NDEBUG
    bool something_happened = false;
#endif

    if (ret->type() != NO_ERROR) return *ret;

    // check that at least one transition has been executed
    assert(something_happened);

    // execute internal transitions
    ret = &executeInternalTransitions();

    if (ret->type() != NO_ERROR) return *ret;

    return update();
}

BipError& AT__learn__Controller::initialize() {
    BipError *ret = &BipError::NoError;
    
    // reset status of ports
    _iport_decl__getSpeedLimit.clearPortValue();
    _iport_decl__getSpeed.clearPortValue();
    _iport_decl__brake.clearPortValue();
    _iport_decl__throttle.clearPortValue();
    _iport_decl__noSpeedChange.clearPortValue();

    // reset status of transitions
    _transguard__1 = false;
    _transguard__2 = false;
    _transguard__3 = false;
    _transguard__4 = false;
    _transguard__5 = false;

    // initialize to empty marking
    for (unsigned int idx = 0; idx < bvector_size; idx++){
        __statesbv[idx] = 0;
    }

    // marking must be initialized to empty
    assert((!atIdle()) && (!atGet()) && (!atCompare()));

    // update initial places
    toIdle();

    // record the index of the latest executed transition
    __previous = 0;




    if (ret->type() != NO_ERROR) return *ret;

    // execute (initial) internal transitions
    ret = &executeInternalTransitions();

    if (ret->type() != NO_ERROR) return *ret;

    return update();
}

string AT__learn__Controller::toString() const {
    ostringstream oss;
    bool first=true;
    if (atIdle()) {
      if (!first) oss << ", ";
      else {
        first = false;
        oss << "at ";
      }
      oss << "Idle";
    }
    if (atGet()) {
      if (!first) oss << ", ";
      else {
        first = false;
        oss << "at ";
      }
      oss << "Get";
    }
    if (atCompare()) {
      if (!first) oss << ", ";
      else {
        first = false;
        oss << "at ";
      }
      oss << "Compare";
    }

    if (first) first = false;
    else oss << std::endl;
    oss << "speed=" << _id__speed;
    if (first) first = false;
    else oss << std::endl;
    oss << "speedLimit=" << _id__speedLimit;
    if (first) first = false;
    else oss << std::endl;
    oss << "deltaSpeed=" << _id__deltaSpeed;
    if (first) first = false;
    else oss << std::endl;
    oss << "zero=" << _id__zero;

    return oss.str(); 
}

BipError& AT__learn__Controller::update() {
    BipError *ret = &BipError::NoError;

    // update status of internal/external ports w.r.t. transitions
    // reset status of port getSpeed
    this->_iport_decl__getSpeed.setIsEnabled(false);
    
    _transguard__2 = (atGet()
    
                );
    
    if (_transguard__2) {
        if (_iport_decl__getSpeed.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__getSpeed);
        
            return *r;
        }
        
        _iport_decl__getSpeed.setIsEnabled(true);
    }
    
    // reset status of port getSpeedLimit
    this->_iport_decl__getSpeedLimit.setIsEnabled(false);
    
    _transguard__1 = (atIdle()
    
                );
    
    if (_transguard__1) {
        if (_iport_decl__getSpeedLimit.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__getSpeedLimit);
        
            return *r;
        }
        
        _iport_decl__getSpeedLimit.setIsEnabled(true);
    }
    
    // reset status of port throttle
    this->_iport_decl__throttle.setIsEnabled(false);
    
    _transguard__5 = (atCompare()
    // /home/siemens/bip/examples/sync_lec/learn.bip:93:2
                && ((int_variables[this->fullName()+"._id__deltaSpeed"])  >=  (0)));
    
    if (_transguard__5) {
        if (_iport_decl__throttle.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__throttle);
        
            return *r;
        }
        
        _iport_decl__throttle.setIsEnabled(true);
    }
    
    // reset status of port noSpeedChange
    this->_iport_decl__noSpeedChange.setIsEnabled(false);
    
    _transguard__3 = (atCompare()
    // /home/siemens/bip/examples/sync_lec/learn.bip:90:2
                && ((int_variables[this->fullName()+"._id__deltaSpeed"])  ==  (0)));
    
    if (_transguard__3) {
        if (_iport_decl__noSpeedChange.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__noSpeedChange);
        
            return *r;
        }
        
        _iport_decl__noSpeedChange.setIsEnabled(true);
    }
    
    // reset status of port brake
    this->_iport_decl__brake.setIsEnabled(false);
    
    _transguard__4 = (atCompare()
    // /home/siemens/bip/examples/sync_lec/learn.bip:91:2
                && ((int_variables[this->fullName()+"._id__deltaSpeed"])  <  (0)));
    
    if (_transguard__4) {
        if (_iport_decl__brake.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__brake);
        
            return *r;
        }
        
        _iport_decl__brake.setIsEnabled(true);
    }
    // recompute modified priority paths
    
    // applies priorities to port getSpeedLimit
    
    // recompute modified priority paths
    
    // applies priorities to port getSpeed
    
    // recompute modified priority paths
    
    // applies priorities to port brake
    
    // recompute modified priority paths
    
    // applies priorities to port throttle
    
    // recompute modified priority paths
    
    // applies priorities to port noSpeedChange
    
    // update port value of getSpeedLimit
    if (this->_iport_decl__getSpeedLimit.isEnabled() && !this->_iport_decl__getSpeedLimit.isDisabledByPriorities()) {
        this->_iport_decl__getSpeedLimit.setPortValue(_iport_decl_pv__getSpeedLimit);
    }
    else {
        this->_iport_decl__getSpeedLimit.clearPortValue();
    }
    
    // update port value of getSpeed
    if (this->_iport_decl__getSpeed.isEnabled() && !this->_iport_decl__getSpeed.isDisabledByPriorities()) {
        this->_iport_decl__getSpeed.setPortValue(_iport_decl_pv__getSpeed);
    }
    else {
        this->_iport_decl__getSpeed.clearPortValue();
    }
    
    // update port value of brake
    if (this->_iport_decl__brake.isEnabled() && !this->_iport_decl__brake.isDisabledByPriorities()) {
        this->_iport_decl__brake.setPortValue(_iport_decl_pv__brake);
    }
    else {
        this->_iport_decl__brake.clearPortValue();
    }
    
    // update port value of throttle
    if (this->_iport_decl__throttle.isEnabled() && !this->_iport_decl__throttle.isDisabledByPriorities()) {
        this->_iport_decl__throttle.setPortValue(_iport_decl_pv__throttle);
    }
    else {
        this->_iport_decl__throttle.clearPortValue();
    }
    
    // update port value of noSpeedChange
    if (this->_iport_decl__noSpeedChange.isEnabled() && !this->_iport_decl__noSpeedChange.isDisabledByPriorities()) {
        this->_iport_decl__noSpeedChange.setPortValue(_iport_decl_pv__noSpeedChange);
    }
    else {
        this->_iport_decl__noSpeedChange.clearPortValue();
    }
    
    // force recomputation of connectors involving getSpeedLimit
    _eport_decl__getSpeedLimit.setIsReset(true);
    
    // recompute port values of getSpeedLimit from scratch
    this->_eport_decl__getSpeedLimit.portValues().clear();
    
    // check port value of getSpeedLimit exported by getSpeedLimit
    if (this->_iport_decl__getSpeedLimit.hasPortValue()) {
        this->_eport_decl__getSpeedLimit.addPortValue(_iport_decl_pv__getSpeedLimit);
    }
    
    // force recomputation of connectors involving getSpeed
    _eport_decl__getSpeed.setIsReset(true);
    
    // recompute port values of getSpeed from scratch
    this->_eport_decl__getSpeed.portValues().clear();
    
    // check port value of getSpeed exported by getSpeed
    if (this->_iport_decl__getSpeed.hasPortValue()) {
        this->_eport_decl__getSpeed.addPortValue(_iport_decl_pv__getSpeed);
    }
    
    // force recomputation of connectors involving brake
    _eport_decl__brake.setIsReset(true);
    
    // recompute port values of brake from scratch
    this->_eport_decl__brake.portValues().clear();
    
    // check port value of brake exported by brake
    if (this->_iport_decl__brake.hasPortValue()) {
        this->_eport_decl__brake.addPortValue(_iport_decl_pv__brake);
    }
    
    // force recomputation of connectors involving throttle
    _eport_decl__throttle.setIsReset(true);
    
    // recompute port values of throttle from scratch
    this->_eport_decl__throttle.portValues().clear();
    
    // check port value of throttle exported by throttle
    if (this->_iport_decl__throttle.hasPortValue()) {
        this->_eport_decl__throttle.addPortValue(_iport_decl_pv__throttle);
    }
    
    // force recomputation of connectors involving noSpeedChange
    _eport_decl__noSpeedChange.setIsReset(true);
    
    // recompute port values of noSpeedChange from scratch
    this->_eport_decl__noSpeedChange.portValues().clear();
    
    // check port value of noSpeedChange exported by noSpeedChange
    if (this->_iport_decl__noSpeedChange.hasPortValue()) {
        this->_eport_decl__noSpeedChange.addPortValue(_iport_decl_pv__noSpeedChange);
    }

    return *ret;
}

BipError &AT__learn__Controller::executeInternalTransitions() {
    BipError &ret = BipError::NoError;

    // used to record the enabled internal transition
    int __enabled_internal = 0;

    do {
        // recompute enabled internal transitions
        __enabled_internal = 0;


        // execute the enabled internal transition if exist
        if (__enabled_internal != 0) {
            switch (__enabled_internal) {

              default:
                assert(false);
            }
        }
    } while (__enabled_internal != 0);

    return ret;
}

AT__learn__Controller::~AT__learn__Controller() {
}
