#ifndef DISTANCET_H
#define DISTANCET_H

#include "calcul.h"

enum distanceType {
	euklid = 1,
	manhattan = 2,
	csiChroma = 3,
	csiChord = 4
};

///Contains pointer to currently used distance function which is internally used for 
struct distancet {

	///Contains currently used distance. 
	union DISTANCE {
		DISTANCE_classic classic;			///< classic distance (calculated from two vectors)
		DISTANCE_csiChroma csiChroma;		///< chroma distance (cover song identification)
		DISTANCE_csiChord csiChord;			///< chord distance (cover song identification)
	} dist;									///< pointer to distance function

	int type;								///< distance type

	///Default constructor
	//distancet() {}
	///Initialization constructor
	///@param[in] type_ distance type
	distancet(int type_) : dist(), type(0)
	{
		switch (type_)
		{
			case distanceType::euklid: dist.classic = calcul::distanceDtwEuklid;	
				type = 1;	
				break;
			case distanceType::manhattan: dist.classic = calcul::distanceDtwManhattan;
				type = 1;	
				break;
			case distanceType::csiChroma: dist.csiChroma = calcul::distanceDtwCsiChroma;
				type = 2;	
				break;
			case distanceType::csiChord: dist.csiChord = calcul::distanceDtwCsiChord;
				type = 3;	
				break;		
		}
	}

	///Calculates distance based on distance type.
	///@param[in] input data
	///@param[in] i index
	///@param[in] j index
	///@return distance between two time series points.
	double getDistance(inputMethod const &input, unsigned i, unsigned j) const
	{
		unsigned row = i - 1;
		unsigned col = j - 1;

		if (type == 1)
		{
			return dist.classic(input.A[row], input.B[col]);
		}
		else if (type == 2)
		{
			return dist.csiChroma(input.A[row], input.B[col], 0.07);
		}
		else 
		{
			return dist.csiChord(input.A[row], input.B[col], input.A2[row], input.B2[col]);
		}
	}
};

#endif //DISTANCET_H