import java.util.Scanner;

class Frazione {
	static int conto;
	int num;
	int den;
}


class Exp {
	int codice; //0->frazione semplice 1->+ 2->* 3->- 4->/
	Frazione f;
	Exp e1;
	Exp e2;
}

public class MainClass {

	static Scanner s;
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Frazione.conto=0;
		
		MainClass.s = new Scanner(System.in);
		
		Exp e = creaExpProdotto( creaExpSomma(
				                     creaExpFrazione( creaFrazione(3,1) ),
				                     creaExpFrazione( creaFrazione(1,2) )
				                  ),
				                 creaExpFrazione(creaFrazione(5,4))
				               );
		
		
		Frazione risultato = evalExp(e);
		
		stampaExp(e);
		
		System.out.print (" = ");
		
		stampaFrazione (risultato);
		
		System.out.println();
		
		e = leggiExp();
        
		risultato = evalExp(e);
		
		stampaExp(e);
		
		System.out.print (" = ");
		
		stampaFrazione (risultato);
		
		/*
		Frazione f1=leggiFrazione();
		Frazione f2=leggiFrazione();
		
		stampaFrazione(f1);
		stampaFrazione(f2);
		System.out.println();
	
		riduciFrazione(f1);
		riduciFrazione(f2);
		
		stampaFrazione(f1);
		stampaFrazione(f2);
	    System.out.println();
	    
		stampaFrazione (sommaFrazione(f1,f2));
		*/
		System.out.println();
		System.out.println("Nel programma sono state create " +
		                    Frazione.conto + " frazioni.");
	    
		
		s.close();
	}
	
	static Exp leggiExpOld (){
		System.out.println();
		System.out.println("0 - frazione semplice");
		System.out.println("1 - somma");
		System.out.println("2 - prodotto");
		System.out.println("3 - differenza");
		System.out.println("4 - divisione");
		System.out.print("Inserisci la tua scelta: ");
		int scelta;
		do {
			scelta= s.nextInt();
			s.nextLine();
		} while (scelta<0 || scelta>4);
		Exp e1=null, e2=null;
		switch (scelta){
		case 0:
			/*
			 * Frazione f = leggiFrazione();
			 * e = creaExpFrazione(f);
			 * return e;
			 */
			return creaExpFrazione( leggiFrazione() );
		case 1:
			System.out.println("Inserisci il primo addendo: ");
			e1 = leggiExpOld();
			System.out.println("Inserisci il secondo addendo: ");
			e2 = leggiExpOld();
			return creaExpSomma (e1, e2);
		case 2:
			System.out.println("Inserisci il primo fattore: ");
			e1 = leggiExpOld();
			System.out.println("Inserisci il secondo fattore: ");
			e2 = leggiExpOld();
			return creaExpProdotto (e1, e2);
		case 3:
			System.out.println("Inserisci il minuendo: ");
			e1 = leggiExpOld();
			System.out.println("Inserisci il sottraendo: ");
			e2 = leggiExpOld();
			return creaExpDifferenza (e1, e2);
		case 4:
			System.out.println("Inserisci il dividendo: ");
			e1 = leggiExpOld();
			System.out.println("Inserisci il divisore: ");
			e2 = leggiExpOld();
			return creaExpDivisione (e1, e2);
		}
		return null;		
	}

	static Exp leggiExp () {
		Exp e = leggiExpCrea(null);
		leggiExpRiempi(e,e);
		return e;
	}
	
	
	static void leggiExpRiempi (Exp e, Exp mainExp){
		switch (e.codice){
		case 0:
			e.f = leggiFrazione();
			break;
		case 1:
		case 2:
		case 3:
		case 4:
			e.e1=leggiExpCrea(mainExp);
			leggiExpRiempi(e.e1,mainExp);
			e.e2=leggiExpCrea(mainExp);
			leggiExpRiempi(e.e2,mainExp);
			break;	
			
		}
	}
	
	static Exp leggiExpCrea (Exp mainExp){
		System.out.print ("Inserisci la sottoespressione " 
	                        +" corrispondente al primo ? in ");
		stampaExp(mainExp);
	    System.out.println();
		System.out.println("0 - frazione semplice");
		System.out.println("1 - somma");
		System.out.println("2 - prodotto");
		System.out.println("3 - differenza");
		System.out.println("4 - divisione");
		System.out.print("Inserisci la tua scelta: ");
		int scelta;
		do {
			scelta= s.nextInt();
			s.nextLine();
		} while (scelta<0 || scelta>4);
		
		switch (scelta){
		case 0:
			return creaExpFrazione( null );
		case 1:
			return creaExpSomma (null, null);
		case 2:
			return creaExpProdotto (null, null);
		case 3:
			return creaExpDifferenza (null, null);
		case 4:
			return creaExpDivisione (null, null);
		}
		return null;		
	}
	
	static Exp creaExpFrazione (Frazione f){
		Exp e = new Exp ();
		e.codice=0;
		e.f=f;
		e.e1=null;
		e.e2=null;
		return e;
	}
	
	static Exp creaExpSomma (Exp e1, Exp e2){
		Exp e = new Exp ();
		e.codice=1;
		e.f=null;
		e.e1=e1;
		e.e2=e2;
		return e;
	}
	
	static Exp creaExpProdotto (Exp e1, Exp e2){
		Exp e = new Exp ();
		e.codice=2;
		e.f=null;
		e.e1=e1;
		e.e2=e2;
		return e;
	}
	
	static Exp creaExpDifferenza (Exp e1, Exp e2){
		Exp e = new Exp ();
		e.codice=3;
		e.f=null;
		e.e1=e1;
		e.e2=e2;
		return e;
	}
	
	static Exp creaExpDivisione (Exp e1, Exp e2){
		Exp e = new Exp ();
		e.codice=4;
		e.f=null;
		e.e1=e1;
		e.e2=e2;
		return e;
	}
	
	static void stampaExp (Exp e){
		if (e==null){
			System.out.print("?");
			return;
		}
		switch (e.codice){
		case 0:
			stampaFrazione (e.f);
			break;
		case 1:
			System.out.print ("(");
			stampaExp (e.e1);
			System.out.print ("+");
			stampaExp (e.e2);
			System.out.print (")");
			break;
		case 2:
			System.out.print ("(");
			stampaExp (e.e1);
			System.out.print ("*");
			stampaExp (e.e2);
			System.out.print (")");
			break;
		case 3:
			System.out.print ("(");
			stampaExp (e.e1);
			System.out.print ("-");
			stampaExp (e.e2);
			System.out.print (")");
			break;
		case 4:
			System.out.print ("(");
			stampaExp (e.e1);
			System.out.print ("/");
			stampaExp (e.e2);
			System.out.print (")");
			break;		
		}
	}
	
	
	static Frazione evalExp (Exp e){
		switch (e.codice){
		case 0:
			Frazione copia = copiaFrazione (e.f);
			riduciFrazione(copia);
			return copia;
		case 1:
			return sommaFrazione( evalExp(e.e1), evalExp(e.e2));
		case 2:
			return prodottoFrazione( evalExp(e.e1), evalExp(e.e2));
		case 3:
			return differenzaFrazione( evalExp(e.e1), evalExp(e.e2));
		case 4:
			return divisioneFrazione( evalExp(e.e1), evalExp(e.e2));
		}
		return null;
	}
	
	static Frazione leggiFrazione(){
		System.out.print ("Inserisci il numeratore: ");
		int num = s.nextInt();
		s.nextLine();
		System.out.print ("Inserisci il denominatore: ");
		int den = s.nextInt();
		s.nextLine();
		return creaFrazione(num,den);		
	}
	
	static Frazione creaFrazione(int num, int den){
		Frazione f = new Frazione();
		Frazione.conto++;
		f.num=num;
		f.den=den;
		return f;
	}
	
	static boolean ugualeFrazione (Frazione a, Frazione b){
		if (a==null || b==null) return false;
		return a.num==b.num && a.den==b.den;
	}
	
	static boolean propriaFrazione (Frazione a){
		if (a==null) return false;
		int num = (a.num>0)?a.num:-a.num;
		int den = (a.den>0)?a.den:-a.den;
		return num<den;
	}
	
	static boolean apparenteFrazione (Frazione a){
		if (a==null) return false;
		return a.num%a.den==0;
	}
	
	//Algoritmo di Euclide
	static int MCD (int a, int b){
		a = abs(a);
		b = abs(b);
		int max = (a>b)?a:b;
		int min = (a<b)?a:b;
		while (min>0){
			int resto=max%min;
			max=min;
			min=resto;			
		}
		return max;
	}
	
	static int mcm(int a, int b){
		return a/MCD(a,b)*b;
	}
	
	static void riduciFrazione(Frazione a){
		if (a==null) return;
		int MCD=MCD(a.num, a.den);
		if (MCD!=0){
			a.num /= MCD;
			a.den /= MCD;
		}
	}
	
	static Frazione sommaFrazione(Frazione a, Frazione b){
		if (a==null || b== null ) return null;
		Frazione risultato=new Frazione();
		Frazione.conto++;
		Frazione copiaA = copiaFrazione(a);
		Frazione copiaB = copiaFrazione(b);
		riduciFrazione(copiaA);
		riduciFrazione(copiaB);
		int mcmDen = mcm(copiaA.den,copiaB.den);
		risultato.den=mcmDen;
		risultato.num = mcmDen/copiaA.den*copiaA.num + 
				         mcmDen/copiaB.den*copiaB.num;
		riduciFrazione(risultato);
		return risultato;
	}
	
	static Frazione copiaFrazione (Frazione a){
		if (a==null) return null;
		return creaFrazione (a.num, a.den);
	}
	
	static Frazione prodottoFrazione(Frazione a, Frazione b){
		if (a==null || b== null ) return null;
		Frazione risultato=new Frazione();
		Frazione copiaA = copiaFrazione(a);
		Frazione copiaB = copiaFrazione(b);
		riduciFrazione(copiaA);
		riduciFrazione(copiaB);
		int MCD1=MCD(copiaA.num,copiaB.den);
		copiaA.num /= MCD1;
		copiaB.den /= MCD1;
		int MCD2=MCD(copiaA.den,copiaB.num);
		copiaA.den /= MCD2;
		copiaB.num /= MCD2;
		risultato.num=copiaA.num*copiaB.num;
		risultato.den=copiaA.den*copiaB.den;
		riduciFrazione(risultato);
		return risultato;
	}
	
	static Frazione oppostaFrazione (Frazione a){
		if (a==null) return null;
		return prodottoFrazione(a, creaFrazione(-1,1));
	}
	
	static Frazione differenzaFrazione(Frazione a, Frazione b){
		if (a==null || b== null ) return null;
		return sommaFrazione (a, oppostaFrazione(b));
	}
	
	static Frazione inversaFrazione (Frazione a){
		if (a==null) return null;
		return creaFrazione(a.den,a.num);
	}
	
	static Frazione divisioneFrazione(Frazione a, Frazione b){
		if (a==null || b== null ) return null;
		return prodottoFrazione (a, inversaFrazione(b));
	}
	
	static int abs(int a){
		return (a>0)?a:-a;
	}
	
	static boolean equivalenteFrazione (Frazione a, Frazione b){
		if (a==null || b==null) return false;
		boolean positiveA = (a.num>=0&&a.den>0 || a.num<=0&&a.den<0)?true:false;
		boolean positiveB = (b.num>=0&&b.den>0 || b.num<=0&&b.den<0)?true:false;
		if (positiveA != positiveB) return false;
		Frazione copiaA = creaFrazione (abs(a.num), abs(a.den));
		Frazione copiaB = creaFrazione (abs(b.num), abs(b.den));
		riduciFrazione(copiaA);
		riduciFrazione(copiaB);
		return ugualeFrazione(copiaA,copiaB);
	}
	
	static void stampaFrazione (Frazione a){
		if (a==null) return;
		boolean positiveA = (a.num>=0&&a.den>0 || a.num<=0&&a.den<0)?true:false;
		if (positiveA==false) System.out.print ("(-");
		System.out.print (abs(a.num));
		if (abs(a.den)!=1) System.out.print("/" + abs(a.den));
		if (positiveA==false) System.out.print (")");
		System.out.print(" ");
	}

}
