#include "interdomainsubsetpropagator.hh"


using namespace Gecode;


InterDomainSubset::InterDomainSubset (Space& home, Int::IntView x0, Int::IntView x1, IntSet domain_restriction_complement) :
  Propagator (home),
  x0 (x0),
  x1 (x1),
  m_domain_restriction_complement (domain_restriction_complement)
{
  this->x0.subscribe (home, *this, Int::PC_INT_DOM);
}


InterDomainSubset::InterDomainSubset (Space& home, bool share, InterDomainSubset& p) :
  Propagator (home, share, p),
  m_domain_restriction_complement (p.m_domain_restriction_complement)
{
  this->x0.update (home, share, p.x0);
  this->x1.update (home, share, p.x1);
}


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


size_t InterDomainSubset::dispose (Space& home) 
{
  this->x0.cancel (home, *this, Int::PC_INT_DOM);
  (void) Propagator::dispose (home);
  return sizeof (*this);
}


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

  
ExecStatus InterDomainSubset::propagate (Space& home, const Gecode::ModEventDelta& med) 
{
  // See section 23.2 for naive propagator for domain equal.
  Int::ViewRanges<Int::IntView> r0 (x0);
  IntSetRanges domain_restriction_complement_range (m_domain_restriction_complement);
  Iter::Ranges::Union<Int::ViewRanges<Int::IntView>, IntSetRanges> r0_union_domain_restriction_complement_range (r0, domain_restriction_complement_range);
  GECODE_ME_CHECK (x1.inter_r (home, r0_union_domain_restriction_complement_range));
  if (x1.assigned ()) {
    return home.ES_SUBSUMED (*this);
  } else {
    return ES_FIX;
  }
}


ExecStatus InterDomainSubset::post (Space& home, Int::IntView x0, Int::IntView x1, IntSet domain_restriction_complement)
{
  (void) new (home) InterDomainSubset (home, x0, x1, domain_restriction_complement);
  return ES_OK;
}


void inter_domain_subset (Space& home, IntVar x0, IntVar x1, IntSet domain_restriction)
{
  Int::IntView x0V (x0);
  Int::IntView x1V (x1);
  IntSetRanges domain_restriction_range (domain_restriction);
  Iter::Ranges::Compl<Int::Limits::min, Int::Limits::max, IntSetRanges> domain_restriction_complement_range (domain_restriction_range);
  IntSet domain_restriction_complement (domain_restriction_complement_range);
  if (InterDomainSubset::post (home, x0V, x1V, domain_restriction_complement) != ES_OK) {
    home.fail ();
  }
}
