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

    // A class for plotting simple run-length encoded pictures.
    // Used to support exercises in Chapter 5 and after.
class PicturePlotter extends JComponent {
    public PicturePlotter(int width,int height) {
        Dimension requiredSize = new Dimension(width,height);
        setMinimumSize(requiredSize);
        setMaximumSize(requiredSize);
        setPreferredSize(requiredSize);
        ComponentFrame frame = new ComponentFrame("Mystery Picture");
        frame.addComponent(this);
        frame.pack();
    }

        // Plot a single pixel at (x,y) in the given color.
    public void plot(int x, int y, int color){
        plot(x,y,1,color);
    }

        // Plot count pixels at (x,y) in the given color.
    public void plot(int x, int y, int count, int color){
        final AbstractList list;
        synchronized(list = getData()){
            DataPoint p = new DataPoint(x,y,count,color);
            list.add(p);
            plotPoint(p,getGraphics());
        }
    }

        // Set a user defined int-based color table.
        // Turn the table into Color objects.
    public void setColorTable(int[][] table){
        if((table != null) && (table.length > 0)){
            final int numRGB = 3;
            final int numColors = table.length;
            final Color[] ctable = new Color[numColors];
            for(int i = 0; i < numColors; i++){
                int[] rgb = table[i];
                if(rgb.length == numRGB){
                    ctable[i] = new Color(rgb[0],rgb[1],rgb[2]);
                }
                else{
                    throw new RuntimeException(
                        "Each row must have three RGB values.");
                }
            }
            setColorTable(ctable);
        }
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        final AbstractList list;
        synchronized(list = getData()){
            Iterator points = list.iterator();
            while(points.hasNext()){
                DataPoint p = (DataPoint) points.next();
                plotPoint(p,g);
            }
        }
    }

        // Inner classes to support this class.
        // The frame for its visualization.
    protected class PictureFrame extends JFrame {
        public PictureFrame() {
            final int defaultWidth = 250, defaultHeight = 250;
            setSize(defaultWidth,defaultHeight);
            addWindowListener(new WindowCloser());
            Container contents = getContentPane();
            contents.add(new QuitJPanel(),"South");
        }
    }

        // Store details of each color plotted.
    protected class DataPoint {
        public DataPoint(int x, int y, int count,int color){
            this.x = x;
            this.y = y;
            this.count = count;
            this.color = color;
        }

        int getX(){
            return x;
        }

        public int getY(){
            return y;
        }

        public int getCount(){
            return count;
        }

        public int getColor(){
            return color;
        }

        private final int x, y, count, color;
    }

    protected void plotPoint(DataPoint p,Graphics g){
        g.setColor(mapColor(p.getColor()));
        final int x = p.getX(), y = p.getY();
        g.drawLine(x,y,x+p.getCount()-1,y);
    }

    protected Color mapColor(int color){
        return getColorTable()[color % numColors()];
    }

    protected AbstractList getData(){
        return data;
    }

    protected int numColors(){
        return getColorTable().length;
    }

    protected Color[] getColorTable(){
        return colorTable;
    }

    protected void setColorTable(Color[] t){
        if(t != null){
            colorTable = t;
        }
    }

        // The default color table for the contents of picture.txt.
    private Color[] colorTable = {
        new Color(0,0,0), // Black.
        new Color(0,128,128), // Dark green.
        new Color(128,64,0), // Yellow.
        new Color(255,255,255), // White.
        new Color(255,255,0), // Brown.
        new Color(0,255,0), // Green.
        new Color(255,255,255),
        new Color(255,255,255),
        new Color(255,255,255),
        new Color(255,255,255),
        new Color(255,255,255),
        new Color(255,255,255),
        new Color(255,255,255),
        new Color(255,255,255),
        new Color(255,255,255),
        new Color(255,255,255),
    };

    // Collection of the datapoints.
    final AbstractList data = new LinkedList();
}
