// Michael Tartaglia
// 02 May 2002
// Graphing Math package functions on a purposefully offset graph

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class Graph extends Applet
implements AdjustmentListener,
           ItemListener
{
   private double x, y, intercept;	// GRAPH XY COORDINATES
   private int graphX = 49,			// WHERE GRAPH'S UPPER-LEFT IS TO START (X)
               graphY = 65,			// WHERE GRAPH'S UPPER-LEFT IS TO START (Y)
               maxX = 300,				// MAXIMUM WIDTH OF GRAPH
               maxY = 300;  			// MAXIMUM HEIGHT OF GRAPH
   private Label instruct;				// INSTRUCTIONS
   private Choice equations;			// LIST OF BUILT IN EQUATIONS
   private Scrollbar zoomFactor;		// ZOOM SCROLLER

   public void init() {
      setBackground(Color.white);
      setLayout(new FlowLayout(FlowLayout.CENTER, 10, 2));

		// CREATE LIST OF EQUATIONS
      equations = new Choice();
      equations.addItem("Select function: ");
      equations.addItem("sin x");
      equations.addItem("cos x");
      equations.addItem("tan x");
      equations.addItem("acos x");
      equations.addItem("asin x");
      equations.addItem("atan x");
      equations.addItem("|x|");
      equations.addItem("x");
      equations.addItem("x^2");
      equations.addItem("x^3");
      equations.addItem("e^x");
      equations.addItem("log x base e");
      equations.addItem("x^.5");
      equations.addItem("random * x");
		equations.addItem("(1/8)(x^2) - 2x + 1");

      equations.addItemListener(this);

      instruct = new Label("   Zoom (+ <--> -):");
      instruct.setFont(new Font("Arial",Font.BOLD,11));
      instruct.setBackground(Color.white);

      zoomFactor = new Scrollbar(0, 53, 10, 1, 120);
      zoomFactor.addAdjustmentListener(this);

      add(equations);
      add(instruct); add(zoomFactor);
   }
   

	// WHEN AN OBJECT'S VALUE HAS BEEN ADJUSTED OR CHANGED ...
   public void adjustmentValueChanged(AdjustmentEvent e) {doIt();}
   public void itemStateChanged(ItemEvent e) {doIt();}

	// ... TEMPORARILY CLOSE ALL OBJECTS UNTIL PAINTING IS OVER
   public void doIt() {
      equations.setEnabled(false);
      zoomFactor.setEnabled(false);
      repaint();
      equations.setEnabled(true);
      zoomFactor.setEnabled(true);
   }


   public void paint(Graphics g) {
		// DRAW Y = 0 AND X = 0 LINES
      g.setColor(Color.black);
      g.drawLine(graphX+(maxX/2), graphY, graphX+(maxX/2), graphY+maxY);
      g.drawLine(graphX+(maxX/2), graphY, graphX+(maxX/2), graphY+maxY);
      g.drawLine(graphX, graphY+(maxY/2), graphX+maxX, graphY+(maxY/2));
      g.setColor(Color.white);
      g.drawRect(graphX+(maxX/2)-1,graphY+(maxY/2)-1,2,2);

		// SET COLOR OF GRAPH
      g.setColor(Color.blue);
      if (equations.getSelectedIndex() != 0) {
         double oldX = 0-maxX*30,	// SET PREVIOUS X COORDINATE IN UPPER LEFT OF GRAPH
         oldY = 0-maxY*30,				// SET PREVIOUS Y COORDINATE IN UPPER LEFT OF GRAPH
         newX, newY;						// NEW XY POINTS
         for (x = 0-(maxX/2); x <= (maxX/2); x += .01) {
				// INCREMENTING X BY 1/100th, PLOT THE VALUES ON THE GRAPH, POINT TO POINT,
				//    BUT USING LINES... MOVE FROM LEFT TO RIGHT PLOTTING POINTS
            y = graphY+(maxY/2)-evalEquation(x);		// GET NEW Y COORDINATE
            if (oldX < 0-(maxX/2)) {oldX=x;oldY=y;}
            newX = x; newY = y;
            g.drawLine((int)oldX + graphX+maxX/2,		// DRAW LINE BETWEEN LAST POINT AND NEWLY
                       (int)oldY,							//    ... CALCULATED ONE
                       (int)newX + graphX+maxX/2,
                       (int)newY);
            oldX = newX; oldY = newY;						// RESET OLD POINTS
         }
      }
      showInterceptMessage(g);				// DISPLAY Y-INTERCEPT INFORMATION
   }



   public void showInterceptMessage(Graphics g) {
      String mesg;
		
		// DISPLAY MESSAGE AS LONG AS AN EXQUATION WAS SELECTED
      if (equations.getSelectedIndex() != 0)
         mesg = "The y-intercept is at (0.0, "+intercept+").";
      else mesg = "Please choose a function!";
      g.setFont(new Font("Courier",Font.BOLD+Font.ITALIC,12));
		
		// CREATE 1-PIXEL BORDER OF WHITE AROUND TEXT SO IT REMAINS READABLE BY USER
      g.setColor(Color.white);
      g.drawString(mesg,graphX-1,graphY-1);
      g.drawString(mesg,graphX+1,graphY-1);
      g.drawString(mesg,graphX-1,graphY+1);
		
		// DRAW MESSAGE WITH GREY DROP SHADOW
      g.setColor(new Color(220,220,220));
      g.drawString(mesg,graphX+1,graphY+1);
      g.setColor(new Color(180,0,0));
      g.drawString(mesg,graphX,graphY);

   }


   public double evalEquation(double x)
	{
	// FUNCTION: use passed x value to calculate y value...
   //				zooming occurs by increasing the calculated value
	//				of y, uniformly throughout the graph< by a factor
	// 			base-10
      int zoom = zoomFactor.getValue();
      switch (equations.getSelectedIndex()) {
         case 1: intercept = 0;
                 return Math.sin(x/zoom) * zoom;
         case 2: intercept = 1;
                 return Math.cos(x/zoom) * zoom;
         case 3: intercept = 0;
                 return Math.tan(x/zoom) * zoom;
         case 4: intercept = 0;
                 return Math.asin(x/zoom) * zoom;
         case 5: intercept = Math.acos(0);
                 return Math.acos(x/zoom) * zoom;
         case 6: intercept = 0;
                 return Math.atan(x/zoom) * zoom;
         case 7: intercept = 0;
					  return Math.abs(x);
         case 8: intercept = 0;
					  return x;
         case 9: intercept = 0;
					  return (x*x)/zoom;
         case 10: intercept = 0;
						return (x*x*x)/zoom;
         case 11: intercept = 1;
						return (Math.exp(x/zoom))*zoom;
         case 12: intercept = Math.log(0);
						return (Math.log(x/zoom))*zoom;
         case 13: intercept = 0;
						return Math.sqrt(x/zoom)*zoom;
         case 14: intercept = 0;
						return Math.random()*100*x;
			case 15: intercept = 1;
						return ((.125*x*x) - (2*x) + 1) * zoom;

         }
         return x;
      }

   }
