#include <stdio.h>

#include <fraction.h>
#include <strings.h>


static __int64 mcd(__int64 a, __int64 b)
{
	if (a < 0)
		a = -a;
	if (b < 0)
		b = -b;

	__int64 r;
	while (b > 0)
	{
    r = a % b;
		a = b;
		b = r;
	}
	return a;
}

static __int64 mcm(__int64 a, __int64 b)
{
	if (a < 0)
		a = -a;
	if (b < 0)
		b = -b;
	return ((a * b) / mcd(a, b));
}


void fraction::simplify()
{
	if (_den > 1 && _num > 1)
	{
		__int64 div = mcd(_num, _den);
		if  (div > 1)
		{
			_num /= div;
			_den /= div;
		}
	}
	if (_den < 0)
	{
		_num = -_num;
		_den = -_den;
	}
}

// Crea una frazione a partire da una stringa avente la VIRGOLA come separatore dei decimali!
void fraction::build_fraction (const char *s)
{
	TString80 n = s;

	_num = 0;
	_den = 1;
	if (n.not_empty())
	{
		int pdec = n.find(',');
		const int psqr = n.find('['), psls = n.find('/');
		int ndec = 0, len_periodo = 0, sign = 1, anti_periodo = 0;
		if (pdec < 0)
			pdec = n.find('.');

		if (n.find('-') >= 0)
			sign = -1;
		if (pdec >= 0)
			ndec = n.len() - pdec - 1;

		if (psls > 0)
		{
		  TString80 num = n.left(psls);
			fraction a(num);
			num = n.mid(psls + 1);
			fraction b(num);
			*this = a / b;
			return;
		}
		if (psqr > 0)
		{
			int end = n.find(']');
			
			if (end < psqr)
				end = n.len();
			len_periodo = end - psqr - 1;
			anti_periodo = psqr -pdec - 1;
		}
		else
			if (ndec > 2)
			{
				bool found = FALSE;
				int j = 0;
				const char * pc;

				for (pc = (const char *)n + pdec + 1; !found && *pc != '\0'; pc++)
				{
					int max_period = strlen(pc) / 3;
					for (j = max_period; !found && j > 0 ; j--)
					{
						int len = 0, pos = 0, c;

						for (c = 0; c < j; c++)
						{
							const char * pp = pc + c;
							len = strlen(pp);
							char cmp = *pp;
							pos = 0;
							while (pos < len)
							{
								if (pp[pos] != cmp)
									if (pos < len - 1 || (pp[pos] - cmp) != 1 || *(pp + 1) < '5')
										break;
								pos += j;
							}
							if (pos < len) 
								break;
						}
						found = (pos == len) && (c == (len + 1) % j + 1);
					}
					if (!found)
						anti_periodo++;
				}
				if (found)
				{
					len_periodo = j + 1;
					n.cut(pdec + anti_periodo + len_periodo + 1);
				}
			}
		n.strip(",.-+/[]");
#ifdef WIN32
	  sscanf(n, "%I64d", &_num);
#else	  
	  sscanf(n, "%Ld", &_num);
#endif
		if (len_periodo > 0)
		{
			_den = 9;
			__int64 sub = _num / 10;
			for (int l = len_periodo - 1; l > 0 ; l--)
			{
				_den = (_den * 10) + 9;
				sub /= 10;
			}
			if (anti_periodo > 0)
				for (int p = anti_periodo; p > 0; p--)
					_den *= 10;
			_num -= sub;
		}
		else
			for (int p = ndec; p > 0; p--)
				_den *= 10;

		_num *= sign;
	}
	simplify();
}

fraction::fraction()
{
	_num = 0;
	_den = 1;
}

fraction::fraction(const fraction& b)
{
	_num = b._num;
	_den = b._den;
}

fraction::fraction(const real& num, const real& den)
{
  if (den == ZERO)
    build_fraction("");
	else
		if (den == UNO)
	    build_fraction(num.stringa());
	  else
	  {
			real n = num; n /= den;
	    build_fraction(n.stringa());
		}
}

int fraction::sign() const
{
	if ( _num == 0 || _den == 0)
		return 0;
  return _num < 0 ? (_den < 0 ? +1 : -1) : (_den < 0 ? -1 : +1);
}

fraction& fraction::operator =(const fraction & b)
{
	_num = b._num;
	_den = b._den;
  return *this;
}

fraction& fraction::operator += (const fraction & b)
{
	const __int64 m = mcm(_den, b._den);
	
	_num = _num * ( m / _den) + b._num * ( m / b._den);
	_den = m;
	simplify();
  return *this;
}

