import java.awt.*;
import java.awt.geom.Point2D;
import javax.swing.*;
import java.util.*;
import java.util.List;

/* Set graphics window
 */
public class MyFrame extends JFrame {
  
  private MyCanvas canvas;
  
  public MyFrame(String t) {
    super(t);
    //setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
    canvas = new MyCanvas();
    canvas.setOpaque(true);
    canvas.setDoubleBuffered(true);
    
    getContentPane().add(canvas);
    pack();
    setVisible(true);
  }
  
  /* Draw a point at (x,y) with specified color */
  public void drawPoint(double x, double y, Color color) {
    canvas.drawPoint(x, y, color);
  }
  
  /* Set drawing region to [x1,x2]-by-[y1,y2] */
  public void setRange(double x1, double x2, double y1, double y2) {
    canvas.setRange( x1,  x2,  y1,  y2);
  }
  
  public void setRadius(int r) {
    canvas.setRadius(r);
  }

  public void setIsMovie(boolean m) {
    canvas.setIsMovie(m);
  }
}


class MyCanvas extends JComponent {
  private List<MyPoint> points;
  private int r = 2, margin = 10;
  private double rangeX1 = 0, rangeX2 = 1;
  private double rangeY1 = 0, rangeY2 = 1;
  private boolean isMovie = true;
  
  public MyCanvas() {
    points = (List<MyPoint>) Collections.synchronizedList(new ArrayList<MyPoint>());
  }
  
  public Dimension getPreferredSize() {
    return new Dimension(500, 500);
  }
  
  public Dimension getMinimumSize() {
    return new Dimension(500, 500);
  }
  
  /* Set drawing region to [x1,x2]-by-[y1,y2] */
  public void setRange(double x1, double x2, double y1, double y2) {
    rangeX1 = x1;
    rangeX2 = x2;
    rangeY1 = y1;
    rangeY2 = y2;
    repaint();
  }
  
  public void setRadius(int rr) {
    r = rr;
  }
  
  public void setIsMovie(boolean m) {
    isMovie = m;
  }
  
  protected void paintComponent(Graphics g) {
    
    // If the canvas is set to opaque, fill the entire component with white
    if (isOpaque()) {
      g.setColor(Color.white);
      g.fillRect(0, 0, getWidth(), getHeight());
    }
    
    synchronized(points) {
      Graphics2D g2d = (Graphics2D)g.create();
      Iterator iter = points.iterator();
      while (iter.hasNext()) {
        MyPoint p = (MyPoint)iter.next();
        int x = (int) Math.round(((p.getX()-rangeX1)/(rangeX2-rangeX1) 
                                    * (getWidth() - 2*margin) + margin));
        int y = (int) Math.round(((rangeY2 - p.getY())/(rangeY2-rangeY1) 
                                    * (getHeight() - 2*margin) + margin));
        g2d.setColor(p.getColor());
        g2d.fillRect(x, y, r, r);
      }
      g2d.dispose(); //clean up
    }
  }
  
  /* Draw a point at (x,y) with specified color */
  public void drawPoint(double x, double y, Color color) {
    synchronized(points) {
      points.add(new MyPoint(x, y, color));
    }
    if (isMovie) repaint();
  }
}


class MyPoint extends Point2D.Double {
  private Color color;
  public MyPoint(double x, double y, Color c) {
    super(x,y);
    color = c;
  }
  public Color getColor() {
    return color;
  }
}
