/**------------------------------------------------------------------------
 * @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: memorydatabase.hxx,v $
 * Revision 1.1.1.1  2002/03/10 07:38:08  dmac
 * Imported sources
 *
 * Revision 1.1  2001/10/03 20:19:57  dmac
 * Added file
 *
 *
 *-----------------------------------------------------------------------*/
#include "BasicUtils.h"

template<class T>
MemoryDatabase<T>::MemoryDatabase()
{
	name = "";
}

template<class T>
MemoryDatabase<T>::~MemoryDatabase()
{
	RemoveAll();
}

template<class T>
pair<T, bool> MemoryDatabase<T>::operator[](ID id)
{
	//Check whether database exist
	if(name == "") return pair<T, bool>(T(),false);
	
	//Check whether record with such id exist
	if(Contained(id))
	{
		//if does return the first item of the pair, 
		//which is a pointer to template class
		return pair<T, bool>(*(records[id]), true);
	}

	//if doesn't return NULL
	return pair<T, bool>(T(),false);
}

template<class T>
ID MemoryDatabase<T>::Add(const T& record)
{
	if(name == "") return NULLID;
	
	ID id;
	T* item = new T;

	//copy data in record to memory pointed by item
	*item = record;
	
	//search for an empty array item 
	for(id = 0;id < records.size() && records[id] != NULL; id++);
	
	//if found an empty item then add record there, else insert new
	if(id < records.size())
	{
		//set array pointer to item 
		records[id] = item;
	}
	else
	{
		records.push_back(item);
	}

	return id;
}

template<class T>
void MemoryDatabase<T>::Remove(ID id)
{
	if(name == "") return;
	
	if(Contained(id))
	{
		//release the memory accupied by record with the id
		delete records[id];
		records[id] = NULL;
	}

	//if the record is the last in the database, then delete it
	if(id + 1 == records.size())
	{
		records.pop_back();
	}
}

template<class T>
void MemoryDatabase<T>::RemoveAll()
{
	if(name == "") return;
	
	ID id;

	//for every record in the database release the memory if the record is not empty
	for(id = 0; id < records.size(); id++)
	{
		if(records[id] != NULL) 
		{
			//release the memory accupied by record with the id
			delete records[id];
			records[id] = NULL;
		}
	}

	//delete all items from the vector records
	records.clear();
}

template<class T>
bool MemoryDatabase<T>::Contained(ID id)
{
	if(name == "") return false;
	
	if(id > records.size() || id < 0 || records[id] == NULL)
		return false;
	else
		return true;
}

template<class T>
string MemoryDatabase<T>::GetDatabaseName()
{
	return name;
}

template<class T>
bool MemoryDatabase<T>::Create(const string& n)
{
	RemoveAll();
		
	name = n;
	return true;
}

template<class T>
std::istream& MemoryDatabase<T>::Read(std::istream& is)
{
	T* item;
	bool doesexist;
	ID size, i;
	char* namestr;
	size_t strlength;

	//remove all existing records
	RemoveAll();
	
    //read the name of the database
	is.read(&size,sizeof(size_t));

	namestr = new char[size];
    is.read(namestr,size);
	name = string(namestr);
	delete [] namestr;

	cout << name << endl;

	//read in the size of the database
	is.read(&size, sizeof(size_t));
	cout << "dude1" << endl;
	cout << "dudes size is " << size << endl;
	records.resize(size);
	cout << "dude2";

	if(!is) 
	{
		name = "";
		return is;
	}

	for(i=0; i < size; i++)
	{
		is.read(&doesexist,sizeof(bool));

		if(doesexist)
		{
			//allocate memory for a new item in the database
			item = new T;
			//read the record and put it into database
			item->read(is);
			records[i] = item;
		}
		else
		{
			records[i] = NULL;
		}
	}

	return is;
}

template<class T>
std::ostream& MemoryDatabase<T>::Write(std::ostream& os)
{
DBG_MSG("in Write 1");
	if(name == "")
	{
		os.fail();
		return os;
	}
	
	T* item;
	bool doesexist;
	ID i;
	size_t t;
DBG_MSG("in Write 2");

	//write the name of the database
	t = name.length() + 1;
	os.write(&t, sizeof(size_t));
	os.write(name.c_str(), t);	
DBG_MSG("in Write 3");

	//write the size of the record container
	t = records.size();
	os.write(&t, sizeof(size_t));

DBG_MSG("in Write 4");
	if(!os) return os;

	for(i = 0; i < t; i++)
	{
DBG_MSG("in Write 5");
		if(records[i] == NULL)
		{
			doesexist = false;
			os.write(&doesexist,sizeof(bool));
		}
		else
		{
			doesexist = true;
			os.write(&doesexist,sizeof(bool));
			item = records[i];
DBG_MSG("in before Write");
			item->write(os);
DBG_MSG("in after Write");
		}
	}

	return os;
}
