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

#include <learn/AT__learn__Environment.hpp>

#include <iostream>
#include <sstream>

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


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

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

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

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

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

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

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

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

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

AT__learn__Environment::AT__learn__Environment(const string &name , AtomIPort__learn__intPort &_iport_decl__sendInput, AtomIPort__learn__silent &_iport_decl__getInput, AtomIPort__learn__silent &_iport_decl__getInputInitial, AtomIPort__learn__silent &_iport_decl__noInput
                         
                         , AtomEPort__learn__intPort &_eport_decl__sendInput, AtomEPort__learn__silent &_eport_decl__getInput, AtomEPort__learn__silent &_eport_decl__getInputInitial, AtomEPort__learn__silent &_eport_decl__noInput
                         
                         ) :  ComponentItf(name, ATOM), Atom(name) , _iport_decl__sendInput(_iport_decl__sendInput), _iport_decl_pv__sendInput(_id__inputIndex, this->fullName()+"._id__inputIndex"), _iport_decl__getInput(_iport_decl__getInput), _iport_decl_pv__getInput(), _iport_decl__getInputInitial(_iport_decl__getInputInitial), _iport_decl_pv__getInputInitial(), _iport_decl__noInput(_iport_decl__noInput), _iport_decl_pv__noInput(), _eport_decl__sendInput(_eport_decl__sendInput), _eport_decl__getInput(_eport_decl__getInput), _eport_decl__getInputInitial(_eport_decl__getInputInitial), _eport_decl__noInput(_eport_decl__noInput), _id__inputIndex(1), _id__time(10), _transguard__1(false), _transguard__2(false), _transguard__3(false), _transguard__4(false), __previous(-1) {
    this->addInternalPort(_iport_decl__sendInput);

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

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

    // link data internal to internal port
    this->addInternalPort(_iport_decl__noInput);
    // export port
    this->addPort(_eport_decl__sendInput);
    this->addPort(_eport_decl__getInput);
    this->addPort(_eport_decl__getInputInitial);
    this->addPort(_eport_decl__noInput);
}

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

#ifndef NDEBUG
    bool something_happened = false;
