#include "ntfsallocation.hh"
#include "util.hh"


using namespace Gecode;


NTFSAllocation::NTFSAllocation (Space& home, Int::IntView cluster, NTFSBitmapExtractor* bitmap_cache, bool allocated) :
  Propagator (home),
  m_allocated (allocated),
  m_bitmap_cache (bitmap_cache),
  m_cluster (cluster)
{
  m_cluster.subscribe (home, *this, Int::PC_INT_DOM);
}


NTFSAllocation::NTFSAllocation (Space& home, bool share, NTFSAllocation& p) :
  Propagator (home, share, p),
  m_allocated (p.m_allocated),
  m_bitmap_cache (p.m_bitmap_cache)
{
  m_cluster.update (home, share, p.m_cluster);
}


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


size_t NTFSAllocation::dispose (Space& home)
{
  m_cluster.cancel (home, *this, Int::PC_INT_DOM);
  (void) Propagator::dispose (home);
  return sizeof (*this);
}


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


ExecStatus NTFSAllocation::propagate (Space& home, const ModEventDelta& med)
{
  Int::ViewRanges<Int::IntView> r_cluster (m_cluster);
  IntSet s_cluster (r_cluster);
  IntSetRanges r_cluster_copy (s_cluster);

  for (; r_cluster_copy (); ++r_cluster_copy) {
    int l = r_cluster_copy.min ();
    int u = r_cluster_copy.max ();
    while (l <= u) {
      if (m_bitmap_cache->isClusterAllocated (l) == m_allocated) {
        GECODE_ME_CHECK (m_cluster.gq (home, l));
        if (m_cluster.assigned ()) {
          return home.ES_SUBSUMED (*this);
        } else {
          return ES_FIX;
        }
      }
      l++;
    }
    GECODE_ME_CHECK (m_cluster.gq (home, l));
  }
  GECODE_NEVER;

}


ExecStatus NTFSAllocation::post (Space& home, Int::IntView cluster, NTFSBitmapExtractor* bitmap_cache, bool allocated)
{
  (void) new (home) NTFSAllocation (home, cluster, bitmap_cache, allocated);
  return ES_OK;
}


void ntfs_allocated (Space& home, IntVar cluster, NTFSBitmapExtractor* bitmap_cache)
{
  Int::IntView clusterV (cluster);
  if (NTFSAllocation::post (home, cluster, bitmap_cache, true) != ES_OK) {
    home.fail ();
  }
}


void ntfs_unallocated (Space& home, IntVar cluster, NTFSBitmapExtractor* bitmap_cache)
{
  Int::IntView clusterV (cluster);
  if (NTFSAllocation::post (home, cluster, bitmap_cache, false) != ES_OK) {
    home.fail ();
  }
}

