#ifndef _D_VAR_H
#define _D_VAR_H

#include "disk_tools.h"
#include "d_ptr.h"

namespace disk_tools {

template< class T >
class d_var {
   offset_type address;
   d_alloc * alloc;
   bfstream * file;
   d_database * db;
   d_env * env;

public:
   d_var(const offset_type & str, d_env * env = p_d_env) {
      address = str;
      this->env = env;
      db = env->get_db();
      file = env->get_file();
      alloc = env->get_alloc();
      db->grab(address, *this);
   }

   d_var(d_env * env = p_d_env) {
      address = create_var(env->get_db());
      this->env = env;
      db = env->get_db();
      file = env->get_file();
      alloc = env->get_alloc();
      db->grab(address, *this);
   }

   d_var(offset_type & off, d_env * env = p_d_env) {
      address = off;
      this->env = env;
      db = env->get_db();
      file = env->get_file();
      alloc = env->get_alloc();
      db->grab(address, *this);
   }

   d_var(const string & name, d_env * env = p_d_env) {
      this->env = env;
      db = env->get_db();
      file = env->get_file();
      alloc = env->get_alloc();
      db->grab(name, *this);
   }

   d_var(const d_var & cp) {
      address = cp.address;
      alloc = cp.alloc;
      file = cp.file;
      db = cp.db;
      env = cp.env;
   }

   ~d_var() {
   }

   d_var & operator=(const d_var & dvar) {
      address = dvar.address;
      alloc = dvar.alloc;
      file = dvar.file;
      db = dvar.db;
      env = dvar.env;
      return *this;
   }

   void grab(bfstream * file, offset_type addr, d_alloc * alloc, d_database * db_ptr) {
      this->file = file;
      this->alloc = alloc;
      this->address = addr;
      this->db = db_ptr;
   }

   d_var & operator=(const T & value) {
      file->seek(address);
      offset_type temp;
      *file >> temp;
      if(temp != -1L) {
         alloc->dealloc(temp); 
      }
      temp = alloc->alloc(get_size(value)); 
      file->seek(temp);
      *file << value;
      file->seek(address);
      *file << temp;
      return *this;
   }

   T get_data() {
      file->seek(address);
      offset_type temp;
      *file >> temp;
      T data;
      if(temp != -1L) {
         file->seek(temp);
         *file >> data;
      }
      return data;
   }

   operator T() {
      return get_data();
   }

   offset_type get_address() const {
      return address;
   }

   void set_address(const offset_type & address) {
      this->address = address;
   }

   d_ptr< T > operator&() const {
      return d_ptr< T >(address, env);
   }

   d_env * get_env() {
      return env;
   }
};

}

#endif /* _D_VAR_H */