fraction& fraction::operator -= (const fraction & b)
{
	__int64 m = mcm(_den, b._den);
	
	_num = _num * ( m / _den) - b._num * ( m / b._den);
	_den = m;
	simplify();
  return *this;
}

fraction& fraction::operator *= (const fraction & b)
{
	_num = _num * b._num;
	_den = _den * b._den;
	simplify();
  return *this;
}

fraction& fraction::operator /= (const fraction & b)
{
	_num = _num * b._den;
	_den = _den * b._num;
	simplify();
  return *this;
}

fraction fraction::operator - () const
{
	fraction b(*this);
	b._num = -b._num;
  return b;
}

// Funzioni comuni dei due real

TObject* fraction::dup () const
{
  return new fraction(*this);
}

fraction::operator real() const
{
	real n, d;
	n.set_int64(_num);
	d.set_int64(_den);

  real q = n; q /= d;
  return q;
}

// @doc EXTERNAL

// @func real | operator + | Somma due numeri reali
//
// @rdesc Ritorna il valore della somma
fraction operator + (
  const fraction & a,  // @parm Primo addendo da sommare
  const fraction & b)  // @parm Secondo addendo da sommare

  // @syntax operator +(const fraction & a, const fraction & b);
  // @syntax operator +(const real & a, const fraction & b);
  // @syntax operator +(const fraction & a, const real & b);

{
	fraction f = a;
	f += b;
  return f;
}

// @doc EXTERNAL

// @func real | operator - | Sottrae due numeri reali
//
// @rdesc Ritorna il valore della sottrazione
fraction operator - (
  const fraction & a,  // @parm Primo addendo da sottrarre
  const fraction & b)  // @parm Secondo addendo da sottrarre

  // @syntax operator -(const fraction & a, const fraction & b);
  // @syntax operator -(const real & a, const fraction & b);
  // @syntax operator -(const fraction & a, const real & b);
{
	fraction f = a;
	f -= b;
  return f;
}

// @doc EXTERNAL

// @func real | operator * | Moltiplica due frazioni
//
// @rdesc Ritorna il valore della moltiplicazione
fraction operator *(
  const fraction & a,  // @parm Prima frazione da moltiplicare
  const fraction & b)  // @parm Seconda frazione da moltiplicare

  // @syntax operator *(const fraction & a, const fraction & b);
  // @syntax operator *(const real & a, const fraction & b);
  // @syntax operator *(const fraction & a, const real & b);

{
	fraction f = a;
	f *= b;
  return f;
}

// @doc EXTERNAL

// @func real | operator * | Moltiplica una frazione e un intero
//
// @rdesc Ritorna il valore della moltiplicazione
fraction operator *(
  const fraction & a,  // @parm frazione da moltiplicare
  __int64 b)  // @parm intero da moltiplicare

  // @syntax operator -(__int64 a, const fraction & b);
  // @syntax operator -(const fraction & a, __int64 b);

{
	fraction f;
	f._num = a._num * b;
	f._den = a._den;
	f.simplify();
  return f;
}

// @doc EXTERNAL

// @func real | operator / | Divide due frazioni
//
// @rdesc Ritorna il valore della divisione
fraction operator / (
  const fraction & a,  // @parm Prima frazione da dividere
  const fraction & b)  // @parm Seconda frazione da dividere

  // @syntax operator /(const fraction & a, const fraction & b);
  // @syntax operator /(const real & a, const fraction & b);
  // @syntax operator /(const fraction & a, const real & b);
{
	fraction f = a;
	f /= b;
  return f;
}

// @doc EXTERNAL

// @func real | operator * | Divide una frazione per un intero
//
// @rdesc Ritorna il valore della divisione
fraction operator /(
  const fraction & a,  // @parm frazione da dividere
  __int64 b)  // @parm intero divisore
  // @syntax operator /(const fraction & a, __int64 b);

{
	fraction f;
	f._num = a._num;
	f._den = a._den * b;
	f.simplify();
  return f;
}

// @doc EXTERNAL

// @func real | operator * | Divide una frazione per un intero
//
// @rdesc Ritorna il valore della divisione
fraction operator /(
  __int64 a,           // @parm intero da dividere
  const fraction & b)  // @parm frazione divisore
  // @syntax operator  /(__int64 a, const fraction & b);

{
	fraction f;
	f._num = b._den * a;
	f._den = b._num ;
	f.simplify();
  return f;
}


// @doc EXTERNAL

