#ifndef __FORENSICS_DATASOURCE_HH__
#define __FORENSICS_DATASOURCE_HH__

#include "forensics-gecode.hh"


class DataSource 
{
protected:
  Gecode::Space& m_home;  // TODO: do we need this?

public:
  DataSource (Gecode::Space& home);

  DataSource (bool share, Gecode::Space& home, DataSource& ds);

  virtual Gecode::IntVar& unavailable () = 0;

  virtual unsigned char read (int64_t offset) const = 0;

  virtual void read (int64_t block, unsigned char* buffer) const = 0;

  virtual void print (std::ostream& os) const = 0;

  virtual void print (void) const;
};


extern unsigned char datasource_buffer[];
extern int64_t datasource_last_block;
// extern DataSource* datasource_p;
extern int64_t cache_hits;
extern int64_t cache_misses;

inline void invalidate_dsread_cache ()
{
  datasource_last_block = -1;
  // datasource_p = NULL;
}


inline unsigned char dsread (DataSource& ds, const int64_t offset)
{
  // std::cout << "dsread: offset = " << offset << std::endl;
  int64_t this_block = offset / BLOCK_SIZE;
  if (datasource_last_block == this_block) {
    cache_hits++;
    // if (datasource_last_block == this_block && datasource_p == &ds) {
    // std::cout << "dsread: cache hit" << std::endl;
    return datasource_buffer[offset % BLOCK_SIZE];
  } else {
    cache_misses++;
    // std::cout << "dsread: cache miss" << std::endl;
    ds.read (this_block, datasource_buffer);
    datasource_last_block = this_block;
    // datasource_p = & ds;
    return datasource_buffer[offset % BLOCK_SIZE];
  }
}

#endif

