/*****************************************************************************

        GRAOUMF TRACKER 2
        Author: Laurent de Soras, 1996-2016

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

*****************************************************************************/



#if defined (BASE_CURRENT_INLINE)
	#error Inclusion recursive du code inline BASE.
#endif
#define	BASE_CURRENT_INLINE

#if ! defined (BASE_INLINE_INCLUDED)
#define	BASE_INLINE_INCLUDED



/*\\\ FICHIERS INCLUDE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include	<math.h>

#include	"base.h"
#include	"base_ct.h"



/*\\\ FONCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*==========================================================================*/
/*      Nom: BASE_is_null                                                   */
/*      Description: Teste si un nombre reel est quasi-nul (valeur absolue  */
/*                   inferieure a EPSILON).                                 */
/*      Parametres en entree:                                               */
/*        - val: valeur a tester.                                           */
/*      Retour: TRUE si la valeur est jugee comme quasi-nulle.              */
/*==========================================================================*/

inline bool	BASE_is_null (double val)
{
	if (val < EPSILON)
	{
		if (val > -EPSILON)
		{
			return (true);
		}
	}

	return (false);
}



/*==========================================================================*/
/*      Nom: BASE_is_infinite                                               */
/*      Description: Teste si un nombre reel est quasi-inifni (valeur       */
/*                   absolue superieure ou egale a GT_INFINITY).            */
/*      Parametres en entree:                                               */
/*        - val: valeur a tester.                                           */
/*      Retour: TRUE si la valeur est jugee comme quasi-inifnie.            */
/*==========================================================================*/

inline bool	BASE_is_infinite (double val)
{
	if (val <= GT_INFINITY)
	{
		if (val >= -GT_INFINITY)
		{
			return (false);
		}
	}

	return (true);
}



/*==========================================================================*/
/*      Nom: BASE_safe_double_inversion                                     */
/*      Description: Inverse proprement un nombre a virgule flottante en    */
/*                   tenant compte des infinis possibles sans generer de    */
/*                   NaN.                                                   */
/*      Parametres en entree:                                               */
/*        - val: valeur a inverser.                                         */
/*      Retour: valeur inverse.                                             */
/*==========================================================================*/

inline double	BASE_safe_double_inversion (double val)
{
	if (BASE_is_null (val))
	{
		return (GT_INFINITY);
	}
	else if (BASE_is_infinite (val))
	{
		return (0.0);
	}

	return (1.0 / val);
}



/*==========================================================================*/
/*      Nom: BASE_lin_to_db                                                 */
/*      Description: Passe une valeur lineaire en decibels.                 */
/*      Parametres en entree:                                               */
/*        - val: valeur lineaire.                                           */
/*      Retour: valeur en dB                                                */
/*==========================================================================*/

inline double	BASE_lin_to_db (double val)
{
	if (val > EPSILON)
	{
		return (log (val) * 20 / LN10);
	}
	
	return (-GT_INFINITY);
}



/*==========================================================================*/
/*      Nom: BASE_db_to_lin                                                 */
/*      Description: Passe une valeur en dB en valeur lineaire              */
/*      Parametres en entree:                                               */
/*        - val: valeur en dB.                                              */
/*      Retour: valeur lineaire                                             */
/*==========================================================================*/

inline double	BASE_db_to_lin (double val)
{
	if (val > -GT_INFINITY)
	{
		return (exp (val * LN10 * 0.05));
	}
	
	return (0);
}



// Adds the trailing L'\0' too.
template <class T>
void	BASE_push_back_utf8_to_utf16 (T &utf16, const char *utf8_0, bool trailing_zero_flag)
{
	int            len = 0; // Remaining length of the current UTF-8 sequence
	int            msk = 0;
	int            pos = 0; // Within the UTF-8 string
	int32_t        val = 0;

	while (utf8_0 [pos] != '\0')
	{
		const unsigned char  c = utf8_0 [pos];

		if (len <= 0)
		{
			val = 0;
			len = 1;
			msk = 0x7F;
			if (c >= 0x80)
			{
				if (c < 0xC2 || c > 0xF4)	// Invalid UTF-8 lead byte
				{
					utf16.push_back (L'\?');
					len = 0;
				}
				else if (c < 0xE0)
				{
					len = 2;
				}
				else if (c < 0xF0)
				{
					len = 3;
				}
				else if (c < 0xF8)
				{
					len = 4;
				}
				else if (c < 0xFC)
				{
					len = 5;
				}
				else
				{
					len = 6;
				}

				msk = 0x7F >> len;
			}
		}

		if (len > 0)
		{
			val <<= 6;
			val |= c & msk;
			msk = 0x3F;
			-- len;
			if (len == 0)
			{
				if (val < 0x10000)
				{
					utf16.push_back (val);
				}
				else
				{
					const int      a = int (((val >> 10) - 0x0040) & 0x03FF);
					const int      b = int (  val                  & 0x03FF);
					utf16.push_back (wchar_t (a | 0xD800));
					utf16.push_back (wchar_t (b | 0xDC00));
				}
			}
		}

		++ pos;
	}

	if (len > 0)   // UTF-8 sequence not terminated
	{
		utf16.push_back (L'\?');
	}
	if (trailing_zero_flag)
	{
		utf16.push_back (L'\0');
	}
}



/****************************************************************************/
/*                                                                          */
/*                                                                          */
/*                                                                          */
/****************************************************************************/



/*==========================================================================*/
/*      Nom:                                                                */
/*      Description:                                                        */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*      Retour:                                                             */
/*==========================================================================*/

#endif

#undef BASE_CURRENT_INLINE

