// (c) Sam Gratrix.


// ===========================================================================================================
// Rational class. Probably only works with positive integers :) I'm quite paranoid about overflowing when I
// don't need to, so that's why lots of gcd use! Yes, this may well be a bit crappy. Assumes that gcd(n, d)
// in the rational class is always is one.

function Rational(n, d)
{
  n = parseInt(n); d = parseInt(d);

  var g = gcd(n, d); this.n = n/g; this.d = d/g;
}


// -----------------------------------------------------------------------------------------------------------
// Set

Rational.prototype.set_i = function(i)     // set by integer i
{
    this.n = parseInt(i); this.d = parseInt(1);
}

Rational.prototype.set_f = function(n, d)  // set by fraction n/d
{
    var n = parseInt(n); var d = parseInt(d);

    var g = gcd(n, d); this.n = n / g; this.d = d / g;
}

Rational.prototype.set_r = function(r)     // set by rational r
{
    this.n = r.n; this.d = r.d;
}


// -----------------------------------------------------------------------------------------------------------
// Mul

Rational.prototype.mul_i = function(i)     // mul by integer i
{
    var n = parseInt(i);

    var g = gcd(n, this.d); n /= g; this.d /= g;

    this.n *= n;
}

Rational.prototype.mul_f = function(n, d)  // mul by fraction n/d
{
    var n = parseInt(n); var d = parseInt(d);

    var g = gcd(     n,      d);      n /= g;      d /= g;
        g = gcd(this.n,      d); this.n /= g;      d /= g;
        g = gcd(     n, this.d);      n /= g; this.d /= g;

    this.n *= n; this.d *= d;
}

Rational.prototype.mul_r = function(r)     // mul by rational r
{
    var n = r.n; var d = r.d;

    var g = gcd(this.n,    r.d); this.n /= g;      d /= g;
        g = gcd(   r.n, this.d);      n /= g; this.d /= g;

    this.n *= n; this.d *= d;
}


// -----------------------------------------------------------------------------------------------------------
// Div

Rational.prototype.div_i = function(i)     // div by integer i
{
    var d = parseInt(i);

    var g = gcd(this.n, d); this.n /= g; d /= g;

    this.d *= d;
}

Rational.prototype.div_f = function(n, d)  // div by fraction n/d
{
    var n = parseInt(d); var d = parseInt(n);

    var g = gcd(     n,      d);      n /= g;      d /= g;
        g = gcd(this.n,      d); this.n /= g;      d /= g;
        g = gcd(     n, this.d);      n /= g; this.d /= g;

    this.n *= n; this.d *= d;
}

Rational.prototype.div_r = function(r)     // div by rational r
{
    var n = r.d; var d = r.n;

    var g = gcd(this.n,      d); this.n /= g;      d /= g;
        g = gcd(     n, this.d);      n /= g; this.d /= g;

    this.n *= n; this.d *= d;
}


// -----------------------------------------------------------------------------------------------------------
// Add

Rational.prototype.add_i = function(i)     // add integer i
{
    var n = parseInt(i);

    this.n += this.d * n;

    g = gcd(this.n, this.d); this.n /= g; this.d /= g;    /// needed?
}

Rational.prototype.add_f = function(n, d)  // add fraction n/d
{
    var n = parseInt(n); var d = parseInt(d);

    var g = gcd(     n,   d);      n /= g;   d /= g;
        g = gcd(this.d, r.d); this.d /= g; r.d /= g;

    this.n *= r.d; this.n += this.d * r.n; this.d *= g * r.d;

    g = gcd(this.n, this.d); this.n /= g; this.d /= g;    /// needed?
}

Rational.prototype.add_r = function(r)     // add rational r
{
    var g = gcd(this.d, r.d); this.d /= g; r.d /= g;

    this.n *= r.d; this.n += this.d * r.n; this.d *= g * r.d;

    g = gcd(this.n, this.d); this.n /= g; this.d /= g;    /// needed?
}


// -----------------------------------------------------------------------------------------------------------
// Sub

Rational.prototype.sub_i = function(i)     // sub integer i
{
    var n = parseInt(i);

    this.n -= this.d * n;

    g = gcd(this.n, this.d); this.n /= g; this.d /= g;    /// needed?
}

Rational.prototype.sub_f = function(n, d)  // sub fraction n/d
{
    var n = parseInt(n); var d = parseInt(d);

    var g = gcd(     n,   d);      n /= g;   d /= g;
        g = gcd(this.d, r.d); this.d /= g; r.d /= g;

    this.n *= r.d; this.n -= this.d * r.n; this.d *= g * r.d;

    g = gcd(this.n, this.d); this.n /= g; this.d /= g;    /// needed?
}

Rational.prototype.sub_r = function(r)     // sub rational r
{
    var g = gcd(this.d, r.d); this.d /= g; r.d /= g;

    this.n *= r.d; this.n -= this.d * r.n; this.d *= g * r.d;

    g = gcd(this.n, this.d); this.n /= g; this.d /= g;    /// needed?
}


// -----------------------------------------------------------------------------------------------------------
// Display

Rational.prototype.display = function()
{
    switch(this.d)
    {
      case  1 : return this.n;
      case  0 : return 'Error';
      default : return '<table cellspacing="0" cellpadding="0" border="0" class="frac"><tr><th align="center">'+this.n+'</th></tr><tr><td align="center">'+this.d+'</td></tr></table>';
    }
}

