/**------------------------------------------------------------------------
 * @file
 *
 * Copyright 2001 by the University of Toronto (UT).
 *
 *                       All Rights Reserved
 *
 * Permission to copy and modify this software and its documentation
 * only for internal use in your organization is hereby granted,
 * provided that this notice is retained thereon and on all copies.
 * UT makes no representations as to the suitability and operability
 * of this software for any purpose.  It is provided "as is" without
 * express or implied warranty.
 *
 * UT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
 * SHALL UT BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
 * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * No other rights, including for example, the right to redistribute
 * this software and its documentation or the right to prepare
 * derivative works, are granted unless specifically provided in a
 * separate license agreement.
 *
 * Author: Maxim Trokhimtchouk (trokhim@cs.utoronto.ca)
 *
 * $Log: diskdatabase.hpp,v $
 * Revision 1.1.1.1  2002/03/10 07:38:07  dmac
 * Imported sources
 *
 * Revision 1.1  2001/10/03 20:19:56  dmac
 * Added file
 *
 *
 *-----------------------------------------------------------------------*/

#ifndef __DISKDATABASE_HPP__
#define __DISKDATABASE_HPP__

#include <list>
#include <string>
#include <utility>
#include <iostream>
#include <fstream>
#include "memorydatabase.hpp"

using namespace std;

///This structure is used to denote start and end positions
///of the record with the particular ID.
struct record_pos
{
	long start;
	long end;
	ID id;
};

///Template for disk resident database.
/**
*Database class template used to maintain a disk resident collection of records
*of type T addressed by the identification numbers
*@param T parameter identifies the type of the records in the database.
*/
template <class T> class DiskDatabase
{
private:
	///Contains the name of the database.
	string name;	
protected:
  ///This contains the instant of the data file stream
  fstream datafile; 

  ///Denotes the largest valid ID for this database. 
  ///The smallest valid ID is zero.
  long lastid;

	///Record index.
	/**
	*Contains an index of record positions in the database. NULL item
	*indicates that item does not exist
	*/
	list<record_pos> index;

public:
	///Default construictor.
	DiskDatabase();
	///Destructor.
	virtual ~DiskDatabase();

	///indexing operator
	/**
	*Returns the pair of record data and boolean value indicating
	*whether such record exist in the database
	*@post This function checks whether element with the identification id exist in the database.
	*@param 'id' contains element identifier.
	*@return Returns pair of record class value and boolean value indicating success of the operation.
	*/
	pair<T, bool> operator[](ID id);	
	
	///Adds a record to the database.
	/**
	*Adds a record to the database and returns its id.
	*@post This function does not enforce for the uniquieness of the record values in the database.
	*@param 'record' is a value of the type T to store in the database
	*@return Returns the identification number of the new element added to a database.
	*@return If mistake occured returns NULLID.
	*/
	ID Add(const T& record);
	
	///Removes the record from the database.
	/**
	*Removes the element with the identification id from the database.
	*@post If element with identification id does not exit, function call is ignored.
	*@param 'id' contains the identification of the element to be removed from the database.
	*@return No return values.
	*/
	void Remove(ID id);

	///Removes all of the records from the database.	
	/**
	*Removes all of the records from the database.	
	*All of the memory allocated for the storage of the records is released.
	*@return No return values.
	*/
	void RemoveAll();

	///Determines whether element with 'id' is  contain in the database.
	/**
	*Determines whether element with 'id' is  contain in the database.
	*@param 'id' contains the identification number.
	*@return Returns true if a record with the specified id exist in the database. Return false otherwise.
	*/
	bool Contained(ID id);

	///Creates the database with the name n.
	/**
	*Creates the database with the name n. 
	*@param 'n' contains the name of the database to be created.
	*@return Returns true if creation of the database was successful. Returns false otherwise.
	*/
	bool Create(const string& n);

	///Returns the name of the database that was specified during creation of the database.
	/**
	*Returns the name of the database that was specified during creation of the database.
	*@return Returns the name of the database.
	*/
	string GetDatabaseName();
	
	///Reads database from a stream.
	/**
	*Reads database from a stream.
	*@param 'is' refers to an instance of a stream that will be used for loading the database
	*@return returns a reference to a stream used for loading the database.
	*/
	istream& Read(istream& is);

	///Writes database to a file
	/**
	*Writes database to a stream.	
	*@param 'os' refers to an instance of a stream that will be used to store the database
	*@return returns a reference to a stream used to store the database.
	*/
	ostream& Write(ostream& os);
	
	///Updates the database by removing all of the free space between records in the database file
	void Update();

	///Closes the database. Does not store index to the stream. You should call Write before hand
	void Close();
protected:
  ///Reads record from datafile
  /**
  *Reads record from datafile
  *@param s denotes the starting position of the record in the data file.
  *@param e denotes the final position of the record in the data file.
  *@return returns pair of the record read and bool value which
  *@return indicate whether operation was sucsessful. True if successful.
  */
  pair<T, bool> ReadRecord(long s, long e);

  ///Writes the record to the database file.
  /*Writes the record to the database file.
  *@param s denotes starting position of the record.
  *@param record is a reference to a record to be written
  *@return If successful returns record_pos structure which contains
  *@return first and last position in the file taken up by record.
  *@return In case of an error, first position of the record return by the
  *@return function is equal to -1.
  */
  record_pos WriteRecord(long s,const T& record);
};


//implementation
#include "diskdatabase.hxx"

#endif //__DISKDATABASE_HPP__
