//----------------------------------------------------
/**
	\file		misc.h
	\ingroup	general
	\ingroup	all

	\brief		Knihovna obecnych funkci
				<<< ALL >>>

	\author		ConTeK s.r.o., Pavel Bazika
	\version	01.01
	\date		10.03.2007
*/
//----------------------------------------------------

#ifndef _MISC_H_
#define _MISC_H_

#include <ctktypes.h>


typedef struct _FLOAT_POINT
{
	float_t		X;
	float_t		Y;
} FLOAT_POINT;


typedef struct _POLYLINE
{
	unsigned	Count;

	FLOAT_POINT	* Points;
} POLYLINE;



//----------------------------------------------------
/**
	\brief	Zkontroluje a pripadne opravi hodnotu promene do intervalu <_min, _max>

	\param	_var		Promena
	\param	_min		Minimalni hodnota
	\param	_max		Maximalni hodnota
*/
//----------------------------------------------------

#define EnsureRange(_var, _min, _max) \
	do { \
		if ((_var) > (_max)) \
		{ \
			(_var) = (_max); \
		} \
		else if ((_var) < (_min)) \
		{ \
			(_var) = (_min); \
		} \
	} while (0)


//----------------------------------------------------
/**
	\brief	Navrati zkontrolovanou hodnotu v intervalu <_min, _max>

	\param	_val		Hodnota
	\param	_min		Minimalni hodnota
	\param	_max		Maximalni hodnota
*/
//----------------------------------------------------

#define EnsureRange_(_val, _min, _max) \
	(_val) > (_max) ? \
		(_max) : \
		(_val) < (_min) ? \
			(_min) : \
			(_val)


//----------------------------------------------------
/**
	\brief	Zkontroluje, zda hodnota je z intervalu <_min, _max>

	\param	_val		Hodnota
	\param	_min		Minimalni hodnota
	\param	_max		Maximalni hodnota
*/
//----------------------------------------------------

#define InRange(_val, _min, _max) \
	(((_val) >= (_min)) && ((_val) <= (_max)))


//----------------------------------------------------
/**
	\brief	Absolutni hodnota cisla
*/
//----------------------------------------------------

#define abs2(_a) \
	(((_a) >= (0)) ? (_a) : (-_a))

//----------------------------------------------------
/**
	\brief	Minimum dvou cisel
*/
//----------------------------------------------------

#define min2(_a, _b) \
	(((_a) <= (_b)) ? (_a) : (_b))


//----------------------------------------------------
/**
	\brief	Maximum dvou cisel
*/
//----------------------------------------------------

#define max2(_a, _b) \
	(((_a) >= (_b)) ? (_a) : (_b))


//----------------------------------------------------
/**
	\brief	Prevod na boolean
*/
//----------------------------------------------------

#define bool2(_b) \
	((_b) ? TRUE : FALSE)


//----------------------------------------------------
/**
    \brief	Funkce signum
*/
//----------------------------------------------------
#define sign2(_x) \
    (_x > 0) ? 1 : ((_x < 0) ? -1 : 0)
    
//----------------------------------------------------
/**
    \brief	Makro pro oznaceni nepouziteho parametru (odstrani "unused parameter" warning)
*/
//----------------------------------------------------    

#if defined(__GNUG__) || defined(__GNUC__)
#define UNUSED_ALWAYS(_x) \
  (void)(_x)
#endif

//----------------------------------------------------
/**
	\brief	Volani funkce na kterou ukazuje nenulovy ukazatel, jinak bez volani

	\param	_fnc	Ukazatel na volanou funkci, nebo NULL
	\param	...		Parametry volane funkce
*/
//----------------------------------------------------

#define CallIfNotNULL(_fnc, ...) \
	if ((_fnc) != NULL) \
	{ \
		_fnc(__VA_ARGS__); \
	}

//----------------------------------------------------
/**
	\brief	Linearni interpolace na primce dane dvema body

	\param	_x		Hodnota na ose x, pro kterou hledame hodnotu y
	\param	_x1		x-ova souradnice prvniho bodu
	\param	_y1		y-ova souradnice prvniho bodu
	\param	_x2		x-ova souradnice druheho bodu
	\param	_y2		y-ova souradnice druheho bodu

	\return		Interpolovana hodnota v bode x na primce dane dvema body
*/
//----------------------------------------------------

float_t LinIntrpl(const float_t _x, const float_t _x1, const float_t _y1, const float_t _x2, const float_t _y2);


