
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"
			+ "http://www.lundin.info/\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.






