public class Fraction
{
/* bottom should be strictly positive, which means that the sign of top will
 * be the sign of the fraction.
 * top and bottom should have no common factors (i.e. the fraction should
 * be in lowest terms
*/
  private int top;
  private int bottom;

  public Fraction(int top, int bottom)
  {
    if(bottom == 0)
    {
      System.err.println("Attempt to create undefined fraction.");
      System.exit(1);
    }
    else if (bottom < 0)
    {
      this.top = -top;
      this.bottom = -bottom;
    }
    else
    {
      this.top = top;
      this.bottom = bottom;
    }
    this.reduce();
  }

  public Fraction(int i)
  {
    this(i, 1);
  }

  public Fraction()
  {
    this(0, 1);
  }

  public int getNumerator()
  {
    return this.top;
  }

  public int getDenominator()
  {
    return this.bottom;
  }

  public String toString()
  {
    return top + "/" + bottom;
  } 

  private void reduce()
  {
    int common = gcd(this.top, this.bottom);
    if (common > 1)
    {
      this.top = this.top / common;
      this.bottom = this.bottom / common;
    }
  }

  private int gcd(int a, int b)
  {
    int temp;

    if (a < 0)
      a = -a;
    if (b < 0)
      b = -b;

    while (b != 0)
    {
      temp = b;
      b = a % temp;
      a = temp;
    }
    return a;
  }

  public Fraction negate()
  {
    return new Fraction(-this.top, this.bottom);
  }

  public Fraction plus(Fraction rhs)
  {
    Fraction retval = new Fraction();
    retval.top = rhs.top * this.bottom + this.top * rhs.bottom;
    retval.bottom = this.bottom * rhs.bottom;
    retval.reduce();
    return retval;
  }

  public Fraction minus(Fraction rhs)
  {
    return this.plus(rhs.negate());
  }

  public Fraction invert()
  {
    if (this.top == 0)
    {
      System.out.println("Cannot invert 0");
      System.exit(1);
      return null;
    }
    else
    {
      return new Fraction(this.bottom, this.top);
    }
  }

  public Fraction times(Fraction rhs)
  {
    Fraction retval = new Fraction();
    retval.top = this.top * rhs.top;
    retval.bottom = this.bottom * rhs.bottom;
    retval.reduce();
    return retval;
  }

  public Fraction dividedBy(Fraction rhs)
  {
    return this.times(rhs.invert());
  }

  public int compareTo(Fraction rhs)
  {
    Fraction temp = this.minus(rhs);
    return temp.top;
  }
  
  public static void main(String args[])
  {
    Fraction f1 = new Fraction();
    Fraction f2 = new Fraction(10);
    Fraction f3 = new Fraction(4, 12);
    Fraction f4 = new Fraction(21, -7);
    Fraction f5 = f3.plus(f2);
    Fraction f6 = f3.minus(f2);
    Fraction f7 = f3.times(f2);
    Fraction f8 = f3.dividedBy(f2);

    System.out.println("f3 = " + f3 + " f2 = " + f2);

    System.out.println("Plus:" + f5);
    System.out.println("Minus:" + f6);
    System.out.println("Times:" + f7);
    System.out.println("dividedBy:" + f8);
    System.out.println(f2.compareTo(f3));
    System.out.println(f3.compareTo(f2));
    System.out.println(f3.compareTo(f3));
  } 
}
