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

#include <learn/AT__learn__Brake.hpp>

#include <iostream>
#include <sstream>

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


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

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

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

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

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

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

AT__learn__Brake::AT__learn__Brake(const string &name , AtomIPort__learn__intPort &_iport_decl__brake, AtomIPort__learn__intPort &_iport_decl__changeSpeed
                         
                         , AtomEPort__learn__intPort &_eport_decl__brake, AtomEPort__learn__intPort &_eport_decl__changeSpeed
                         
                         ) :  ComponentItf(name, ATOM), Atom(name) , _iport_decl__brake(_iport_decl__brake), _iport_decl_pv__brake(_id__deltaSpeed, this->fullName()+"._id__deltaSpeed"), _iport_decl__changeSpeed(_iport_decl__changeSpeed), _iport_decl_pv__changeSpeed(_id__deltaSpeed, this->fullName()+"._id__deltaSpeed"), _eport_decl__brake(_eport_decl__brake), _eport_decl__changeSpeed(_eport_decl__changeSpeed), _transguard__1(false), _transguard__2(false), __previous(-1) {
    this->addInternalPort(_iport_decl__brake);

    // link data internal to internal port
    this->addInternalPort(_iport_decl__changeSpeed);
    // export port
    this->addPort(_eport_decl__brake);
    this->addPort(_eport_decl__changeSpeed);
}

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

#ifndef NDEBUG
    bool something_happened = false;
#endif

    // find the right transitions to execute
    if ((&_iport_decl_pv__brake == &portValue) && _transguard__1) {
        // 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(atIdle());

        // update input places
        fromIdle();

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

        // update output places
        toAction();

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



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

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

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

        // update input places
        fromAction();

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

        // update output places
        toIdle();

        // record the index of the latest executed transition
        __previous = 2;
// /home/siemens/bip/examples/sync_lec/learn.bip:105: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__Brake::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__Brake::initialize() {
    BipError *ret = &BipError::NoError;
    
    // reset status of ports
    _iport_decl__brake.clearPortValue();
    _iport_decl__changeSpeed.clearPortValue();

    // reset status of transitions
    _transguard__1 = false;
    _transguard__2 = 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()) && (!atAction()));

    // 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__Brake::toString() const {
    ostringstream oss;
    bool first=true;
    if (atIdle()) {
      if (!first) oss << ", ";
      else {
        first = false;
        oss << "at ";
      }
      oss << "Idle";
    }
    if (atAction()) {
      if (!first) oss << ", ";
      else {
        first = false;
        oss << "at ";
      }
      oss << "Action";
    }

    if (first) first = false;
    else oss << std::endl;
    oss << "deltaSpeed=" << _id__deltaSpeed;

    return oss.str(); 
}

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

    // update status of internal/external ports w.r.t. transitions
    // reset status of port brake
    this->_iport_decl__brake.setIsEnabled(false);
    
    _transguard__1 = (atIdle()
    
                );
    
    if (_transguard__1) {
        if (_iport_decl__brake.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__brake);
        
            return *r;
        }
        
        _iport_decl__brake.setIsEnabled(true);
    }
    
    // reset status of port changeSpeed
    this->_iport_decl__changeSpeed.setIsEnabled(false);
    
    _transguard__2 = (atAction()
    
                );
    
    if (_transguard__2) {
        if (_iport_decl__changeSpeed.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__changeSpeed);
        
            return *r;
        }
        
        _iport_decl__changeSpeed.setIsEnabled(true);
    }
    // recompute modified priority paths
    
    // applies priorities to port brake
    
    // recompute modified priority paths
    
    // applies priorities to port changeSpeed
    
    // 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 changeSpeed
    if (this->_iport_decl__changeSpeed.isEnabled() && !this->_iport_decl__changeSpeed.isDisabledByPriorities()) {
        this->_iport_decl__changeSpeed.setPortValue(_iport_decl_pv__changeSpeed);
    }
    else {
        this->_iport_decl__changeSpeed.clearPortValue();
    }
    
    // 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 changeSpeed
    _eport_decl__changeSpeed.setIsReset(true);
    
    // recompute port values of changeSpeed from scratch
    this->_eport_decl__changeSpeed.portValues().clear();
    
    // check port value of changeSpeed exported by changeSpeed
    if (this->_iport_decl__changeSpeed.hasPortValue()) {
        this->_eport_decl__changeSpeed.addPortValue(_iport_decl_pv__changeSpeed);
    }

    return *ret;
}

BipError &AT__learn__Brake::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__Brake::~AT__learn__Brake() {
}
