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

/** 
 * This class is an illustration of class Vector<Character>. Instances are
 * a frame that contains a visual representation of a Vector along with the 
 * elements it contains.
 * 
 * If you are using the Java 1.4 compiler, this file will not compile.
 * But then again, you should not be using Java 1.4.  Upgrade!
 */
public class VisualVector extends JFrame {

    /** The list of objects that will be displayed. Note: According to our principles. this
      * field should be private. It is made public so that the lab can be done most easily,
      * using the interactions pane. 
      */
    public Vector<Character> v= null;
    
    /** Constructor: a JFrame with a Vector that has default properties. */
    public VisualVector() {
        super("CS1110 Lab 05: An illustration of class Vector");
        v= new Vector<Character>();
        createGUI(); 
    }
    
    /** Constructor: a JFrame with a Vector with initial capacity c
      * and capacity increment ci.  
      */
    public VisualVector(int c, int ci) {
        super("CS1110 Lab 05: An illustration of class Vector");
        v= new Vector<Character>(c, ci);
        createGUI();
    }
    
    /** Swap the objects at v[first] and v[second]
      * Precondition: first and second are in range 0..v.size()-1. 
      */
    public void swap(int first, int second) {
        
        //-------- IMPLEMENT ME! --------//
    }
    
    /** Yields: "there is more than one occurrence of obj in v" */
    public boolean moreThanOne(Character obj) {
        
        //-------- IMPLEMENT ME! --------//

        return false; // STUB: this is only here so that the stub method compiles
    }
    
    /** Yields: "v has unused space" */
    public boolean hasExtraSpace() {
        
        //-------- IMPLEMENT ME! --------//
        
        return false; // STUB: this is only here so that the stub method compiles
    }
    
    /** Yields: a String that contains the characters of Vector v.
      * Precondition: the characters ',' and ' ' do not appear in v 
      */
    public String toString() {
        //-------- IMPLEMENT ME! --------//
        
        return "";  // STUB: this is here only so that the method compiles
    }
    
    /** Set the total capacity of v to 10 and fill it completely
      * with Character objects. 
      */
    public void initializeV() {
        v.clear();
        v.trimToSize();
        v.ensureCapacity(10);
        v.add(new Character('X'));
        v.add(new Character('Y'));
        v.add(new Character('Z'));
        v.add(new Character('1'));
        v.add(new Character('2'));
        v.add(new Character('3'));
        v.add(new Character('$'));
        v.add(new Character('#'));
        v.add(new Character('3'));
        v.add(new Character('2'));
    }
    
    /*********************************************************************
     * You do NOT need to read the code below here                       *
     * This code displays the graphical vector inside a JFrame.          *  
     * *******************************************************************/
    
    private JPanel panel;
    private JScrollBar scrollbar;
    private Font indexFont= new Font("Monospace", Font.BOLD, 16);
    private int indexFontSize= indexFont.getSize();
    private Font charFont= new Font("Serif", Font.BOLD, 25);
    private int cellSize= charFont.getSize();
    private int xOffset= 20;
    private int yOffset= 20;
    private int cellPadding= 15;
    private Thread repaintThread;
    private Image offscreenImage;
    private Graphics offscreenGraphics;
    private Dimension screen= Toolkit.getDefaultToolkit().getScreenSize();
    
    /** Create a GUI that graphically displays Vector v. */
    private void createGUI() {
        // Create thread to continually repaint
        repaintThread= new Thread() {
            
            public void run() {
                while (VisualVector.this.isVisible()) {
                    VisualVector.this.pack();
                    if (panel.getGraphics() != null)
                        panel.update(panel.getGraphics());
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException ie) {}
                }
            }
        };
        
        repaintThread.setDaemon(true);
        
