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

#include <learn/AT__learn__Perception.hpp>

#include <iostream>
#include <sstream>

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


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

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

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

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

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

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

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

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

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

AT__learn__Perception::AT__learn__Perception(const string &name , AtomIPort__learn__intPort &_iport_decl__getInput, AtomIPort__learn__intPort &_iport_decl__sendResult, AtomIPort__learn__silent &_iport_decl__inference
                         
                         , AtomEPort__learn__intPort &_eport_decl__getInput, AtomEPort__learn__intPort &_eport_decl__sendResult, AtomEPort__learn__silent &_eport_decl__inference
                         
                         ) :  ComponentItf(name, ATOM), Atom(name) , _iport_decl__getInput(_iport_decl__getInput), _iport_decl_pv__getInput(_id__inputIndex, this->fullName()+"._id__inputIndex"), _iport_decl__sendResult(_iport_decl__sendResult), _iport_decl_pv__sendResult(_id__result, this->fullName()+"._id__result"), _iport_decl__inference(_iport_decl__inference), _iport_decl_pv__inference(), _eport_decl__getInput(_eport_decl__getInput), _eport_decl__sendResult(_eport_decl__sendResult), _eport_decl__inference(_eport_decl__inference), _transguard__1(false), _transguard__2(false), _transguard__3(false), __previous(-1) {
    this->addInternalPort(_iport_decl__getInput);

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

    // link data internal to internal port
    this->addInternalPort(_iport_decl__inference);
    // export port
    this->addPort(_eport_decl__getInput);
    this->addPort(_eport_decl__sendResult);
    this->addPort(_eport_decl__inference);
}

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

#ifndef NDEBUG
    bool something_happened = false;
#endif

    // find the right transitions to execute
    if ((&_iport_decl_pv__getInput == &portValue) && _transguard__1) {
        // 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 (atInference()) {
            NonOneSafePetriNetError *r = new NonOneSafePetriNetError(*this);
            r->setPort(_iport_decl__getInput);
            return *r;
        }

        // update output places
        toInference();

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



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

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

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

        // update input places
        fromInference();

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

        // update output places
        toRead();

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

        // execute transition actions
// /home/siemens/bip/examples/sync_lec/learn.bip:67:49
        int_variables[this->fullName()+"._id__result"] = deepLearn(int_variables[this->fullName()+"._id__inputIndex"]);

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



        
#ifndef NDEBUG
        something_happened = true;
#endif
    } else if ((&_iport_decl_pv__sendResult == &portValue) && _transguard__3) {
        // check consistency (enabledness, port values, ...)
        assert(_iport_decl__sendResult.hasPortValue());
        assert(&_iport_decl__sendResult.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__sendResult);
            return *r;
        }

        // update output places
        toIdle();

        // record the index of the latest executed transition
        __previous = 3;
// /home/siemens/bip/examples/sync_lec/learn.bip:68: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__Perception::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__Perception::initialize() {
    BipError *ret = &BipError::NoError;
    
    // reset status of ports
    _iport_decl__getInput.clearPortValue();
    _iport_decl__sendResult.clearPortValue();
    _iport_decl__inference.clearPortValue();

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

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

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

    return oss.str(); 
}

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

    // update status of internal/external ports w.r.t. transitions
    // reset status of port inference
    this->_iport_decl__inference.setIsEnabled(false);
    
    _transguard__2 = (atInference()
    
                );
    
    if (_transguard__2) {
        if (_iport_decl__inference.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__inference);
        
            return *r;
        }
        
        _iport_decl__inference.setIsEnabled(true);
    }
    
    // reset status of port getInput
    this->_iport_decl__getInput.setIsEnabled(false);
    
    _transguard__1 = (atIdle()
    
                );
    
    if (_transguard__1) {
        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 sendResult
    this->_iport_decl__sendResult.setIsEnabled(false);
    
    _transguard__3 = (atRead()
    
                );
    
    if (_transguard__3) {
        if (_iport_decl__sendResult.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__sendResult);
        
            return *r;
        }
        
        _iport_decl__sendResult.setIsEnabled(true);
    }
    // recompute modified priority paths
    
    // applies priorities to port getInput
    
    // recompute modified priority paths
    
    // applies priorities to port sendResult
    
    // recompute modified priority paths
    
    // applies priorities to port inference
    
    // 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 sendResult
    if (this->_iport_decl__sendResult.isEnabled() && !this->_iport_decl__sendResult.isDisabledByPriorities()) {
        this->_iport_decl__sendResult.setPortValue(_iport_decl_pv__sendResult);
    }
    else {
        this->_iport_decl__sendResult.clearPortValue();
    }
    
    // update port value of inference
    if (this->_iport_decl__inference.isEnabled() && !this->_iport_decl__inference.isDisabledByPriorities()) {
        this->_iport_decl__inference.setPortValue(_iport_decl_pv__inference);
    }
    else {
        this->_iport_decl__inference.clearPortValue();
    }
    
    // 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 sendResult
    _eport_decl__sendResult.setIsReset(true);
    
    // recompute port values of sendResult from scratch
    this->_eport_decl__sendResult.portValues().clear();
    
    // check port value of sendResult exported by sendResult
    if (this->_iport_decl__sendResult.hasPortValue()) {
        this->_eport_decl__sendResult.addPortValue(_iport_decl_pv__sendResult);
    }
    
    // force recomputation of connectors involving inference
    _eport_decl__inference.setIsReset(true);
    
    // recompute port values of inference from scratch
    this->_eport_decl__inference.portValues().clear();
    
    // check port value of inference exported by inference
    if (this->_iport_decl__inference.hasPortValue()) {
        this->_eport_decl__inference.addPortValue(_iport_decl_pv__inference);
    }

    return *ret;
}

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