import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;

public class DrawingCanvas extends JPanel implements ActionListener {

	private JFrame frame;
	private int width, height;
	private Vector drawing = new Vector();
	private Color color = Color.black;
	private boolean filled = false;
	private Polygon polygon;

	static class Splodge implements Serializable {
		Color color;
		boolean filled;
		Polygon polygon;
		Splodge(Color c, boolean f, Polygon p) {
			color = c;
			filled = f;
			polygon = p;
		}
	}

	void XORpolygon() {
		Graphics g = this.getGraphics();
		g.setXORMode(this.getBackground());
		g.setColor(color);
		if (filled)
			g.fillPolygon(polygon);
		else
			g.drawPolygon(polygon);
	}

	class DCMouseAdapter extends MouseAdapter {
		public void mousePressed(MouseEvent e) {
			polygon = new Polygon();
			polygon.addPoint(e.getX(), e.getY());
			XORpolygon();
		}

		public void mouseReleased(MouseEvent e) {
			XORpolygon();
			polygon.addPoint(e.getX(), e.getY());
			drawing.addElement(new Splodge(color, filled, polygon));
			repaint();
		}
	}

	class DCMouseMotionAdapter extends MouseMotionAdapter {
		public void mouseDragged(MouseEvent e) {
			XORpolygon();
			polygon.addPoint(e.getX(), e.getY());
			XORpolygon();
		}
	}

	DrawingCanvas(JFrame frame, int width, int height) {
		this.frame = frame;
		this.width = width;
		this.height = height;
		this.addMouseListener(new DCMouseAdapter());
		this.addMouseMotionListener(new DCMouseMotionAdapter());
	}

	public Dimension getPreferredSize() {
		return new Dimension(width, height);
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		g.setPaintMode();
		for (int d = 0; d < drawing.size(); d++) {
			Splodge s = (Splodge) drawing.elementAt(d);
			g.setColor(s.color);
			if (s.filled)
				g.fillPolygon(s.polygon);
			else
				g.drawPolygon(s.polygon);
		}
	}

	public void actionPerformed(ActionEvent e) {
		String s = e.getActionCommand();
		if (s.equals("new"))
			newDrawing();
		else if (s.equals("load"))
			load();
		else if (s.equals("save"))
			save();
		else if (s.equals("print"))
			print();
		else if (s.equals("quit"))
			System.exit(0);
		else if (s.equals("black"))
			color = Color.black;
		else if (s.equals("blue"))
			color = Color.blue;
		else if (s.equals("red"))
			color = Color.red;
		else if (s.equals("green"))
			color = Color.green;
		else if (s.equals("on"))
			filled = true;
		else if (s.equals("off"))
			filled = false;
	}

	private void newDrawing() {
		drawing.removeAllElements();
		this.repaint();
	}

	private void load() {
		FileDialog fd = new FileDialog(frame, "Load drawing", FileDialog.LOAD);
		fd.show();
		File f = new File(fd.getDirectory(), fd.getFile());
		if (f != null) {
			try {
				FileInputStream s = new FileInputStream(f);
				ObjectInputStream o = new ObjectInputStream(s);
				Vector v = (Vector) o.readObject();
				o.close();
				drawing = v;
				this.repaint();
			} catch (Exception e) {
				System.err.println(e);
			}
		}
	}

	private void save() {
		FileDialog fd = new FileDialog(frame, "Save drawing", FileDialog.SAVE);
		fd.show();
		File f = new File(fd.getDirectory(), fd.getFile());
		if (f != null) {
			try {
				FileOutputStream s = new FileOutputStream(f);
				ObjectOutputStream o = new ObjectOutputStream(s);
				o.writeObject(drawing);
				o.close();
			} catch (Exception e) {
				System.err.println(e);
			}
		}
	}

	private static Properties preferences = new Properties();

	private void print() {
		Toolkit toolkit = this.getToolkit();
		PrintJob printjob =
			toolkit.getPrintJob(frame, "Print drawing", preferences);
		if (printjob == null)
			return;
		Graphics sheet = printjob.getGraphics();
		Dimension canvassize = this.getSize();
		Dimension pagesize = printjob.getPageDimension();
		sheet.translate(
			(pagesize.width - canvassize.width) / 2,
			(pagesize.height - canvassize.height) / 2);
		sheet.drawRect(-1, -1, canvassize.width + 1, canvassize.height + 1);
		sheet.setClip(0, 0, canvassize.width, canvassize.height);
		this.print(sheet);
		sheet.dispose();
		printjob.end();
	}
}
