
import lundin.SymbolicMath.Eval;
import lundin.SymbolicMath.Derive;
import java.applet.Applet;
import java.util.*;
import java.awt.*;


public final class Calculator extends Applet{

	Eval ev = null;
	Derive de = null;
	TextField tf = null;
	Button info,clear,equa,plus,minus,divide,mult;
	Button zerow,one,two,three,four,five,six,seven;
	Button eight,nine,point;
	Hashtable values = null;

	
	public void init()
	{	
		int color = 0x000000;
		String temp = "";
		GridBagLayout gb = null;
		GridBagConstraints gbc = null;
		
		ev = new Eval();
		de = new Derive();
		values = new Hashtable();
		
		gb = new GridBagLayout();
		gbc = new GridBagConstraints();
	
		this.setLayout( gb );
		this.setFont( new Font( "Dialog" , Font.BOLD, 11 ) );
		
		tf = new TextField( "" , 35 );
		
		info = new Button( "Info" );
		clear = new Button( "Clear" );
		plus = new Button( "+" );	
		minus = new Button( "-" );
		mult = new Button( "*" );
		divide = new Button( "/" );
		equa = new Button( "=" );
		point = new Button( "." );
		zerow = new Button( "0" );
		one = new Button( "1" );
		two = new Button( "2" );
		three = new Button( "3" );
		four = new Button( "4" );
		five = new Button( "5" );
		six = new Button( "6" );
		seven = new Button( "7" );
		eight = new Button( "8" );
		nine = new Button( "9" );
				
				
		this.setBackground( new Color( color ) );
		
		tf.setBackground( Color.white );
		tf.setForeground( Color.black );
		
		info.setBackground( new Color( 0x000066 ) );
		clear.setBackground( new Color( 0x660000 ) );
		plus.setBackground( Color.gray );
		minus.setBackground( Color.gray );
		mult.setBackground( Color.gray );
		divide.setBackground( Color.gray );
		equa.setBackground( new Color( 0x006600 ) );
		
		point.setBackground( Color.lightGray );
		zerow.setBackground( Color.lightGray );
		one.setBackground( Color.lightGray );
		two.setBackground( Color.lightGray );
		three.setBackground( Color.lightGray );
		four.setBackground( Color.lightGray );
		five.setBackground( Color.lightGray );
		six.setBackground( Color.lightGray );
		seven.setBackground( Color.lightGray );
		eight.setBackground( Color.lightGray );
		nine.setBackground( Color.lightGray );
			
		info.setForeground( Color.white );
		clear.setForeground( Color.white );
		plus.setForeground( Color.white );
		minus.setForeground( Color.white );
		mult.setForeground( Color.white );
		divide.setForeground( Color.white );
		equa.setForeground( Color.white );
		point.setForeground( Color.white );
		zerow.setForeground( Color.white );
		one.setForeground( Color.white );
		two.setForeground( Color.white );
		three.setForeground( Color.white );
		four.setForeground( Color.white );
		five.setForeground( Color.white );
		six.setForeground( Color.white );
		seven.setForeground( Color.white );
		eight.setForeground( Color.white );
		nine.setForeground( Color.white );		
		
		setConstr( gbc, 0, 0, 4, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  tf , gbc );
		setConstr( gbc, 0, 1, 1, 1, 25, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  seven , gbc );
		setConstr( gbc, 1, 1, 1, 1, 25, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  eight , gbc );
		setConstr( gbc, 2, 1, 1, 1, 25, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  nine , gbc );
	
		setConstr( gbc, 3, 1, 1, 1, 25, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  plus , gbc );											
		setConstr( gbc, 0, 2, 1, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  four , gbc );
		setConstr( gbc, 1, 2, 1, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  five , gbc );
		setConstr( gbc, 2, 2, 1, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  six , gbc );
		
		setConstr( gbc, 3, 2, 1, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  minus , gbc );
		setConstr( gbc, 0, 3, 1, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  one , gbc );	
		setConstr( gbc, 1, 3, 1, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  two , gbc );
		setConstr( gbc, 2, 3, 1, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  three , gbc );
		
		setConstr( gbc, 3, 3, 1, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  mult , gbc );
		setConstr( gbc, 0, 4, 1, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  equa , gbc );
		setConstr( gbc, 1, 4, 1, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  zerow , gbc );	
		setConstr( gbc, 2, 4, 1, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  point , gbc );
		
		setConstr( gbc, 3, 4, 1, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  divide , gbc );
		setConstr( gbc, 0, 5, 2, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  clear , gbc );
		setConstr( gbc, 2, 5, 2, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, 2, 2, 2, 2 );	
		gb.setConstraints(  info , gbc );
									
		
		add( tf );
		add( seven );	
		add( eight );		
		add( nine );		
		add( plus );		
		add( four );		
		add( five );		
		add( six );		
		add( minus );		
		add( one );		
		add( two );		
		add( three );		
		add( mult );		
		add( equa );		
		add( zerow );
		add( point );
		add( divide );		
		add( clear );			
		add( info );	
	
		System.out.println("\n\nApplet Calculator Made by Patrik Lundin, plundin@javathings.com\n\n");	
	}

