package edu.uchicago.cs.cspp51035;

import java.util.Scanner;

/*
 * Created on Jun 26, 2005
 *
 */

/**
 * @author yuhu
 *
 */
import java.util.*;
import java.lang.*;


// In this code, I only support + - * /, surely, you can put more if you want
// Please input like 3 4 + = 
// Or 3 4.5 2 * 1 5 - / + = 

// Here the last "=" is necessary !!


public class Calculator {

	static Stack myStack = new Stack(); 
	
	public static void main (String[] args)
	{
		addOp				oneaddOp;
		minusOp			oneminusOp;
		timeOp			onetimeOp;
		divOp				onedivOp; 
		RPNInteger			oneInteger;
		RPNDouble			oneDouble;
		RPNFloat			oneFloat;
		RPNLong			oneLong;
		int				testsum; 
		int				grosstype; // 1: operator ; 2: operand
		int				operatortype, operandtype; 
		Object			oneOb; 
		String			oneInfo;
		String			operatorstring = "I am an Operator";
		String			operandstring = "I am an Operand";
		String			onetext;
		String			addex = "+";
		String			minusex ="-";
		String			mulex = "*";
		String			divex = "/";
		String			equalex = "=";
		int				oneintvalue;
		long			onelongvalue;
		float			onefloatvalue;
		double			onedoublevalue;
		
		
		
		
		
		while (!myStack.empty())
		{
			myStack.pop();
		}
		
	
		// Read the expression and put them into stack
		System.out.println("Please Input the RPN expression");
		
		Scanner In = new Scanner(System.in);
		
		
		while(In.hasNext())
		{
			if ( In.hasNextInt())
			{
				//System.out.println("Got an Integer.");
				oneintvalue = In.nextInt();
				oneInteger = new RPNInteger(oneintvalue);
				myStack.push(oneInteger);
				continue;
			}
			else if (In.hasNextDouble())
			{
				//System.out.println("Got an Double.");
				onedoublevalue = In.nextDouble();
				oneDouble = new RPNDouble(onedoublevalue);
				myStack.push(oneDouble);
				continue;
			}
			else if (In.hasNextLong())
			{
				//System.out.println("Got an Long.");
				onelongvalue = In.nextLong();
				oneLong = new RPNLong(onelongvalue);
				myStack.push(oneLong);
				continue;
			}
			else if (In.hasNextFloat())
			{
				//System.out.println("Got an Float.");
				onefloatvalue = In.nextFloat();
				oneFloat = new RPNFloat(onefloatvalue);
				myStack.push(oneFloat);
				continue;
			}
			else
			{
			
			}
				
			onetext = In.next();
			if ( onetext.equalsIgnoreCase(addex))
			{
				//System.out.println("Got an +.");
				oneaddOp = new addOp(); 
				myStack.push(oneaddOp);
				continue;
			}
			
			if ( onetext.equalsIgnoreCase(minusex))
			{
				//System.out.println("Got an -.");
				oneminusOp = new minusOp(); 
				myStack.push(oneminusOp);
				continue;
			}
			
			if ( onetext.equalsIgnoreCase(mulex))
			{
				//System.out.println("Got an *.");
				onetimeOp = new timeOp(); 
				myStack.push(onetimeOp);
				continue;
			}
			
			if ( onetext.equalsIgnoreCase(divex))
			{
				//System.out.println("Got an /.");
				onedivOp = new divOp(); 
				myStack.push(onedivOp);
				continue;
			}
			
			if ( onetext.equalsIgnoreCase(equalex))
			{
				//System.out.println("Got an =.");
				break;
			}
			
			System.out.println("The format is wrong. Please try again...");	
			return; 			
			
		}
				
		
		// Pop up from stack and caculate
		System.out.println("Begin to Compute...");
		
		oneOb = myStack.pop(); 
		oneInfo = ((StackElement)(oneOb)).getInfo();
			
		if (oneInfo.equalsIgnoreCase(operatorstring))
		{
			grosstype = 1; 
		}
		else 
		{
			System.out.println("Wrong Format, Exiting...");
			return; 
		}
			
		((Operator)(oneOb)).execute(myStack);
		
		// Get the final result
		oneOb = myStack.pop(); 
		operandtype = ((Operand)(oneOb)).type;
		
		if (operandtype == 1)
		{
			oneInteger = (RPNInteger)(oneOb);
			System.out.println("Result is : " + oneInteger.getValue().intValue());
		}
		
		if (operandtype == 2)
		{
			oneLong = (RPNLong)(oneOb);
			System.out.println("Result is : " + oneLong.getValue().longValue());
		}
		
		if (operandtype == 3)
		{
			oneFloat = (RPNFloat)(oneOb);
			System.out.println("Result is : " + oneFloat.getValue().floatValue());
		}
		
		if (operandtype == 4)
		{
			oneDouble = (RPNDouble)(oneOb);
			System.out.println("Result is : " + oneDouble.getValue().doubleValue());
		}
		
		
		
		//System.out.println();
		
		
		
		// Test programs
		/*
		oneInteger = new RPNInteger(3);
		myStack.push(oneInteger);
		
		oneaddOp = new addOp(); 
		myStack.push(oneaddOp);
		
		oneInteger = new RPNInteger(4);
		myStack.push(oneInteger);
		
		testsum = 0; 

		
		
		while(!myStack.empty())
		{
			oneOb = myStack.pop(); 
			oneInfo = ((StackElement)(oneOb)).getInfo();
			
			if (oneInfo.equalsIgnoreCase(operatorstring))
			{
				grosstype = 1; 
			}
			else 
			{
				if (oneInfo.equalsIgnoreCase(operandstring))
				{
					grosstype = 2; 
				}
				else
				{
					System.out.println("Something is wrong. Exiting...");
					return; 
				}
			}
			
			if (grosstype == 1)
			{
				operatortype = ((Operator)(oneOb)).type;
				
				if (operatortype == 1)
				{
					System.out.println("Got an Operator Add.");
				}
				
				
			}
			else if (grosstype == 2)
			{
				operandtype = ((Operand)(oneOb)).type;
				
				if (operandtype == 1)
				{
					System.out.println("Got an Integer");
				}
				
				oneInteger = (RPNInteger)(oneOb);
				testsum += oneInteger.getValue().intValue(); 
				
			}
		}
		
		//oneOb = myStack.pop(); 
		//oneInfo = ((StackElement)(oneOb)).getInfo();
		//System.out.println("2. Got one Info: " + oneInfo);
		
		//oneOb = myStack.pop(); 
		//oneInfo = ((StackElement)(oneOb)).getInfo();
		//System.out.println("3. Got one Info: " + oneInfo);
		
		
		//operatortype = ((Operator)(myStack.pop())).type; 
		//System.out.println("2. Op is  " + operatortype);
		//myStack.pop();
		
		//oneInteger = (RPNInteger) myStack.pop();
		//testsum += oneInteger.getValue().intValue(); 
		//System.out.println("3. Sum is " + testsum);
		
		System.out.println("Sum is " + testsum);
		
		// End of test programs
		*/
		
	
		
		
		
		
	}
	
}