#endif

    // find the right transitions to execute
    if ((&_iport_decl_pv__getInputInitial == &portValue) && _transguard__1) {
        // check consistency (enabledness, port values, ...)
        assert(_iport_decl__getInputInitial.hasPortValue());
        assert(&_iport_decl__getInputInitial.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 (atRead()) {
            NonOneSafePetriNetError *r = new NonOneSafePetriNetError(*this);
            r->setPort(_iport_decl__getInputInitial);
            return *r;
        }

        // update output places
        toRead();

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



        
#ifndef NDEBUG
        something_happened = true;
#endif
    } else if ((&_iport_decl_pv__getInput == &portValue) && _transguard__2) {
        // check consistency (enabledness, port values, ...)
        assert(_iport_decl__getInput.hasPortValue());
        assert(&_iport_decl__getInput.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 (atRead()) {
            NonOneSafePetriNetError *r = new NonOneSafePetriNetError(*this);
            r->setPort(_iport_decl__getInput);
            return *r;
        }

        // update output places
        toRead();

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



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

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

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

        // update input places
        fromRead();

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

        // update output places
        toIdle();

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

        // execute transition actions
// /home/siemens/bip/examples/sync_lec/learn.bip:40:74
        int_variables[this->fullName()+"._id__inputIndex"] = (int_variables[this->fullName()+"._id__inputIndex"])  +  (1);

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



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

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

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

        // update input places
        fromRead();

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

        // update output places
        toStop();

        // record the index of the latest executed transition
        __previous = 4;
// /home/siemens/bip/examples/sync_lec/learn.bip:41: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__Environment::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__Environment::initialize() {
    BipError *ret = &BipError::NoError;
    
    // reset status of ports
    _iport_decl__sendInput.clearPortValue();
    _iport_decl__getInput.clearPortValue();
    _iport_decl__getInputInitial.clearPortValue();
    _iport_decl__noInput.clearPortValue();

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

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

    if (first) first = false;
    else oss << std::endl;
    oss << "inputIndex=" << _id__inputIndex;
    if (first) first = false;
    else oss << std::endl;
    oss << "time=" << _id__time;

    return oss.str(); 
}

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

    // update status of internal/external ports w.r.t. transitions
    // reset status of port sendInput
    this->_iport_decl__sendInput.setIsEnabled(false);
    
    _transguard__3 = (atRead()
    // /home/siemens/bip/examples/sync_lec/learn.bip:40:2
                && ((int_variables[this->fullName()+"._id__inputIndex"])  <=  (10)));
    
    if (_transguard__3) {
        if (_iport_decl__sendInput.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__sendInput);
        
            return *r;
        }
        
        _iport_decl__sendInput.setIsEnabled(true);
    }
    
    // reset status of port getInputInitial
    this->_iport_decl__getInputInitial.setIsEnabled(false);
    
    _transguard__1 = (atIdle()
    // /home/siemens/bip/examples/sync_lec/learn.bip:38:2
                && ((int_variables[this->fullName()+"._id__inputIndex"])  ==  (1)));
    
    if (_transguard__1) {
        if (_iport_decl__getInputInitial.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__getInputInitial);
        
            return *r;
        }
        
        _iport_decl__getInputInitial.setIsEnabled(true);
    }
    
    // reset status of port getInput
    this->_iport_decl__getInput.setIsEnabled(false);
    
    _transguard__2 = (atIdle()
    
                );
    
    if (_transguard__2) {
        if (_iport_decl__getInput.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__getInput);
        
            return *r;
        }
        
        _iport_decl__getInput.setIsEnabled(true);
    }
    
    // reset status of port noInput
    this->_iport_decl__noInput.setIsEnabled(false);
    
    _transguard__4 = (atRead()
    // /home/siemens/bip/examples/sync_lec/learn.bip:41:2
                && ((int_variables[this->fullName()+"._id__inputIndex"])  >  ((10)  +  (1))));
    
    if (_transguard__4) {
        if (_iport_decl__noInput.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__noInput);
        
            return *r;
        }
        
        _iport_decl__noInput.setIsEnabled(true);
    }
    // recompute modified priority paths
    
    // applies priorities to port sendInput
    
    // recompute modified priority paths
    
    // applies priorities to port getInput
    
    // recompute modified priority paths
    
    // applies priorities to port getInputInitial
    
    // recompute modified priority paths
    
    // applies priorities to port noInput
    
    // update port value of sendInput
    if (this->_iport_decl__sendInput.isEnabled() && !this->_iport_decl__sendInput.isDisabledByPriorities()) {
        this->_iport_decl__sendInput.setPortValue(_iport_decl_pv__sendInput);
    }
    else {
        this->_iport_decl__sendInput.clearPortValue();
    }
    
    // update port value of getInput
    if (this->_iport_decl__getInput.isEnabled() && !this->_iport_decl__getInput.isDisabledByPriorities()) {
        this->_iport_decl__getInput.setPortValue(_iport_decl_pv__getInput);
    }
    else {
        this->_iport_decl__getInput.clearPortValue();
    }
    
    // update port value of getInputInitial
    if (this->_iport_decl__getInputInitial.isEnabled() && !this->_iport_decl__getInputInitial.isDisabledByPriorities()) {
        this->_iport_decl__getInputInitial.setPortValue(_iport_decl_pv__getInputInitial);
    }
    else {
        this->_iport_decl__getInputInitial.clearPortValue();
    }
    
    // update port value of noInput
    if (this->_iport_decl__noInput.isEnabled() && !this->_iport_decl__noInput.isDisabledByPriorities()) {
        this->_iport_decl__noInput.setPortValue(_iport_decl_pv__noInput);
    }
    else {
        this->_iport_decl__noInput.clearPortValue();
    }
    
    // force recomputation of connectors involving sendInput
    _eport_decl__sendInput.setIsReset(true);
    
    // recompute port values of sendInput from scratch
    this->_eport_decl__sendInput.portValues().clear();
    
    // check port value of sendInput exported by sendInput
    if (this->_iport_decl__sendInput.hasPortValue()) {
        this->_eport_decl__sendInput.addPortValue(_iport_decl_pv__sendInput);
    }
    
    // force recomputation of connectors involving getInput
    _eport_decl__getInput.setIsReset(true);
    
    // recompute port values of getInput from scratch
    this->_eport_decl__getInput.portValues().clear();
    
    // check port value of getInput exported by getInput
    if (this->_iport_decl__getInput.hasPortValue()) {
        this->_eport_decl__getInput.addPortValue(_iport_decl_pv__getInput);
    }
    
    // force recomputation of connectors involving getInputInitial
    _eport_decl__getInputInitial.setIsReset(true);
    
    // recompute port values of getInputInitial from scratch
    this->_eport_decl__getInputInitial.portValues().clear();
    
    // check port value of getInputInitial exported by getInputInitial
    if (this->_iport_decl__getInputInitial.hasPortValue()) {
        this->_eport_decl__getInputInitial.addPortValue(_iport_decl_pv__getInputInitial);
    }
    
    // force recomputation of connectors involving noInput
    _eport_decl__noInput.setIsReset(true);
    
    // recompute port values of noInput from scratch
    this->_eport_decl__noInput.portValues().clear();
    
    // check port value of noInput exported by noInput
    if (this->_iport_decl__noInput.hasPortValue()) {
        this->_eport_decl__noInput.addPortValue(_iport_decl_pv__noInput);
    }

    return *ret;
}

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