	private void 
	setConstr( GridBagConstraints gbc, int x, int y, int w, int h, int wx, int wy, int f, int a, int bottom, int left, int right, int top)
	{
		gbc.gridx = x;
	 	gbc.gridy = y;
	  	gbc.gridwidth = w;
	  	gbc.gridheight = h;
	  	gbc.weightx = wx;
	  	gbc.weighty = wy;
	  	gbc.fill = f;
	  	gbc.anchor = a;	
	  	gbc.insets = new Insets( bottom, left, right, top );
	}	
	
	private void
	evaluate()
	{
		String temp = "";
		String tmp = "";
		int ind1 = 0;
		int ind2 = 0;
		
		try{
			
			tmp = prepare( tf.getText().toLowerCase() );
			
			if( tmp.equals("") ){
				return;
			}
			
			// check if is diff, set or clear() command.
			if( ( ind1 = tmp.indexOf("diff(")) != -1 ){
				temp = de.diff( tmp.substring( ind1 + 5, tmp.lastIndexOf(")")))[0];
				
				tf.setText( temp );
				return;
				
			}else if( ( ind1 = tmp.indexOf("set(") ) != -1 ){
				try{	
					ind2 = tmp.lastIndexOf(")");
					temp = tmp.substring( ind1 + 4, ind2 );
					values.put( temp.substring( 0,temp.indexOf("=")) , temp.substring( temp.indexOf("=") + 1, temp.length()));
					tf.setText("Value set, " + getValues());
				}catch(Exception ex){
					tf.setText("Syntax error, " + tmp);
				}
				return;
			}else if( ( ind1 = tmp.indexOf("clear(")) != -1 ){
				if( (ind2 = tmp.lastIndexOf(")")) == -1 ){
					tf.setText("Non matching brackets");
					return;
				}
				temp = tmp.substring( ind1 + 6 , ind2 );
				values.remove( temp );
				tf.setText( "Value cleared, " + getValues() );
				return;
			}else if( tmp.indexOf("memory") != -1 ){
				tf.setText( getValues() );
				return;
			}
			
			
			// normal, evaluate.
			tf.setText( String.valueOf(ev.eval( tmp , values)));


		}catch(Exception ex){
			tf.setText( ex.getMessage());
		}
	}

	
	private String
	getValues()
	{
		String temp = "";
		String tmp = "";
		Enumeration en = values.keys();
		
		while( en.hasMoreElements() )
		{
			tmp = (String)en.nextElement();
			if( temp.equals("") )
			{
				temp = tmp + "=" + (String)values.get( tmp );  	
			}
			else
			{
				temp += ";" + tmp + "=" + (String)values.get( tmp );
			}
		}
		
		return temp;
	}
	
	
	public boolean 
	keyDown(Event event, int key)
	{
		char c = (char)key;
		tf.requestFocus();
		if( c == '\n' )
		{
			evaluate();
			return true;
		}
		
		return false;
	}