// @func bool | operator <gt> | Controlla se un reale e' maggiore di un altro
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se <p a> e' maggiore di <p b>
// @flag FALSE | Se <p a> e' non maggiore di <p b>
bool operator > (
  const fraction & a,  // @parm Prima frazione da confrontare
  const fraction & b)  // @parm Seconda frazione da confrontare

  // @syntax operator <gt> (const fraction & a, const fraction & b);
  // @syntax operator <gt> (const real & a, const fraction &b);
  // @syntax operator <gt> (const fraction &a, const real & b);

{
	fraction f = a - b;
  return f.sign() > 0;
}

// @doc EXTERNAL

// @func bool | operator <lt> | Controlla se un reale e' minore di un altro
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se <p a> e' minore di <p b>
// @flag FALSE | Se <p a> e' non minore di <p b>
bool operator < (
  const fraction & a,  // @parm Prima frazione da confrontare
  const fraction & b)  // @parm Seconda frazione da confrontare

  // @syntax operator <lt> (const fraction &a, const fractio &b);
  // @syntax operator <lt> (const real & a, const fraction &b);
  // @syntax operator <lt> (const fraction &a, const real & b);

{
	fraction f = a - b;
  return f.sign() < 0;
}

// @doc EXTERNAL

// @func bool | operator <gt>= | Controlla se un reale e' maggiore o uguale ad
//                               un altro
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se <p a> e' maggiore o uguale a <p b>
// @flag FALSE | Se <p a> e' minore di <p b>
bool operator >= (
  const fraction & a,  // @parm Prima frazione da confrontare
  const fraction & b)  // @parm Seconda frazione da confrontare

  // @syntax operator <gt>= (const fraction &a, const fractio &b);
  // @syntax operator <gt>= (const real & a, const fraction &b);
  // @syntax operator <gt>= (const fraction &a, const real & b);

{
	fraction f = a - b;
  return f.sign() >= 0;
}

// @doc EXTERNAL

// @func bool | operator <lt>= | Controlla se un reale e' minore o uguale ad
//                               un altro
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se <p a> e' minore o uguale a <p b>
// @flag FALSE | Se <p a> e' maggiore di <p b>
bool operator <= (
  const fraction & a,  // @parm Prima frazione da confrontare
  const fraction & b)  // @parm Seconda frazione da confrontare

  // @syntax operator <lt>= (const fraction &a, const fractio &b);
  // @syntax operator <lt>= (const real & a, const fraction &b);
  // @syntax operator <lt>= (const fraction &a, const real & b);
{
	fraction f = a - b;
  return f.sign() <= 0;
}

// @doc EXTERNAL

// @func bool | operator == | Controlla se un reale e' uguale ad un altro
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se <p a> e' uguale a <p b>
// @flag FALSE | Se <p a> non e' uguale a <p b>
bool operator == (
  const fraction & a,  // @parm Prima frazione da confrontare
  const fraction & b)  // @parm Seconda frazione da confrontare

  // @syntax operator == (const fraction &a, const fractio &b);
  // @syntax operator == (const real & a, const fraction &b);
  // @syntax operator == (const fraction &a, const real & b);
{
	fraction f = a - b;
  return f.sign() == 0;
}

// @doc EXTERNAL

// @func bool | operator != | Controlla se 2 reali dono diversi
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se <p a> e' diverso da <p b>
// @flag FALSE | Se <p a> e' uguale a <p b>
bool operator != (
  const fraction & a,  // @parm Prima frazione da confrontare
  const fraction & b)  // @parm Seconda frazione da confrontare

  // @syntax operator != (const fraction &a, const fractio &b);
  // @syntax operator != (const real & a, const fraction &b);
  // @syntax operator != (const fraction &a, const real & b);
{
  return ! ::operator ==(a, b);
}

// @doc EXTERNAL

// @func Scambia la frazione <p a> con la frazione <p b>
void swap (
  fraction & a,  // @parm Prima frazione da scambiare
  fraction & b)  // @parm Seconda frazione da scambiare

{
	fraction f = a;
	a = b;
	b = f;
}

// @doc EXTERNAL

// @func Ritorna il numero reale piu' piccolo tra <p a> e <p b>
const fraction& fnc_min (
  const fraction & a,  // @parm Prima frazione da confrontare
  const fraction & b)  // @parm Seconda frazione da confrontare
  
// @syntax const real& fnc_min (const fraction & a, const fraction & b)
  
{
  return a < b ? a : b;
}

// @doc EXTERNAL

// @func Ritorna il numero reale piu' grande tra <p a> e <p b>
const fraction& fnc_max (
  const fraction & a,  // @parm Prima frazione da confrontare
  const fraction & b)  // @parm Seconda frazione da confrontare

// @syntax const real& fnc_max (const fraction & a, const fraction & b)

{
  return a > b ? a : b;
}