#include "blockreadpropagator.hh"


using namespace Gecode;


BlockRead::BlockRead (Space& home, ViewArray<Int::IntView> blocksV, Int::IntView unavailableV, Int::IntView parent_unavailableV) : 
  Propagator (home),
  blocksV (blocksV),
  unavailableV (unavailableV),
  parent_unavailableV (parent_unavailableV)
{
  blocksV.subscribe (home, *this, Int::PC_INT_VAL);
  parent_unavailableV.subscribe (home, *this, Int::PC_INT_DOM);
}


BlockRead::BlockRead (Space& home, bool share, BlockRead& p) : 
  Propagator (home, share, p)
{
  blocksV.update (home, share, p.blocksV);
  unavailableV.update (home, share, p.unavailableV);
  parent_unavailableV.update (home, share, p.parent_unavailableV);
}


Propagator* BlockRead::copy (Space& home, bool share)
{
  return new (home) BlockRead (home, share, *this);
}


size_t BlockRead::dispose (Space& home) 
{
  blocksV.cancel (home, *this, Int::PC_INT_VAL);
  parent_unavailableV.cancel (home, *this, Int::PC_INT_DOM);
  (void) Propagator::dispose (home);
  return sizeof (*this);
}


PropCost BlockRead::cost (const Space& home, const ModEventDelta& med) const 
{
  return PropCost::binary (PropCost::HI);
}


ExecStatus BlockRead::propagate (Space& home, const Gecode::ModEventDelta& med) 
{
  int blocks_size = blocksV.size ();
  int all_assigned = true;
  for (int i = 0; i < blocks_size; i++) {
    if (blocksV[i].assigned () && !parent_unavailableV.in (blocksV[i].val ())) {
      if (unavailableV.nq (home, i) == Int::ME_INT_FAILED) {
        return ES_FAILED; 
      }
    } else {
      all_assigned = false;
    }
  }
  if (all_assigned) {
    return home.ES_SUBSUMED (*this);
  } else {
    return ES_NOFIX;
  }
  GECODE_NEVER;
}


ExecStatus BlockRead::post (Space& home, ViewArray<Int::IntView> blocksV, Int::IntView unavailableV, Int::IntView parent_unavailableV)
{
  (void) new (home) BlockRead (home, blocksV, unavailableV, parent_unavailableV);
  return ES_OK;
}


void block_read (Space& home, IntVarArray blocks, IntVar unavailable, IntVar parent_unavailable)
{
  ViewArray<Int::IntView> blocksV (home, IntVarArgs (blocks));
  Int::IntView unavailableV (unavailable);
  Int::IntView parent_unavailableV (parent_unavailable);
  if (BlockRead::post (home, blocksV, unavailableV, parent_unavailableV) != ES_OK) {
    home.fail ();
  }
}