	public boolean
	handleEvent(Event event)
	{
	
		if( event.id == Event.ACTION_EVENT )
		{
			if( event.target == info ){
				new Message("Info", information() );
				return true;
			}else if( event.target == equa ){
				evaluate();
				return true;
			}else if( event.target == clear ){
				tf.setText("");
				return true;
			}
		}
		
		return super.handleEvent(event);
	}


	public boolean
	action(Event event, Object ob)
	{
		if( event.target instanceof Button ){
			tf.setText( tf.getText() + (String)ob );
			return true;
		}
		
		return false;
	}


	private String 
	information()
	{
		String message = 
		  	  "			SimpleCalc\n"
			+ "			----------\n"
			+ "This is a simple Java Calculator with advanced functions :-D\n"
			+ "You can use the mouse or the keyboard and then press the [=] button or\n" 
			+ "press enter to evaluate.\n\n"
			+ "For the more advanced functions you'll have use the keyboard.\n\n"
			+ " The calculator supports these operators and functions:\n"
			+ "-------------------------------------------------\n\n"
			+ " +              addition\n"
			+ " -              subtraction\n"
			+ " *              multiplication\n"
			+ " /              division\n"
			+ " ^               power to\n"
			+ " %             modulo\n"
			+ " sin()         sinus\n"
			+ " cos()        cosinus\n"
			+ " tan()         tangent\n"
			+ " atan()       arcustangent\n"
			+ " asin()       arcussinus\n"
			+ " acos()       arcuscosinus\n"
			+ " sinh()        hyperbolicsinus\n"
			+ " cosh()       hyperboliccosinus\n"
			+ " tanh()       hyperbolictangens\n"
			+ " exp()        constant E raised to\n"
			+ " ln()           natural logarithm\n"
			+ " [n]log()     any logaritm, base n\n"
			+ " sqrt()       squareroot\n"
			+ " cotan()      cotangens\n"
			+ " acotan()    inverted cotangens\n"
			+ " abs()         absolute value of\n"
			+ " ceil()         ceil, ceil(2.3) = 3\n"
			+ " floor()       floor, floor(1.23) = 1\n"
			+ " fac()         faculty, fac(n) = n*(n-1)*(n-2)*..*1\n"
			+ " sfac()        semifaculty, sfac(n) = n*(n-2)*(n-4)*..4*2 if n even,\n"
			+ "                  sfac(n) = n*(n-2)*(n-4)*..3*1 if n is noteven\n"
			+ " round()      round\n"
			+ " fpart()       decimal part of\n\n"
			+ "Logical operators :\n"
			+ "-----------------\n\n"
			+ " ==             equal, returns 1.0 if arguments are equal, 0.0 otherwise\n"
			+ " !=              not equal, returns 1.0 if arguments is not equal, 0.0 otherwise\n"
			+ " !                not, returns 0.0 if it's argument is 1.0, 1.0 otherwise\n"
			+ " &&            and, returns 1.0 if argumnets both evaluates to 1.0, 0.0 otherwise\n"
			+ " ||               or, returns 1.0 if any argument evaluates to 1.0, 0.0 otherwise\n"
			+ " >               larger than, returns 1.0 if left side is larger than the right side\n"
			+ " <               less than, returns 1.0 if left side is less than the right side\n"
			+ " <=             less than or equal, returns 1.0 if left side is less than or equal the right side\n"
			+ " >=             larger than or equal, returns 1.0 if left side is larger than or equal the right side\n\n"
			+ "Special functions :\n"
			+ "-----------------\n\n"
			+ "diff( )         will symbolically differentiate a mathematical\n"
			+ "                  expression of one variable.\n"
			+ "                  Ex. diff( x^2-2*x ) will return 2*x-2\n"
			+ "                  To evaluate a differentiated expression first use\n"
			+ "                  set( ) to store values in the variable currently used\n"
			+ "                  and then differentiate and then press enter again to evaluate.\n"
			+ "                  Ex. set(x=2) [enter] returns \"Value set\" as confirmation\n"
			+ "                        diff(x^2) [enter] returns 2*x\n"
			+ "                        [enter] evaluates 2*x and returns 4\n"
			+ "set( )          will set a variable so it can be used in a calculation.\n"
			+ "                   Ex. set(x=5) x will be set to 5 so the calculation x^3\n"
			+ "                   will evaluate to 125.\n"
			+ "                   You can also store a calculation directly like : set(x=3*(5-2)/7)\n"
			+ "                    x will be set to 3*(5-2)/7\n"
			+ "clear( )        Clears a stored variable.\n"
			+ "                   Ex. clear(x) will clear the variable x, any calculation\n"
			+ "                   with x in it after calling clear(x) will generate the error:\n"
			+ "                  \"No value associated with x\"\n"
			+ "memory          Will show all values currently in memory.\n"
			+ "                        values will still be in memory after pressing the [clear] button,\n"
			+ "                        use clear( ) to clear a value in memory.\n\n"
			+ "Please note that diff( ) , set( ), memory and clear( ) cannot be used as a part of\n"
			+ "an expression, this will not generate an error but will just\n"
			+ "cause the first occurance of any of the commands to be evaluated.\n"
			+ "for example: 2*5-diff(x^3) will just cause diff(x^3) to be evaluated.\n\n"
			+ "Constants supported:\n"
			+ "-------------------\n\n"
 			+ "Pi            pi, 3.1415...\n"
 			+ "Euler       base for the natural logarithm, 2.7182..\n"
 			+ "true        1.0\n"
 			+ "false       0.0\n\n"
			+ "Operator precedence in order of evaluation:\n"
			+ "---------------------------------------\n"
			+ "( you can always change the order of evaluation by using paranthesis. )\n\n"
			+ "!\n"
			+ "cos sin tan sqrt exp.....etc\n"
			+ "^\n"
			+ "* / %\n"
			+ "log\n"
			+ "+ -\n"
			+ ">  >=  <  <=\n"
			+ "==  !=\n"
			+ "||\n"
			+ "&&\n\n"
			+ "Applet Calculator Made by Patrik Lundin,\n"
			+ "plundin@javathings.com  \n"
			+ "http://www.javathings.com/\n";


	
		return message;
	}



