//----------------------------------------------------------------------
//  IMPLEMENTATION FILE (newfrac.cpp)
//  This module exports FracType and two operator functions,
//  operator* and operator==.
//  It also adds a default (parameterless) constructor
//  and exports operator<< and operator>> for stream I/O.
//----------------------------------------------------------------------
#include <iostream.h>
#include <stdlib.h>     // For abs() function
#include "newfrac.h"

int GreatestCommonDivisor( int, int );  // Auxiliary function prototype

// Private members of class:
//     int numer;
//     int denom;
//
// CLASSINV: denom > 0

FracType::FracType( /* in */ int initNumer,
                    /* in */ int initDenom )
    //..................................................................
    // PRE:  Assigned(initNumer)  &&  initDenom > 0
    // POST: numer == initNumer  &&  denom == initDenom
    //..................................................................
{
    numer = initNumer;
    denom = initDenom;
}

FracType::FracType()
    //..................................................................
    // POST: numer == 0  &&  denom == 1
    //..................................................................
{
    numer = 0;  denom = 1;
}

ostream& operator<<( /* inout */ ostream& someStream,
                     /* in */    FracType frac       )
    //..................................................................
    // Friend of the FracType class
    // PRE:  someStream is a valid stream object
    // POST: Fraction has been displayed as frac.numer/frac.denom
    //       with no blanks
    //    && FCTVAL == address of someStream
    //..................................................................
{
    someStream << frac.numer << "/" << frac.denom;
    return someStream;
}

istream& operator>>( /* inout */ istream&  someStream,
                     /* out */   FracType& frac       )
    //..................................................................
    // Friend of the FracType class
    // PRE:  someStream is a valid stream object
    // POST: User has typed in a value for frac.numer, then a slash,
    //       then a value for frac.denom
    //    && frac.denom > 0
    //    && FCTVAL == address of someStream
    //..................................................................
{
    char slash;

    do {
        someStream >> frac.numer >> slash >> frac.denom;
        if (someStream && frac.denom <= 0)
            cout << "Denominator must be positive\n"
                 << "Please re-enter fraction: ";
    } while (someStream && frac.denom <= 0);
    return someStream;
}

float FracType::FloatEquiv() const
    //..................................................................
    // POST: FCTVAL == float equivalent of this fraction
    //..................................................................
{
    return float(numer) / float(denom);
}

void FracType::Simplify()
    //..................................................................
    // POST: Fraction is reduced to lowest terms. (No integer > 1
    //       evenly divides both numer and denom)
    //..................................................................
{
    int gcd;
    int absNumer = abs(numer);

    if (numer==0 || absNumer==1 || denom==1)
        return;
    gcd = GreatestCommonDivisor(absNumer, denom);
    if (gcd > 1) {
        numer /= gcd;
        denom /= gcd;
    }
}

FracType FracType::operator*( /* in */ FracType frac2 ) const
    //..................................................................
    // PRE:  This fraction and frac2 are in simplest terms
    // POST: FCTVAL == this fraction * frac2  (fraction multiplication)
    //       (WARNING: Overflow is possible)
    //..................................................................
{
    int resultNumer = numer * frac2.numer;
    int resultDenom = denom * frac2.denom;

    FracType resultFrac(resultNumer, resultDenom);
    // ASSERT: New fraction created

    resultFrac.Simplify();
    return resultFrac;
}

Boolean FracType::operator==( /* in */ FracType frac2 ) const
    //..................................................................
    // PRE:  This fraction and frac2 are in simplest terms
    // POST: FCTVAL == TRUE, if this fraction == frac2 (numerically)
    //              == FALSE, otherwise
    //..................................................................
{
    return (numer==frac2.numer) && (denom==frac2.denom);
}

int GreatestCommonDivisor( /* in */ int a,
                           /* in */ int b )
    //..................................................................
    // PRE:  a >= 0  &&  b > 0
    // POST: FCTVAL == Greatest common divisor of a and b
    //                 (Algorithm: the Euclidean algorithm)
    //..................................................................
{
    int temp = a % b;
    while (temp > 0) {  // INV (prior to test):
                        //    No integer > b evenly divides
                        //    both a<entry> and b<entry>
        a = b;
        b = temp;
        temp = a % b;
    }
    // ASSERT: b == Greatest common divisor of a<entry> and b<entry>
    return b;
}


