/**------------------------------------------------------------------------
 * @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: Diego Macrini
 *
 *-----------------------------------------------------------------------*/

#ifndef __MATCHING_RESULTS_H__
#define __MATCHING_RESULTS_H__
 
#include <DAGDatabase.h>
#include <DirWalker.h>
#include "InfoStructures.h"
#include "Matching.h"

class MatchingResults
{
	const ShapeMatchingParams& m_matchInfo;

	std::fstream m_resultsFile;
	std::fstream m_statsFile;

	int m_statsFileID;

	int m_nShowResults;

	int m_nMaxModelsPerQuery;

	DAGDatabase* m_pQueryDB;
	DAGDatabase* m_pModelDB;

	std::list< std::list<DAGPtr> > m_dags;

public:
	MatchingResults(const ShapeMatchingParams& matchInfo)
		: m_matchInfo(matchInfo)
	{
		m_statsFileID = -1;

		m_nShowResults = m_matchInfo.showResults;

		m_nMaxModelsPerQuery = 10;

		m_pQueryDB = NULL;
		m_pModelDB = NULL;
	}

	void CreateFiles(std::string fileName, std::string modelDBName,
		const char* szFileNameSubfix)
	{
		if (fileName != modelDBName)
			fileName += "_" + modelDBName;

		if (szFileNameSubfix != NULL)
			fileName += szFileNameSubfix;

		if (m_matchInfo.saveResults)
		{
			std::string resultsFileName = fileName;

			resultsFileName += "_results.log";

			DirWalker::MakeNameUnique(&resultsFileName);

			std::cerr << "Writing output to " << resultsFileName << "...\n";

			m_resultsFile.open(resultsFileName.c_str(), std::ios::out | std::ios::trunc);
			
			// Write all the current command-line parameter values
			//Print(m_resultsFile);
		}

		if (m_matchInfo.computeStats)
		{
			DirWalker dw;
			std::string statsFileName = fileName;

			statsFileName += "_stats.m";

			dw.AddToPath(m_matchInfo.statsOutDir);

			if (DirWalker::IsDirectory(dw.path.c_str()))
			{
				ShowStatus1("Stats directory is", dw.path);

				dw.AddToPath(statsFileName.c_str());
				statsFileName = dw.path;
			}
			else
			{
				ShowError1("Invalid directory", dw.path);
			}

			m_statsFileID = DirWalker::MakeNameUnique(&statsFileName);

			ShowStatus1("Stats file is", statsFileName);
			
			m_statsFile.open(statsFileName.c_str(), std::ios::trunc | std::ios::out);

			STATINFO::WriteHeader(m_statsFile, m_statsFileID, 
				m_matchInfo.idxKBest, 0 /*m_maxOcclusionRate*/);
		}
	}

	void Init(DAGDatabase* pQueryDB, DAGDatabase* pModelDB,
		const char* szFileNameSubfix = NULL)
	{
		m_pQueryDB = pQueryDB;
		m_pModelDB = pModelDB;

		CreateFiles(DirWalker::GetName(pQueryDB->GetFileName()), 
			DirWalker::GetName(pModelDB->GetFileName()),
			szFileNameSubfix);
	}

	/*!
		If bSaveStats is true, matching statistics are computed and saved
		as long as m_matchInfo.computeStats is also true.
	*/
	void Init(const char* szQueryName, const char* szModelName,
		const char* szFileNameSubfix = NULL)
	{
		m_pQueryDB = NULL;
		m_pModelDB = NULL;

		CreateFiles(szQueryName, szModelName, szFileNameSubfix);
	}

	void Close()
	{
		if (m_matchInfo.computeStats)
			STATINFO::WriteTailer(m_statsFile);

		if (m_nShowResults == 2)
			ShowResultsAsTable();
	}

	bool HasStatsFile() const
	{
		return (m_statsFile.is_open());
	}

	std::fstream& GetStatsFile()
	{
		return m_statsFile;
	}

	void Add(const DAG* pDAG, const STATINFO& idxSt, const STATINFO& matSt,
		int dagID = -1)
	{
		if (m_resultsFile.is_open())
			SaveResults(pDAG, *m_pModelDB, idxSt, matSt, m_resultsFile);

		if (m_nShowResults == 1)
		{
			if (!ShowResults(pDAG, matSt, *m_pQueryDB, *m_pModelDB, dagID))
				m_nShowResults = 0;
		}
		else if (m_nShowResults == 2)
			CopyResults(pDAG, matSt, *m_pQueryDB, *m_pModelDB, dagID);

		if (m_statsFile.is_open())
			STATINFO::Write(m_statsFile, dagID, pDAG->GetViewNumber(), idxSt, matSt,
				matSt.GetCompTime(), 0 /*dOcclusionRate*/);
	}

	void CopyResults(const DAG* pTarget, const STATINFO& matSt, 
		DAGDatabase& queryDB, DAGDatabase& modelDB, int nQueryID);

	void ShowResultsAsTable();
};

#endif // __MATCHING_RESULTS_H__
