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

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

        public Ulamek(int licznik, int mianownik)
        {
            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, 1);
        public static Ulamek Jeden = new Ulamek(1, 1);
        public static Ulamek Polowa = new Ulamek(1, 2);
        public static Ulamek Cwierc = new Ulamek(1, 4);

        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 (mianownik == 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());
        }
                
        //konwersja z Ulamek na double
        public static explicit operator double(Ulamek u)
        {
            return u.ToDouble();
        }

        //konwersja z int na Ulamek
        public static implicit operator Ulamek(int n)
        {
            return new Ulamek(n,1);
        }         
        #endregion

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