import java.awt.*;
import java.applet.*;
import java.awt.event.*;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;

public class FractalRecursion extends Applet implements ItemListener
{

   Choice      recursionLevel = new Choice();
   Choice      fractalShape = new Choice();


   public void init()
   {
      setLayout(new FlowLayout());

      recursionLevel.add("1");
      recursionLevel.add("2");
      recursionLevel.add("3");
      recursionLevel.add("4");
      recursionLevel.add("5");
      recursionLevel.add("6");
      recursionLevel.add("7");
      recursionLevel.add("8");
      recursionLevel.add("9");

      fractalShape.add("Triangle");
      fractalShape.add("Square");

      add(new Label("Selection Menu for Detail Level: "));
      add(new Label("Selection Menu for Shape Type: "));
      add(recursionLevel);
      add(fractalShape);

      recursionLevel.addItemListener(this);
      fractalShape.addItemListener(this);
   }

   public void paint(Graphics g)
   {
      Graphics2D g2 = (Graphics2D) g;

      n = new Integer(recursionLevel.getItem(recursionLevel.getSelectedIndex())).intValue();

      if(fractalShape.getItem(fractalShape.getSelectedIndex()) == "Triangle")
      {
         this.trianglePrint(0.0, 0.0, 400.0, 0.0, n);
      }

      else if(fractalShape.getItem(fractalShape.getSelectedIndex()) == "Square")
      {
         if (n > 7)
         {
            g2.drawString("Please enter a lesser degree of accuracy for square fractal.", 150, 150);
         }
         else
         {
         this.squarePrint(0.0, 0.0, 400.0, 0.0, n);
         }
      }

      if (fractal.size() != 0)
      {
         for (int i = 0; i < fractal.size(); i++)
         {
            Line2D.Double path = fractal.get(i);
            g2.draw(path);
         }
      }
   }

   public void itemStateChanged(ItemEvent select)
   {
      fractal.clear();
      repaint();
   }

   public void trianglePrint(double x1, double y1, double x2, double y2, int n)
   {
      double dx, dy, x1n, y1n, x2n, y2n, xexp, yexp;

      if(n > 0)
      {
         dx = (x2-x1)/3.;
         dy = (y2-y1)/3.;

         x1n = x1+dx;
         y1n = y1+dy;

         x2n = x1+2.*dx;
         y2n = y1+2.*dy;

         xexp = .5 * dx - .866 *dy +x1n;
         yexp = .5 * dy + .866 *dx +y1n;

         trianglePrint(x1, y1, x1n, y1n, n-1);
         trianglePrint(x1n, y1n, xexp, yexp, n-1);
         trianglePrint(xexp, yexp, x2n, y2n, n-1);
         trianglePrint(x2n, y2n, x2, y2, n-1);
      }


      else
      {
         Line2D.Double path = new Line2D.Double(x1 + 100, -y1 + 250, x2 + 100, -y2 + 250);
         fractal.add(path);
      }
   }

   public void squarePrint(double x1, double y1, double x2, double y2, int n)
   {
      double dx, dy, x1n, y1n, x2n, y2n, xexp, yexp;

      if(n > 0)
      {
         dx = (x2-x1)/3.;
         dy = (y2-y1)/3.;

         x1n = x1+dx;
         y1n = y1+dy;

         x2n = x1+2.*dx;
         y2n = y1+2.*dy;

         xexp = x1n + .9*dx - .9*dy;
         yexp = y1n + .9*dx;

         squarePrint(x1, y1, x1n, y1n, n-1);
         squarePrint(x1n, y1n, x1n, yexp, n-1);
         squarePrint(x1n, yexp, xexp, yexp, n-1);
         squarePrint(xexp, yexp, xexp, y2n, n-1);
         squarePrint(xexp, y2n, x2n, y2n, n-1);
         squarePrint(x2n, y2n, x2, y2, n-1);
      }

      else
      {
         Line2D.Double path = new Line2D.Double(x1 + 100, -y1 + 250, x2 + 100, -y2 + 250);
         fractal.add(path);
      }
   }

   private ArrayList<Line2D.Double> fractal = new ArrayList<Line2D.Double>();
   private int n;
}