        // Create panel to draw vector
        panel= new JPanel() {
            public void paint(Graphics g) {
                if (offscreenGraphics != null) {
                    g.drawImage(offscreenImage, -1*scrollbar.getValue(), 0, null);
                }
            }
            
            // Prepare the image and paint it
            public void update(Graphics g) {
                // prepare offscreen image
                try {
                    if (offscreenImage != null) {
                        offscreenImage.flush();
                        offscreenGraphics.finalize();
                        offscreenImage= null;
                        offscreenGraphics= null;
                    }
                    offscreenImage= 
                        createImage(Math.max(cellSize * v.capacity() + 2*xOffset, panel.getWidth()),
                                    cellSize + 2*yOffset + indexFont.getSize());
                    offscreenGraphics= offscreenImage.getGraphics();
                } catch (Exception e) { return; /*the window had 0-dimensions*/ }
                
                // clear image
                offscreenGraphics.setColor(Color.white);
                
                offscreenGraphics.fillRect(0, 0,
                                           offscreenImage.getWidth(null),
                                           offscreenImage.getHeight(null));
                
                // adjust scrollbar settings
                scrollbar.setMaximum(Math.max(offscreenImage.getWidth(null) - panel.getWidth(), 0));
                scrollbar.setUnitIncrement(cellSize);
                
                // Draw the Character objects in v.  If a cell contains
                // an object besides Character, draw a red question mark.
                FontRenderContext frc= ((Graphics2D)offscreenGraphics).getFontRenderContext();
                offscreenGraphics.setFont(charFont);
                offscreenGraphics.setColor(Color.blue);
                
                for (int i= 0; i < v.size(); i= i+1) {
                    Object item= v.get(i);
                    GlyphVector glyph= null; //will contain char to be printed
                    if (item instanceof Character) {
                        // get the glyph associated with this character
                        glyph= charFont.createGlyphVector
                            (frc, new char[] {((Character) item).charValue()});
                    }
                    else {// get the glyph associated with '?'
                        glyph= charFont.createGlyphVector(frc, new char[] {'?'});
                        offscreenGraphics.setColor(Color.red);
                        item= "?";
                    }
                    
                    // get the bounds of the glyph
                    Rectangle bounds= glyph.getOutline().getBounds();
                    
                    int charWidth= (int) bounds.getWidth();
                    int charHeight= (int) bounds.getHeight();
                    int maxBound= Math.max(charWidth, charHeight);
                    if (maxBound + cellPadding > cellSize)
                        cellSize= maxBound + cellPadding;
                    
                    offscreenGraphics.drawString(item.toString(),
                            xOffset + cellSize * i + (cellSize - charWidth)/2,
                            yOffset + charHeight + (cellSize - charHeight)/2 + indexFontSize);
                    offscreenGraphics.setColor(Color.blue);
                }
                
                // Draw the vector
                offscreenGraphics.setColor(Color.black);
                int capacity= v.capacity();
                offscreenGraphics.drawRect(xOffset, yOffset + indexFontSize, capacity * cellSize, cellSize);
                for (int i= 0; i < capacity; i= i+1)
                    offscreenGraphics.drawLine(xOffset + cellSize * i, yOffset + indexFontSize,                       
                                               xOffset + cellSize * i, yOffset + cellSize + indexFontSize);
                
                // Draw the indices above their corresponding cells
                offscreenGraphics.setFont(indexFont);
                // offscreenGraphics.setXORMode(getContentPane().getBackground());  
                for (int i= 0; i < v.capacity(); i= i+1)
                    offscreenGraphics.drawString(String.valueOf(i), xOffset + cellSize * i + cellSize / 2,
                                                 yOffset  + indexFont.getSize());
                paint(g);   
            }
            
            public Dimension getPreferredSize() {
                return new Dimension(screen.width-10, 
                                     cellSize + yOffset * 2 + indexFont.getSize() + cellPadding);
            }
        };
        
        // Create scrollbar to pan along vector
        scrollbar= new JScrollBar(JScrollBar.HORIZONTAL);
        
        // Add panel and scrollbar to the frame
        Container c= getContentPane();
        c.setBackground(Color.white);
        c.setLayout(new BorderLayout());
        c.add(panel, BorderLayout.CENTER);
        c.add(scrollbar, BorderLayout.SOUTH);    
        setResizable(false);
        pack();
        setVisible(true);
        
        // start the thread
        repaintThread.start();
    }
    
}