// Rational.cpp
// Aren Jansen
// Purpose: Rational class member function definitions

#include <math.h>
#include "Rational.h"


// Constructors 
Rational::Rational()
{
   m_numer = 0;
   m_denom = 1;
}

Rational::Rational( int iNumer, int iDenom )
{
   if ( iDenom == 0 )
   {
      cout << "Warning: 0 Denominator request..."
	   << "setting to default" << endl;
      iNumer = 0;
      iDenom = 1;
   }

   if ( iNumer <= 0 && iDenom < 0 )
   {
      iNumer = abs(iNumer);
      iDenom = abs(iDenom);
   }

   if ( iNumer == 0 )
   {
      m_numer = 0;
      m_denom = 1;
   }
   else
   {
      int d = gcd( abs(iNumer), iDenom );
      m_numer = iNumer/d;
      m_denom = iDenom/d;
   }
}



// Methods to return data members
int Rational::numerator( void ) const
{
   return m_numer;
}

int Rational::denominator( void ) const
{
   return m_denom;
}




// Methods for arithmetic operations
Rational Rational::add( const Rational & iRat ) const
{
   int oNum = m_numer*iRat.denominator() + m_denom*iRat.numerator();
   int oDen = m_denom*iRat.denominator();
   return Rational( oNum, oDen );
}

Rational Rational::sub( const Rational & iRat ) const
{
   int oNum = m_numer*iRat.denominator() - m_denom*iRat.numerator();
   int oDen = m_denom*iRat.denominator();
   return Rational( oNum, oDen );
}

Rational Rational::mult( const Rational & iRat ) const
{
   int oNum = m_numer*iRat.numerator();
   int oDen = m_denom*iRat.denominator();
   return Rational( oNum, oDen );
}

Rational Rational::div( const Rational & iRat ) const
{
   int oNum = m_numer*iRat.denominator();
   int oDen = m_denom*iRat.numerator();
   return Rational( oNum, oDen );
}

Rational Rational::negative( void ) const
{
   return Rational( -m_numer, m_denom );
}



// Methods for comparison
bool Rational::lt( const Rational & iRat ) const
{
   if ( m_numer*iRat.denominator() < m_denom*iRat.numerator() )
   {
      return true;
   }
   else
   {
      return false;
   } 
}

bool Rational::gt( const Rational & iRat ) const
{
   if ( m_numer*iRat.denominator() > m_denom*iRat.numerator() )
   {
      return true;
   }
   else
   {
      return false;
   } 
}

bool Rational::equal( const Rational & iRat ) const
{
   if ( m_numer == iRat.numerator() &&
	m_denom == iRat.denominator() )
   {
      return true;
   }
   else
   {
      return false;
   }
}

bool Rational::notequal( const Rational & iRat ) const
{
   return !equal(iRat);
}

bool Rational::ltequal( const Rational & iRat ) const
{
   return ( lt(iRat) || equal(iRat) );
}

bool Rational::gtequal( const Rational & iRat ) const
{
   return ( gt(iRat) || equal(iRat) );
}


// Method for outputting rationals
void Rational::print( void )
{
   cout << m_numer << '/' << m_denom;
}



// Overloaded operator versions of the arithmetic/comp methods
Rational Rational::operator+( const Rational & iRat ) const
{
   return add( iRat );
}

Rational Rational::operator-( const Rational & iRat ) const
{
   return sub( iRat );
}

Rational Rational::operator*( const Rational & iRat ) const
{
   return mult( iRat );
}

Rational Rational::operator/( const Rational & iRat ) const
{
   return div( iRat );
}

Rational Rational::operator-( void ) const
{
   return negative();
}

bool Rational::operator<( const Rational & iRat ) const
{
   return lt( iRat );
}

bool Rational::operator>( const Rational & iRat ) const
{
   return gt( iRat );
}

bool Rational::operator==( const Rational & iRat ) const
{
   return equal( iRat );
}

bool Rational::operator!=( const Rational & iRat ) const
{
   return notequal( iRat );
}

bool Rational::operator<=( const Rational & iRat ) const
{
   return ltequal( iRat );
}

bool Rational::operator>=( const Rational & iRat ) const
{
   return gtequal( iRat );
}




// Euclid's algorithm for finding gcd
int Rational::gcd( int num1, int num2 )
{
   int remainder = num2 % num1;
   
   if ( remainder != 0 )
      return gcd( remainder, num1 );
	
   return num1;
}




// Overloaded ostream function (can't be a member function)
ostream & operator<<( ostream & os, const Rational & iRat )
{
   os << iRat.numerator() << "/" << iRat.denominator();
   return os;
}
