// /opt/bip_fmu/examples/simple/priorities_in_atom.bip:5:2

#include <priorities_xin_xatom/AT__priorities_xin_xatom__MyAtom.hpp>

#include <iostream>
#include <sstream>

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


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

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

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

AT__priorities_xin_xatom__MyAtom::AT__priorities_xin_xatom__MyAtom(const string &name , AtomIPort__priorities_xin_xatom__Port &_iport_decl__p, AtomIPort__priorities_xin_xatom__Port &_iport_decl__q
                         
                         
                         
                         ) :  ComponentItf(name, ATOM), Atom(name) , _iport_decl__p(_iport_decl__p), _iport_decl_pv__p(), _iport_decl__q(_iport_decl__q), _iport_decl_pv__q(), _transguard__1(false), _transguard__2(false), _prioguard__myPrioEven(false), _prioguard__myPrioOdd(false), _prioenabled__myPrioEven(false), _prioenabled__myPrioOdd(false), __previous(-1) {
    this->addInternalPort(_iport_decl__p);

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

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

#ifndef NDEBUG
    bool something_happened = false;
#endif

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

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

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

        // update input places
        fromLOOP();

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

        // update output places
        toLOOP();

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

        // execute transition actions
// /opt/bip_fmu/examples/simple/priorities_in_atom.bip:15:12
        int_variables[this->fullName()+"._id__i"] = (int_variables[this->fullName()+"._id__i"])  +  (1);

        // end of execute transition actions
// /opt/bip_fmu/examples/simple/priorities_in_atom.bip:14:4



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

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

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

        // update input places
        fromLOOP();

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

        // update output places
        toLOOP();

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

        // execute transition actions
// /opt/bip_fmu/examples/simple/priorities_in_atom.bip:18:12
        int_variables[this->fullName()+"._id__i"] = (int_variables[this->fullName()+"._id__i"])  +  (1);

        // end of execute transition actions
// /opt/bip_fmu/examples/simple/priorities_in_atom.bip:17:4



        
#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__priorities_xin_xatom__MyAtom::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__priorities_xin_xatom__MyAtom::initialize() {
    BipError *ret = &BipError::NoError;
    
    // reset status of ports
    _iport_decl__p.clearPortValue();
    _iport_decl__q.clearPortValue();

    // reset status of transitions
    _transguard__1 = false;
    _transguard__2 = false;

    // reset status of guards of priorities
    _prioguard__myPrioEven = true;
    _prioguard__myPrioOdd = true;

    // reset status of enabledness of priorities
    _prioenabled__myPrioEven = true;
    _prioenabled__myPrioOdd = true;

    // reset status of enabledness of priority paths
    _priopathenabled__1__2 = true;
    _priopathenabled__1 = true;

    _priopathenabled__2__1 = true;
    _priopathenabled__2 = true;

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

    // marking must be initialized to empty
    assert((!atLOOP()));

    // update initial places
    toLOOP();

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

    // execute transition actions
// /opt/bip_fmu/examples/simple/priorities_in_atom.bip:12:12
    int_variables[this->fullName()+"._id__i"] = 0;

    // end of execute transition actions




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

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

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

    return update();
}

string AT__priorities_xin_xatom__MyAtom::toString() const {
    ostringstream oss;
    bool first=true;
    if (atLOOP()) {
      if (!first) oss << ", ";
      else {
        first = false;
        oss << "at ";
      }
      oss << "LOOP";
    }

    if (first) first = false;
    else oss << std::endl;
    oss << "i=" << _id__i;

    return oss.str(); 
}

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

    // update status of internal/external ports w.r.t. transitions
    // reset status of port p
    this->_iport_decl__p.setIsEnabled(false);
    
    _transguard__1 = (atLOOP()
    
                );
    
    if (_transguard__1) {
        if (_iport_decl__p.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__p);
        
            return *r;
        }
        
        _iport_decl__p.setIsEnabled(true);
    }
    
    // reset status of port q
    this->_iport_decl__q.setIsEnabled(false);
    
    _transguard__2 = (atLOOP()
    
                );
    
    if (_transguard__2) {
        if (_iport_decl__q.isEnabled()) {
            NonDeterministicPetriNetError *r = new NonDeterministicPetriNetError(*this);
            r->setPort(_iport_decl__q);
        
            return *r;
        }
        
        _iport_decl__q.setIsEnabled(true);
    }
    // update guards of priorities
    // /opt/bip_fmu/examples/simple/priorities_in_atom.bip:20:46
    _prioguard__myPrioEven = ((int_variables[this->fullName()+"._id__i"])  %  (2))  ==  (0);
    // /opt/bip_fmu/examples/simple/priorities_in_atom.bip:21:46
    _prioguard__myPrioOdd = ((int_variables[this->fullName()+"._id__i"])  %  (2))  ==  (1);
    
    // check for cycles in priorities
    if ((_prioguard__myPrioOdd && _prioguard__myPrioEven))
        return *(new CycleInAtomPrioritiesError());
    
    // recompute modified priority paths
    _priopathenabled__2__1 = (_prioguard__myPrioOdd && _prioguard__myPrioEven && this->_iport_decl__p.isEnabled()); // myPrioOdd, myPrioEven
    _priopathenabled__2 = (_prioguard__myPrioOdd && this->_iport_decl__q.isEnabled()); // myPrioOdd
    
    // applies priorities to port p
    if (_priopathenabled__2__1 || // p < q < p
        _priopathenabled__2 // p < q
        ) {
        // disable port p
        _iport_decl__p.setIsDisabledByPriorities(true);
    }
    else {
        _iport_decl__p.setIsDisabledByPriorities(false);
    }
    
    // recompute modified priority paths
    _priopathenabled__1__2 = (_prioguard__myPrioEven && _prioguard__myPrioOdd && this->_iport_decl__q.isEnabled()); // myPrioEven, myPrioOdd
    _priopathenabled__1 = (_prioguard__myPrioEven && this->_iport_decl__p.isEnabled()); // myPrioEven
    
    // applies priorities to port q
    if (_priopathenabled__1__2 || // q < p < q
        _priopathenabled__1 // q < p
        ) {
        // disable port q
        _iport_decl__q.setIsDisabledByPriorities(true);
    }
    else {
        _iport_decl__q.setIsDisabledByPriorities(false);
    }
    
    // update port value of p
    if (this->_iport_decl__p.isEnabled() && !this->_iport_decl__p.isDisabledByPriorities()) {
        this->_iport_decl__p.setPortValue(_iport_decl_pv__p);
    }
    else {
        this->_iport_decl__p.clearPortValue();
    }
    
    // update port value of q
    if (this->_iport_decl__q.isEnabled() && !this->_iport_decl__q.isDisabledByPriorities()) {
        this->_iport_decl__q.setPortValue(_iport_decl_pv__q);
    }
    else {
        this->_iport_decl__q.clearPortValue();
    }

    return *ret;
}

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