import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

import java.util.ArrayList;

/**
 * This class defines a panel where the user can sketch
 * curves.  The curves can be of different colors.  Each
 * curve has a "symmetry" option; if it uses symmetry, then
 * the horizontal and vertical reflections of the original
 * curve are also drawn.  A menu bar is available with 
 * menus for selecting the current drawing color and a
 * few other commands.  This class also has a main()
 * routine that just creates a window showing a panel
 * of type SeveralCurves along with its menu bar.
 */
public class SeveralCurves extends JPanel {

   public static void main(String[] args) {
       JFrame window = new JFrame("SeveralCurves");
       SeveralCurves c = new SeveralCurves();
       window.setContentPane(c);
       window.setJMenuBar(c.createMenuBar());
       window.pack();
       window.setLocation(200,100);
       window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       window.setVisible(true);
   }
   
   
   private ArrayList<CurveData> curves;
   private Color currentColor;
   private JCheckBoxMenuItem useSymmetryCheckbox;


   public SeveralCurves() {
      curves = new ArrayList<CurveData>();  // Create the list, initially empty.
      currentColor = Color.BLACK;
      setPreferredSize( new Dimension(500,500) );
      setBackground(Color.WHITE);
      setBorder( BorderFactory.createLineBorder(Color.GRAY,2) );
      MouseHandler mh = new MouseHandler();
      addMouseListener(mh);
      addMouseMotionListener(mh);
   }
   
   
   public JMenuBar createMenuBar() {
      MenuHandler ah = new MenuHandler();

      JMenu controlMenu = new JMenu("Control");

      JMenuItem clear = new JMenuItem("Clear");
      clear.addActionListener(ah);
      controlMenu.add(clear);

      JMenuItem undo = new JMenuItem("Undo");
      undo.addActionListener(ah);
      controlMenu.add(undo);
      useSymmetryCheckbox = new JCheckBoxMenuItem("Use Symmetry");
      useSymmetryCheckbox.setSelected(true);
      controlMenu.add(useSymmetryCheckbox);

      controlMenu.addSeparator();

      JMenuItem quit = new JMenuItem("Quit");
      quit.addActionListener(ah);
      controlMenu.add(quit);
      
      JMenu colorMenu = new JMenu("Color");
      String[] colors = new String[] { "Black", "Red", "Green", "Blue", "Cyan", "Magenta", "Yellow" };
      for (int i = 0; i < colors.length; i++) {
         JMenuItem c = new JMenuItem(colors[i]);
         c.addActionListener(ah);
         colorMenu.add(c);
      }
      
      JMenuBar menubar = new JMenuBar();
      menubar.add(controlMenu);
      menubar.add(colorMenu);
      return menubar;
   }
   
   
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      int w = getWidth();  // The actual current width of this panel.
      int h = getHeight(); // The actual current height of this panel.
      for (int i = 0; i < curves.size(); i++) {
         CurveData thisCurve = curves.get(i);
         g.setColor(thisCurve.color);  // Use this curve's color.
         for (int j = 1; j < thisCurve.points.size(); j++) {
            Point thisPt = thisCurve.points.get(j);
            Point lastPt = thisCurve.points.get(j-1);
            g.drawLine(lastPt.x, lastPt.y, thisPt.x, thisPt.y); // original curve
            if (thisCurve.useSymmetry) {  // Draw reflections only if this curve uses symmetry.
               g.drawLine(w-lastPt.x, lastPt.y, w-thisPt.x, thisPt.y);       // horizontal reflection
               g.drawLine(lastPt.x, h-lastPt.y, thisPt.x, h-thisPt.y);       // vertical reflection
               g.drawLine(w-lastPt.x, h-lastPt.y, w-thisPt.x, h-thisPt.y);   // double reflection
            }
         }
      }
   }
   
   
   private static class CurveData {
      ArrayList<Point> points;
      Color color;
      boolean useSymmetry;
   }
   
   
   private class MenuHandler implements ActionListener {
      public void actionPerformed(ActionEvent evt) {
         String cmd = evt.getActionCommand();
         if (cmd.equals("Clear")) {
            curves.clear();
            repaint();
         }
         else if (cmd.equals("Undo")) {
             if (curves.size() > 0) {
                curves.remove(curves.size()-1);
                repaint();
             }
         }
         else if (cmd.equals("Quit")) {
             System.exit(0);
         }
         else if (cmd.equals("Black"))
             currentColor = Color.BLACK;
         else if (cmd.equals("Red"))
             currentColor = Color.RED;
         else if (cmd.equals("Green"))
             currentColor = Color.GREEN;
         else if (cmd.equals("Blue"))
             currentColor = Color.BLUE;
         else if (cmd.equals("Cyan"))
             currentColor = Color.CYAN;
         else if (cmd.equals("Magenta"))
             currentColor = Color.MAGENTA;
         else if (cmd.equals("Yellow"))
             currentColor = Color.YELLOW;
      }
   }
   
   
   private class MouseHandler implements MouseListener, MouseMotionListener {
      boolean dragging;
      int startX, startY;
      CurveData currentCurve;
      public void mousePressed(MouseEvent evt) {
         startX = evt.getX();
         startY = evt.getY();
         currentCurve = null;
         dragging = true;
      }
      public void mouseDragged(MouseEvent evt) {
         if (!dragging)
            return;
         if (currentCurve == null) {
            currentCurve = new CurveData();
            currentCurve.points = new ArrayList<Point>();
            currentCurve.points.add( new Point(startX, startY) );
            currentCurve.color = currentColor;
            currentCurve.useSymmetry = useSymmetryCheckbox.isSelected();
            curves.add(currentCurve);
         }
         currentCurve.points.add( new Point( evt.getX(), evt.getY() ) );
         repaint();
      }
      public void mouseReleased(MouseEvent evt) {
         if (!dragging)
            return;
         currentCurve = null;
         dragging = false;
      }
      public void mouseMoved(MouseEvent evt) {
      }
      public void mouseEntered(MouseEvent evt) {
      }
      public void mouseExited(MouseEvent evt) {
      }
      public void mouseClicked(MouseEvent evt) {
      }
   }
   
   
}

