/**------------------------------------------------------------------------
 * @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: matchingdatabase.hpp,v $
 * Revision 1.1.1.1  2002/03/10 07:38:07  dmac
 * Imported sources
 *
 * Revision 1.2  2002/01/15 16:48:22  dmac
 * Bugs fixed
 *
 * Revision 1.1  2001/10/03 20:19:57  dmac
 * Added file
 *
 *
 *-----------------------------------------------------------------------*/

#ifndef __MATCHINGDATABASE_HPP__
#define __MATCHINGDATABASE_HPP__

#include <set>
#include <string>
#include <list>
#include <map>
#include <vector>
#include <HnSRTree/HnSRTreeFile.hh>

#include <LEDA/string.h>
#include <LEDA/queue.h>
#include <LEDA/list.h>
#include <LEDA/graph_alg.h>
#include <LEDA/d_array.h>
#include <LEDA/tuple.h>

#include "DAG.h"
#include "DAGNode.h"
#include "SmartArray.h"

#include "memorydatabase.hpp"

using namespace std;

///This constant defines the minimal dimention for the near neigbour search database.
const int  Min_NND_Dimension = 1;

///DAGView structure.
/**
*Class that contains data relevant to a particular view.
*/
class DAGView
{
public:
	DAGView() {};
	DAGView(ID t, ID r, ID g) : type(t), region(r), graph(g) {};
	ID type; ///<ID of the type of this view.
	ID region; ///<ID of the region that contains this view.
	ID graph; ///<ID of the graph that represents this view.

	///Output operator used to write view data to a stream
	ostream& write(ostream& os);

	///Input operator used to read view data from a stream
	istream& read(istream& is);
};


///DAGPrototype structure
/**
*Class that contains the data relevant to a prototype view.
*/
class DAGPrototype
{
public:
	DAGPrototype(){};
	DAGPrototype(const DAGView& v) : view(v) {};

	DAGView view; ///<Contains the view data for this prototype.
	int count; ///<Contains number of times this prototype was seen.
	///Output operator used to write prototype data to a stream
	ostream& write(ostream& os);

	///Input operator  used to read prototype data from a stream
	istream& read(istream& is);
};

///DAGType structure
/**
*Class that contains data relevant to a particular type.
*/
class DAGType
{
public:
	DAGType(){};
	DAGType(string& n) : name(n) {};

	string name; ///<Contains name of the type.
	int count; ///<Number of time this particular type has been observed.
	///Output operator used to write type data to a stream
	ostream& write(ostream& os);

	///Input operator  used to read type data from a stream
	istream& read(istream& is);
};




///DAGRegion class
/**
*Class that is used to mantain view region of the DAG views.
*An id for each view contained in the region is stored in the 'views' vector.
*A view can be added or delete from the region by means of the vector 'views'.
*This class also implements selection of the prototype for this region.
*/
class DAGRegion
{
public:
	///vector of all views (referenced by their ID) belonging to this region
	vector<ID> views;

	///Retrieves the prototype for this region.
	/**
	*Retrieves the prototype for this region.
	*@return Returns the data for a view that is a prototype for this region.
	*THIS FUNCTION IS CURRENTLY NOT IMPLEMENTED
	*/
	DAGView GetPrototype();

	///This operator is used to write the region to a stream.
	/**
	*This operator is used to read the region from a stream.
	*@param os refers to a stream that is used to write the region data.
	*@param region refers to the region data to be stored in the stream.
	*@return Returns reference to a stream.
	*/
	ostream& write(ostream& os);
	
	///This operator is used to read the region from a stream.
	/**
	*This operator is used to read the region from a stream.
	*@param is refers to a stream that is used to read the region data.
	*@param region refers to the region data to be read from the stream.
	*@return Returns reference to a stream.
	*/
	istream& read(istream& is);
};

///DAGSearchRecord structure
/*
*This structure is used to contain data in the near neighbour search database
*/
struct DAGSearchRecord
{
	ID prototype; ///<Identification number of the prototype to which the node belongs to.
	ID node; ///<ID of the node, TSV of which is contained in NND
};

struct DAGSearchRecordEx : public DAGSearchRecord
{
	TSV nodeTSV;

	void operator=(const DAGSearchRecord& rhs)
	{
		prototype = rhs.prototype;
		node = rhs.node;
	}
};

///Template for DAGTypeDatabase class
/**
*This class manages a collection of DAG types referenced by an index.
*@param baseclass defines the base class for this template
*/
template<class baseclass>
class DAGTypeDatabase : public baseclass
{
	///This map contains the map from the name to the DAG type id.
	map<string,ID> namemap;
public:
	///Default constructor.
	DAGTypeDatabase();

	///Destructor.
	virtual ~DAGTypeDatabase();

