using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace UlamekDemo
{
    //struct Ulamek
    struct Ulamek : IComparable<Ulamek>
    {
        private int licznik, mianownik;

        public Ulamek(int licznik, int mianownik = 1)
        {
            if (mianownik == 0) throw new Exception("Mianownik musi być różny od zera");
            this.licznik = licznik;
            this.mianownik = mianownik;
        }

        public static Ulamek Zero = new Ulamek(0);
        public static Ulamek Jeden = new Ulamek(1);
        public static Ulamek Polowa = new Ulamek(1, 2);
        public static Ulamek Cwierc = new Ulamek(1, 4);

        public static string Info()
        {
            return "Struktura Ulamek, (c) Jacek Matulewski 2010";
        }

        public override string ToString()
        {
            return licznik.ToString() + "/" + mianownik.ToString();
        }

        public double ToDouble()
        {
            return licznik / (double)mianownik;
        }

        public void Uprosc()
        {
            //NWD
            int mniejsza = Math.Min(Math.Abs(licznik), Math.Abs(mianownik));
            for (int i = mniejsza; i > 0; i--)
                if ((licznik % i == 0) && (mianownik % i == 0))
                {
                    licznik /= i;
                    mianownik /= i;
                }

            //znaki
            if (licznik * mianownik < 0)
            {
                licznik = -Math.Abs(licznik);
                mianownik = Math.Abs(mianownik);
            }
            else
            {
                licznik = Math.Abs(licznik);
                mianownik = Math.Abs(mianownik);
            }
        }

        #region Wlasnosci
        public int Licznik
        {
            get //odczyt
            {
                return licznik;
            }
            set //zapis
            {
                licznik = value;
            }
        }

        public int Mianownik
        {
            get //odczyt
            {
                return mianownik;
            }
            set //zapis
            {
                if (value == 0) throw new Exception("Mianownik musi być różny od zera");
                mianownik = value;
            }
        }
        #endregion

        #region Operatory
        //operatory arytmetyczne
        public static Ulamek operator -(Ulamek u)
        {
            return new Ulamek(-u.Licznik, u.Mianownik);
        }

        public static Ulamek operator +(Ulamek u1, Ulamek u2)
        {
            Ulamek wynik = new Ulamek(u1.Licznik * u2.Mianownik + u2.Licznik * u1.Mianownik, u1.Mianownik * u2.Mianownik);
            wynik.Uprosc();
            return wynik;
        }

        public static Ulamek operator -(Ulamek u1, Ulamek u2)
        {
            Ulamek wynik = new Ulamek(u1.Licznik * u2.Mianownik - u2.Licznik * u1.Mianownik, u1.Mianownik * u2.Mianownik);
            wynik.Uprosc();
            return wynik;
        }

        public static Ulamek operator *(Ulamek u1, Ulamek u2)
        {
            Ulamek wynik = new Ulamek(u1.Licznik * u2.Licznik, u1.Mianownik * u2.Mianownik);
            wynik.Uprosc();
            return wynik;
        }

        public static Ulamek operator /(Ulamek u1, Ulamek u2)
        {
            Ulamek wynik = new Ulamek(u1.Licznik * u2.Mianownik, u1.Mianownik * u2.Licznik);
            wynik.Uprosc();
            return wynik;
        }

        //operatory logiczne
        public static bool operator ==(Ulamek u1, Ulamek u2)
        {
            return (u1.ToDouble() == u2.ToDouble());
        }

        public static bool operator !=(Ulamek u1, Ulamek u2)
        {
            return !(u1 == u2);
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Ulamek)) return false;
            Ulamek u = (Ulamek)obj;
            return (this == u);
        }

        public override int GetHashCode()
        {
            return licznik ^ mianownik;
        }

        public static bool operator >(Ulamek u1, Ulamek u2)
        {
            return (u1.ToDouble() > u2.ToDouble());
        }

        public static bool operator >=(Ulamek u1, Ulamek u2)
        {
            return (u1.ToDouble() >= u2.ToDouble());
        }

        public static bool operator <(Ulamek u1, Ulamek u2)
        {
            return (u1.ToDouble() < u2.ToDouble());
        }

        public static bool operator <=(Ulamek u1, Ulamek u2)
        {
            return (u1.ToDouble() <= u2.ToDouble());
        }

        //operatory konwersji
        public static explicit operator double(Ulamek u)
        {
            return u.ToDouble();
        }

        public static implicit operator Ulamek(int n)
        {
            return new Ulamek(n);
        }
        #endregion

        #region IComparable
        public int CompareTo(Ulamek u)
        {
            double roznica = this.ToDouble() - u.ToDouble();
            if (roznica != 0) roznica /= Math.Abs(roznica);
            return (int)(roznica);
        }
        #endregion
    }
}