//----------------------------------------------------
/**
	\brief	Linearni interpolace na usecce dane dvema body

	\param	_x		Hodnota na ose x, pro kterou hledame hodnotu y
	\param	_x1		x-ova souradnice prvniho bodu
	\param	_y1		y-ova souradnice prvniho bodu
	\param	_x2		x-ova souradnice druheho bodu
	\param	_y2		y-ova souradnice druheho bodu

	\return		Interpolovana hodnota v bode x na usecce dane dvema body.
				Pokud bod x lezi mimo interval x1-x2, je navracena hodnota y1, resp. y2.

	\note		Pro spravnou funkci je treba, aby platilo (_x1 < _x2)
*/
//----------------------------------------------------

float_t LinIntrplLimit(const float_t _x, const float_t _x1, const float_t _y1, const float_t _x2, const float_t _y2);


//----------------------------------------------------
/**
	\brief	Linearni interpolace na lomene care

	\param	_x		Hodnota na ose x, pro kterou hledame hodnotu y
	\param	_line	Lomena cara

	\return		Interpolovana hodnota v bode x na primce dane dvema body
*/
//----------------------------------------------------

float_t PolylineIntrpl(const float_t _x, const POLYLINE * const _line);

//----------------------------------------------------
/**
	\brief	Funkce pro jednoduche filtrovani

	\param	_actual		aktualni hodnota
	\param	_last		minula hodnota
	\param	_k			koeficient filtru

	\return		vrati filtrovanou hodnotu
*/
//----------------------------------------------------

float_t KFilter(float_t _actual, float_t _last, float_t _k);


//----------------------------------------------------
/**
	\brief	Porovnani floatu s danou toleranci

	\param	_a		Prvni cislo
	\param	_b		Druhe cislo
	\param	_tol	Tolerance

	\return		TRUE, pokud od sebe cisla _a a _b nejsou dale nez _tol (vcetne)
*/
//----------------------------------------------------

bool_t FloatEqual(const float_t _a, const float_t _b, const float_t _tol);


//----------------------------------------------------
/**
	\brief	Porovnani double s danou toleranci

	\param	_a		Prvni cislo
	\param	_b		Druhe cislo
	\param	_tol	Tolerance

	\return		TRUE, pokud od sebe cisla _a a _b nejsou dale nez _tol (vcetne)
*/
//----------------------------------------------------

bool_t DoubleEqual(const double_t _a, const double_t _b, const double_t _tol);


//----------------------------------------------------
/**
	\brief	Porovnani floatu na presnou shodu

	\param	_a		Prvni cislo
	\param	_b		Druhe cislo

	\return		TRUE, pokud si cisla _a a _b presne odpovidaji (maji stejnout binarni reprezentaci)
*/
//----------------------------------------------------

bool_t FloatAbsEqual(const float_t _a, const float_t _b);


//----------------------------------------------------
/**
	\brief	Porovnani double na presnou shodu

	\param	_a		Prvni cislo
	\param	_b		Druhe cislo

	\return		TRUE, pokud si cisla _a a _b presne odpovidaji (maji stejnout binarni reprezentaci)
*/
//----------------------------------------------------

bool_t DoubleAbsEqual(const double_t _a, const double_t _b);


//----------------------------------------------------
/**
	\brief	Inicializace knihovny
*/
//----------------------------------------------------

static inline bool_t MiscInitialize(void)
{
	return TRUE;
}


//----------------------------------------------------
/**
	\brief	Finalizace knihovny
*/
//----------------------------------------------------

static inline bool_t MiscFinalize(void)
{
	return TRUE;
}

#ifdef MSVC

// Callback volany pri prochazeni adresare
// _fileName - jmeno souboru
// _userData - uzivatelska data
// vrati-li FALSE, bude dalsi hledani ukonceno
typedef bool_t (*browsecb_t) (const char_t * const _fileName, void * const _userData);

//----------------------------------------------------
/**
	\brief	Prochazeni souboru ve slozce

	\param	_path			Cesta k adresari, ktery se ma prochazet
	\param	_recursive		Je-li TRUE, budou se rekurzivne prochazet slozky
	\param	_callback		Funkce volana pro kazdy soubor
	\param	_userData		Uzivatelska data predana callbacku

	\return		TRUE, pokud byl adresar cely prohledan, FALSE, pokud bylo prochazeni ukonceno na zadost uzivatele
*/
//----------------------------------------------------

bool_t BrowseFolderForFiles(const char_t * const _path, const bool_t _recursive, browsecb_t _callback, void * const _userData);

// objekt pro odstranovani objektu z kontejneru
class CallDelete
{
	public:
		template <typename T>
		void operator() (T * _ptr)
		{
			if (_ptr != NULL)
			{
				delete _ptr;
				_ptr = NULL;
			}
		}
};

class CallDestructor
{
    public:
        template <typename T>
        void operator() (T * _ptr)
        {
            if (_ptr != NULL)
            {
                _ptr->~T();
                _ptr = NULL;
            }
        }
};

#endif //MSVC

#endif // _MISC_H_
