//=============================================================================
//  MuseScore
//  Music Composition & Notation
//
//  Copyright (C) 2009 Werner Schweer
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License version 2
//  as published by the Free Software Foundation and appearing in
//  the file LICENCE.GPL
//=============================================================================

#include "fraction.h"
#include "mscore.h"


namespace Ms {

//---------------------------------------------------------
//   gcd
//    greatest common divisor
//---------------------------------------------------------

static int gcd(int a, int b)
      {
      if (b == 0)
            return a < 0 ? -a : a;
      return gcd(b, a % b);
      }

//---------------------------------------------------------
//   lcm
//    least common multiple
//---------------------------------------------------------

static unsigned lcm(int a, int b)
      {
      return a * b / gcd(a, b);
      }

//---------------------------------------------------------
//   Fraction
//---------------------------------------------------------

Fraction::Fraction(int z, int n)
   : _numerator(z), _denominator(n)
      {
      }

//---------------------------------------------------------
//   reduce
//---------------------------------------------------------

void Fraction::reduce()
      {
      int tmp = gcd(_numerator, _denominator);
      _numerator /= tmp;
      _denominator /= tmp;
      }

//---------------------------------------------------------
//   reduced
//---------------------------------------------------------

Fraction Fraction::reduced() const
      {
      int tmp = gcd(_numerator, _denominator);
      return Fraction(_numerator / tmp, _denominator / tmp);
      }

//---------------------------------------------------------
//   absValue
//---------------------------------------------------------

Fraction Fraction::absValue() const
      {
      return Fraction(qAbs(_numerator), qAbs(_denominator));
      }

// --- comparison --- //

bool Fraction::operator<(const Fraction& val) const
      {
      const int v = lcm(_denominator, val._denominator);
      return _numerator * (v / _denominator) < val._numerator * (v / val._denominator);
      }

bool Fraction::operator<=(const Fraction& val) const
      {
      const int v = lcm(_denominator, val._denominator);
      return _numerator * (v / _denominator) <= val._numerator * (v / val._denominator);
      }

bool Fraction::operator>=(const Fraction& val) const
      {
      const int v = lcm(_denominator, val._denominator);
      return _numerator * (v / _denominator) >= val._numerator * (v / val._denominator);
      }

bool Fraction::operator>(const Fraction& val) const
      {
      const int v = lcm(_denominator, val._denominator);
      return (_numerator * (v / _denominator)) > (val._numerator * (v / val._denominator));
      }

bool Fraction::operator==(const Fraction& val) const
      {
      const int v = lcm(_denominator, val._denominator);
      return (_numerator * (v / _denominator)) == (val._numerator * (v / val._denominator));
//      return (_numerator == val._numerator) && (_denominator == val._denominator);
      }

bool Fraction::operator!=(const Fraction& val) const
      {
      const int v = lcm(_denominator, val._denominator);
      return (_numerator * (v / _denominator)) != (val._numerator * (v / val._denominator));
//      return (_numerator != val._numerator) || (_denominator != val._denominator);
      }

//---------------------------------------------------------
//   operator+=
//---------------------------------------------------------

Fraction& Fraction::operator+=(const Fraction& val)
      {
      const int tmp = lcm(_denominator, val._denominator);
      _numerator = _numerator * (tmp / _denominator) + val._numerator * (tmp / val._denominator);
      _denominator = tmp;
      return *this;
      }

//---------------------------------------------------------
//   operator-=
//---------------------------------------------------------

Fraction& Fraction::operator-=(const Fraction& val)
      {
      const unsigned tmp = lcm(_denominator, val._denominator);
      _numerator = _numerator * (tmp / _denominator) - val._numerator * (tmp / val._denominator);
      _denominator  = tmp;
      return *this;
      }

//---------------------------------------------------------
//   operator*=
//---------------------------------------------------------

Fraction& Fraction::operator*=(const Fraction& val)
      {
      _numerator *= val._numerator;
      _denominator  *= val._denominator;
      return *this;
      }

Fraction& Fraction::operator*=(int val)
      {
      _numerator *= val;
      return *this;
      }

//---------------------------------------------------------
//   operator/=
//---------------------------------------------------------

Fraction& Fraction::operator/=(const Fraction& val)
      {
      _numerator   *= val._denominator;
      _denominator *= val._numerator;
      return *this;
      }

Fraction& Fraction::operator/=(int val)
      {
      _denominator *= val;
      return *this;
      }

//---------------------------------------------------------
//   fromTicks
//---------------------------------------------------------

Fraction Fraction::fromTicks(int ticks)
      {
      return Fraction(ticks, MScore::division * 4).reduced();
      }

//---------------------------------------------------------
//   ticks
//---------------------------------------------------------

int Fraction::ticks() const
      {
      // MScore::division - ticks per quarter note
      // MScore::division * 4 - ticks per whole note
      // result: rounded (MScore::division * 4 * _numerator * 1.0 / _denominator) value
      return (_numerator * MScore::division * 4 + (_denominator/2)) / _denominator;
      }

} // namespace Ms

