#ifndef _D_PTR_H
#define _D_PTR_H

#include "disk_tools.h"

namespace disk_tools {

template< class T >
class d_ptr_assign {
   offset_type addr;
   T * value;
   bfstream * file;
   d_alloc * alloc;

public:
   d_ptr_assign(bfstream * file, d_alloc * alloc, T * value, const offset_type addr) {
      this->addr = addr;
      this->value = value;
      this->file = file;
      this->alloc = alloc;
   }
   d_ptr_assign(const d_ptr_assign & cp) {
      addr = cp.addr;
      value = cp.value;
      file = cp.file;
      alloc = cp.alloc;
   }
   d_ptr_assign & operator=(const d_ptr_assign & cp) {
      addr = cp.addr;
      value = cp.value;
      file = cp.file;
      alloc = cp.alloc;
      return *this;
   }
   d_ptr_assign() {
      addr = -1L;
      value = 0;
      file = 0;
      alloc = 0;
   }
   ~d_ptr_assign() {
   }
   d_ptr_assign & operator=(const T & value) {
      file->seek(addr);
      offset_type temp;
      *file >> temp;
      if(temp != -1L) {
         alloc->dealloc(temp);
      }
      size_t size = get_size(value);
      temp = alloc->alloc(size);
      file->seek(addr);
      *file << temp;
      file->seek(temp);
      *file << value;
      *(this->value) = value;
      return *this;
   }
   operator T() {
      file->seek(addr);
      offset_type address;
      *file >> address;
      if(address != -1L) {
         file->seek(address);
         *file >> *value;
      }
      return *value;
   }
};

template< class T >
class d_ptr {
   offset_type addr;
   bfstream * file;
   d_alloc * alloc;
   d_database * db_ptr;
   T value;

public:
   d_ptr(const offset_type address, d_env * env = p_d_env) {
      addr = address;
      db_ptr = env->get_db();
      alloc = env->get_alloc();
      db_ptr->grab(address, *this);
   }
   d_ptr(const d_ptr & cp) {
      addr = cp.addr;
      db_ptr = cp.db_ptr;
      alloc = cp.alloc;
      db_ptr->grab(addr, *this);
   }
   void grab(bfstream * file, offset_type addr, d_alloc * alloc, d_database * db_ptr) {
      this->file = file;
      this->alloc = alloc;
      this->addr = addr;
      this->db_ptr = db_ptr;
   }
   ~d_ptr() {
   }
   d_ptr & operator=(const d_ptr & cp) {
      addr = cp.addr;
      value = cp.value;
      return *this;
   } 
   d_ptr & operator=(const T & value) {
      file->seek(addr);
      *file << value;
      return *this;
   } 
   void set_address(offset_type addr) {
      this->addr = addr;
   }
   offset_type get_address() {
      return addr;
   }
   T * operator->() {
      file->seek(addr);
      offset_type address;
      *file >> address;
      if(address != -1L) {
         file->seek(address);
         *file >> value;
      }
      return &value;
   }
   d_ptr_assign< T > operator*() {
      file->seek(addr);
      offset_type address;
      *file >> address;
      if(address != -1L) {
         file->seek(address);
         *file >> value;
      }
      return d_ptr_assign< T >(file, alloc, &value, addr);
   }

   operator T() {
      file->seek(addr);
      offset_type address;
      *file >> address;
      if(address != -1L) {
         file->seek(address);
         *file >> value;
      }
      return value;
   }
};

}

#endif
