/**------------------------------------------------------------------------
 * @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
 * 
 * $Log: Stats.h,v $
 *
 *-----------------------------------------------------------------------*/
#ifndef __STATS_H__
#define __STATS_H__

#include <DAGDatabase.h>
#include <DAG.h>
#include <BasicUtils.h>
 
// NOT_SET is a big negative number that is easy to spot when computing stats
#define NOT_SET -100

#define	MAXPOS 10000
#define	MAXVIEW 128

using namespace dml;

class STATINFO
{
public:
	enum DATA_FORMAT {UOFT_FORMAT = 1, PBS_FORMAT, KIMIA_FORMAT};

public:
	bool bCompViewStats;
    leda_array<MatchInfo> matchList;
    int nParamsToSet;

	class INFOVAR
	{
		int nDAGId;					//!< ID of the dag.
		double dSimilarity;	        //!< Assigned indexing or matching similarity
		int nDBId;                  //!< ID of the database that containts the DAG
		int nQueryDBId;             //!< ID of the query database
		
		int nBestRankingPosition;   //!< Best position in either the indexing or matching ranking
		int nWorstRankingPosition;  //!< Worst position in either the indexing or matching ranking

		int nBestIdxPos;      		//!< Best position in the index (only if appropiate)
		int nWorstIdxPos;     		//!< Worst position in the index (only if appropiate)

	public:
		INFOVAR() { Clear(); }
		void Clear();
		int GetDAGId() const { return nDAGId; }

		void SetRankPos(int currentRankPos, const leda_array<MatchInfo>& rankList);

		void SetRankPos(int currentRankPos, const leda_array<MatchInfo>& rankList, 
			const INFOVAR& queryPos);

		void SetIdxPos(int currentIdxPos, const leda_array<MatchInfo>& idxRankList);

		void SetIdxPos(int currentIdxPos, const leda_array<MatchInfo>& idxRankList, 
			const INFOVAR& queryPos);

		bool IsNotSet() const;

		static int GetBestPos(int i, const leda_array<MatchInfo>& matches);
		static int GetWorstPos(int i, const leda_array<MatchInfo>& matches);

		friend std::ostream& operator<<(std::ostream &os, const INFOVAR& v);
	};

    INFOVAR queryObj;	//!< query object
    INFOVAR rightClass; //!< first object of the same class than the query object
    INFOVAR wrongClass; //!< first object of a different class than the query object
    INFOVAR neigType1;  //!< type-3 closest neig. in the viewing sphere
    INFOVAR neigType2;  //!< type-9 closest neig. (including the type-3 closest neigbours)
    INFOVAR topRanked;  //!< info of the first ranked DAG, whatever the DAG is.

	double m_compTime;

	STATINFO() { bCompViewStats = false; }

	void InitStats();

	const double& GetCompTime() const
	{
		return m_compTime; 
	}

	void SetCompTime(const double& t)
	{
		m_compTime = t; 
	}

	/*!
		@brief Return number of parameters (INFOVAR's) that need to be set
	*/
	int GetParamCount() const { return nParamsToSet; }

	void ComputeStats(const DAG* pQueryDag, DATA_FORMAT formatId = UOFT_FORMAT);

	void ComputeStatsFromKimiaData(const DAG* pQueryDag);
	void ComputeStatsFromPBSData(const DAG* pQueryDag);
	void ComputeStatsFromUofTData(const DAG* pQueryDag);

	void ComputeCrossRankingIdxStats(const STATINFO& matStats);
	int FindDAGPos(const DAG* pQueryDag) const;
	int FindDAGPos(int nDAGId) const;

	static void RemoveQueryExemplar(const DAG* pQueryDag, leda_array<MatchInfo>& rankList);

	static void WriteHeader(std::ostream& os, int nFileIdx, int nIdxKBest, double dMaxOcclusionRate);

	static void Write(std::ostream& os, int i, int nViewNum, const STATINFO& idxSt, const STATINFO& matSt,
		double dCompTime, double dOcclusionRate = 0);

	static void WriteTailer(std::ostream& os);

	friend std::ostream& operator<<(std::ostream& os, const STATINFO& v);
};

bool GetClosestViews(int i, int res, int& a, int &b, int &c);
bool GetClosestViews2(int i, int res, SmartArray<int>& neigs, bool bIncludeFirstLevel);
SmartArray<int> GetClosestViewsByRange(int i, int res, const double& range);
SmartArray<int> GetSymmetricViewMap();

#endif //__STATS_H__
