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

#include <fstream.h>
#include "matchingsystem.hpp"
#include <algorithm>
#include "DAGNode.h"
#include "BasicUtils.h"

template <class DAG>
MatchData<class DAG>::MatchData()
{
}

template <class DAG>
MatchData<class DAG>::MatchData(ID prot, typename DAG::distance_type dist)
{
	prototype = prot;
	distance = dist;
}

template <class DAG>
DAGMatchingDatabase<class DAG>::DAGMatchingDatabase()
{
}

template <class DAG>
DAGMatchingDatabase<class DAG>::~DAGMatchingDatabase()
{
}

template <class DAG>
bool DAGMatchingDatabase<class DAG>::Write(string& filename)
{
	fstream f;

	f.open(filename.c_str(), ios::in | ios::out | ios::binary);
	if(f.fail()) return false;
DBG_MSG("1");

	if(!prototypes.Write(f)) return false;
DBG_MSG("2");
	if(!views.Write(f)) return false;
DBG_MSG("3");
	if(!regions.Write(f)) return false;
DBG_MSG("4");
	if(!types.Write(f)) return false;
DBG_MSG("5");
	if(!DAGs.Write(f)) return false;
DBG_MSG("6");
	if(!index.Write(f)) return false;
DBG_MSG("7");
	
	f.close();

	return true;
}

template <class DAG>
bool DAGMatchingDatabase<class DAG>::Read(string& filename)	
{
	fstream f;

	f.open(filename.c_str(), ios::in | ios::out | ios::binary | ios::nocreate);
	if(f.fail()) return false;
DBG_MSG("1");
	if(!prototypes.Read(f)) return false;
DBG_MSG("2");
	if(!views.Read(f)) return false;
DBG_MSG("3");
	if(!regions.Read(f)) return false;
DBG_MSG("4");
	if(!types.Read(f)) return false;
DBG_MSG("5");
	if(!DAGs.Read(f)) return false;
DBG_MSG("6");
	if(!index.Read(f)) return false;
DBG_MSG("7");

	f.close();

	return true;
}

template <class DAG>
DAGMatcher<class DAG>::DAGMatcher(DAGMatchingDatabase<DAG>& mdata):data(mdata)
{
}

template <class DAG>
DAGMatcher<class DAG>::~DAGMatcher()
{
}

template <class DAG>
void DAGMatcher<class DAG>::SortByClosest(DAG& dag, vector< MatchData<DAG> >& m_list)
{
  int x;
  pair<DAG, bool> temp_a;
  pair<DAGPrototype, bool> temp_b;
//  DAG d1;
//  DAG d2;


//  cout << d1.ReadFromXMLFile("doll.xml") << endl;
// cout << d2.ReadFromXMLFile("plane.xml") << endl;

  //Calculate an actual distance between image and database models
  for(x = 0; x < m_list.size(); x++)
    {
	  temp_b = data.prototypes[m_list[x].prototype];
	  if(!temp_b.second) DBG_MSG("couldn't retrieve prototype")

	  temp_a = data.DAGs[temp_b.first.view.graph];
	  if(!temp_b.second) DBG_MSG("couldn't retrieve dag")

//	  Distance(d1, d2);
DBG_MSG("Before")
	  NODE_MAP nodeMap;
      m_list[x].distance = DAG::Distance(dag, temp_a.first, nodeMap, DAG::INV_NODE_DIST_AND_TSV);
DBG_MSG("After")
    }

  //Sort prototypes by distance
  sort(m_list.begin(), m_list.end());
}

template <class DAG>
void DAGMatcher<class DAG>::GetSimilar(DAG& dag, vector< MatchData<DAG> >& m_list, int& k)
{
  leda_node i, compnode;
  int p;
	
  pair<DAGPrototype, bool> temp_a;
  pair<DAG, bool> temp_b;


  //This is the object model accumulator
  map<ID, typename DAG::distance_type> ac;

  list<DAGSearchRecord>* c_list;


  //defines a search record iterator	
  typename list<DAGSearchRecord>::iterator srecord;
	
  //defines an iterator of a object model bin
  //for now I am using a map class which has worst case complexity of log(n)
  //I a future I plan to implement a hash map
  typename map<ID, typename DAG::distance_type>::iterator bincount;

	i = dag.first_node();

	while (i != nil)
  //This accumulates evidence for every node
  //forall_nodes(i, dag);
    {
      //gets k closest neighbours of that node in the index database
      c_list = data.index.GetClosest(dag, i, k);

	  if(c_list == NULL)
	  {
		  m_list.clear();
		  return;
	  }

      //For each neighbour perform object model count
      for(srecord = c_list->begin(); srecord != c_list->end(); srecord++)
	  {
		temp_a = data.prototypes[srecord->prototype];
		temp_b = data.DAGs[temp_a.first.view.graph];

		  //retrive the node from the database for comparison
		  compnode = temp_b.first.GetNode(srecord->node);

		  //Check if the labels of the two nodes correspond
		  if(temp_b.first.GetNodeLbl(compnode) == dag.GetNodeLbl(i))
			{

			  //retrive a count for that prototype
			  bincount = ac.find(srecord->prototype);


			  //Check if count exits, if it doesn't than create new
			  if(bincount == ac.end())
				{

				  bincount = ac.insert(map<ID, typename DAG::distance_type>::value_type(srecord->prototype, 0.0)).first;

				}

			  //add the weight to the bin
			  bincount->second += dag.NodeSimilarity(i, temp_b.first, compnode, DAG::INV_NODE_DIST_AND_TSV);
			}
	  }

      delete c_list;

	  i = dag.succ_node(i);
    }
	
  //build a heap and pick out k closest models
  //vector to contain the heap
  vector< MatchData<DAG> > md;

  //copy from map to vector
  for(bincount=ac.begin(); bincount!=ac.end();bincount++)
    {
      md.push_back(MatchData<DAG>(bincount->first, bincount->second)); 
    }
	
  p = md.size();
  if(p < k) k = p;

  m_list.clear();
  m_list.resize(k);


  partial_sort_copy(md.begin(), md.end(), m_list.begin(), m_list.end());
}


template <class DAG>
vector< MatchData<DAG> > DAGMatcher<class DAG>::GetMatch(DAG& dag, int k = 3)
{
  
}

template <class DAG>
void DAGMatcher<class DAG>::Update(ID id)
{
}