	///Finds id of the type with particular name.
	/**
	*Returns an id of the type with a particular name.
	*@param name refers to the name of the type to be found.
	*@return Returns identification number of the type with the specified name.
	*@return If there was no type found with the specified name, then NULLID is returned.
	*/
	ID Find(string& name);

	///Adds the record to the database.
	/**
	*Adds the type record to the database.
	*@param record contains the reference to the type data that 
	*@param record is to be added to the database.
	*@return Returns the id of the newly added record.
	*/
	ID Add(const DAGType& record);

	///Removes the element from the database
	/**
	*Removes the element from the DAGTypeDatabase.
	*@param id contain the identification number of the 
	*@param id type record that is to be removed from the database.
	*@return Returns no values.
	*/
	void Remove(ID id);

	///Removes all records from the database.
	/**
	*Removes all records from the database.
	*@return Returns no values.
	*/
	void RemoveAll();

	///Reads database from a stream.
	/**
	*This function is used to read the type database from a stream.
	*@param is refers to the stream used to read the type database.
	*@return Returns a reference to a stream used to read the type database.
	*/
	istream& Read(istream& is);

	///Writes database to a stream.
	/**
	*This function is used to write the type database to a stream.
	*@param is refers to the stream used to write the type database.
	*@return Returns a reference to a stream used to write the type database.
	*/
	ostream& Write(ostream& os);
public:
	///contains number of views seen by the system
	long views_seen;
};

//Contains template implementation
#include "matchingdatabase.hxx"

///Near neighbour search database used to index the DAG prototypes
/*
*This an encupsulating class for a near neigbour search database.
*It defines the interface for functions required by the indexer and
*implements them using an adopted near neighbour search database.
*/
class DAGSearchDatabase
{
	///Near neigbour database data
	/**
	*This structure contains the instance of the NND class,
	*as well as the name of a file in which the database is stored.
	*This structure also stores the number of dimensions in NND.
	*/
	class NND
	{
	public:
		HnSRTreeFile data; ///<Instance of the actual NND class.
		string name; ///<Name of the database file.
		int dimension; ///<Number of dimensions in the database
	} nnd;
	
public:
	///Default constructor.
	DAGSearchDatabase();
	
	///Destructor.
	virtual ~DAGSearchDatabase();

	///Adds prototype.
	 /**
	 *Adds the prototype to the database.
	 *@pre No error checking is performed.
	 *@param prototype contains identification number of the 
	 *@param prototype prototype view described which is to be added to NND.
	 *@param dag refers to the instance of the DAG class 
	 *@param dag that describes the prototype view to be addded to the database.
	 *@return No return values.
	 */
	 void Add(ID prototype, const DAG& dag);

	///Removes prototype.
	/**
	*Removes the prototype from the search database.
	 *@pre No error checking is performed.
	 *@param prototype contains identification number 
	 *of the prototype view which is to be removed from NND.
	 *@param dag refers to the instance of the DAG class that 
	 *describes the prototype view to be removed from the database.
	 *@return No return values.
	*/
	void Remove(ID prototype, DAG& dag);

	///Finds closest nodes.
	/**
	*Finds n nodes closest to quety node.
	*@param querynode refers to the node for which n closest
	* nodes will be found in the database.
	*@param n contains number of neighbours to be retrieved during the search.
	*@return the pointer to the list of nodes found closest to the 
	*@return query node. If n < 1 then NULL is return.
	*/
	SmartArray<DAGSearchRecordEx> GetClosest(const DAG& dag, const leda_node& querynode, int n);

	///Creates the database.
	/**
	*Creates the database with the file name 'name' and dimensions 'dim'.
	*@pre name must be a valid file name.
	*@param name contains file name of the database to be created.
	*@param dim is the number of dimensions of the new database.
	*@return Returns true if database was created successfully, false otherwise.
	*/
	bool Create(string& name, int dim);

	///Opens the database.
	/**
	*Opens the database with the file name 'name'.
	*@pre name must be a valid file name.
	*@param name contains file name of the database to be created.
	*@return Returns true if database was opened successfully, false otherwise.
	*/
	bool Open(string& name);

	///Read the database from the stream.
	/**
	*Reads database parameters from a stream and loads the database.
	*@param is refers to a stream which is used to load the database.
	*@return Returns reference to a stream used to load the database.
	*@return If the error occured during an attempt to load the database, 
	*@return state of the stream will be set to fail.
	*/
	istream& Read(istream& is);

	///Writes the database from a stream
	/**
	*Writes database parameters to a stream. This parameters can latter 
	*be used to read the database
	*@param os refers to a stream which is used to write the database parameters.
	*@return Returns reference to a stream used to write the database parameters.
	*/
	ostream& Write(ostream& os);
private:
  static HnPoint TSVtoHnPoint(const TSV& tsv);
  static TSV HnPointToTSV(const HnPoint& pt);
};

#endif