	private String
	prepare(String str)
	{
		String nstr = "";
		int i = 0;
		int count = 0;

		
		while( i < str.length() ){
		
			if(str.charAt( i ) == '('){
      			count++;
    		}else if(str.charAt( i ) == ')'){
      			count--;
			}
			
			if( str.charAt( i ) != ' ' ){
				nstr += str.charAt( i );
			}
			
			i++;
		}
		
		if( count != 0 ){
			tf.setText("Non matching brackets, " + str);
			return "";
		} 
		
		return nstr;
	}
	

  


}// end class calculator.



class Message extends Frame{

	
	public 
	Message(String title, String message)
	{
		super();
		GridBagLayout gridb = new GridBagLayout();
	    	GridBagConstraints constr = new GridBagConstraints();
		Message a = new Message(title);
		a.setLayout( gridb );
		TextArea p = new TextArea( message );
		p.resize( 250 , 250 );
		Button b = new Button("OK, Close This Window");
		constr.fill = GridBagConstraints.BOTH;
		constr.anchor = GridBagConstraints.NORTH;
		constr.gridx = 0;
		constr.gridy = 0;
		gridb.setConstraints( p , constr );
		a.add( p );
		constr.fill = GridBagConstraints.HORIZONTAL;
		constr.anchor = GridBagConstraints.CENTER;
		constr.gridx = 0;
		constr.gridy = 1;
		gridb.setConstraints( b , constr );
		a.add( b );
		a.pack();
		a.show();
	}
	
	public Message(String s)
	{
		super(s);
	}
	
	public boolean
	action(Event ev, Object o)
	{
	
		this.hide();
		this.dispose();			
	
		return true;		
	}
	
	
} // end class Message.





