// Queue.java -- partially written source file for Lab07

package lab07;

import java.awt.*;

/**
 *
 * @author J.K. Daugherty
 */

public class Queue implements Paintable {

    private Node frontNode;
    private Node rearNode;
    private int itemCount;

    // Constants for graphical display...
    
    public static final int CELL_WIDTH = 120;
    public static final int CELL_HEIGHT = 30;
    public static final Color CELL_COLOR = new Color (0xEC,0xEC,0xEC);
    public static final Color ARROW_COLOR = Color.black;

    // Dual (x,y) arrays, used to draw an arrow pointing to the top of
    // the stack. These represent relative values, where the tip of the
    // (leftward pointing) arrow is at (0,0). To render this arrow at
    // a specific location in the display window, fixed offsets must
    // be added to these values (see below).

    private static final int[] X_ARROW = {0, 20,20,70,70,20,20};
    private static final int[] Y_ARROW = {0,-15,-5,-5, 5, 5,15};

    /** Creates an empty Stack object. */
    public Queue () {
        frontNode = rearNode = null;
        itemCount = 0;
    }

    /** Adds the specified value to the rear of the Queue.
     *
     * @param value The object to be added.
     */
    public void add (Object value) {

                       // STUB -- implement this method
    }
    
    /** Removes and returns the value currently at the front
     *  of the Queud. The method assumes as a precondition that
     *  the Queue is not already empty, and it throws an
     *  IllegalStateException if this is violated.
     *
     * @return The value removed from the front of the Queue.
     */
    public Object remove () throws IllegalStateException {

      return null;     // STUB -- remove this line and implement
    }

    /** Indicates whether the stack is empty.
     * @return true if the stack is empty, false otherwise.
     */
    public boolean isEmpty () {
        return (itemCount == 0);
    }

    /** Returns the number of items currently stored in the stack.
     * @return The number of stored items.
     */
    public int size () {
	return itemCount;
    }

    /**
     * Removes all values currently stored on the stack.
     */
    public void removeAll () {

                       // STUB -- implement this method
    }
    
    /** Renders the stack in a graphical display window. The window
     * dimensions and its associated graphics context
     * (java.awt.Graphics object) are both supplied as input
     * parameters.
     * @param g Graphics context associated with the display window.
     * A Graphics object provides rendering methods as well as the
     * reference frame for pixel coordinates.
     * @param panelSize Width and height of the display area, in pixels.
     */
    public void render (Graphics g, Dimension panelSize) {
        int panelWidth = (int) panelSize.getWidth();
        int panelHeight = (int) panelSize.getHeight();

        // Choose horizontal "baseline" (bottom of array)
        
        int xbase = panelWidth / 2;                   // Vertical axis
        int ybase = panelHeight - CELL_HEIGHT - 20;   // Bottom of array

        // Find x-coordinate of upper left-hand corner of each cell
        
        int xloc = (panelWidth - CELL_WIDTH) / 2;

        Node curNode = frontNode;
        
        for (int cell = 0; cell < itemCount; cell++) {
            g.setColor (CELL_COLOR);
            int yloc = ybase - (cell + 1) * CELL_HEIGHT;

            g.fill3DRect (xloc, yloc, CELL_WIDTH, CELL_HEIGHT, true);

            g.setColor(Color.black);
            if (cell < 10) {
                g.drawString (" " + cell, xloc - 20, yloc + CELL_HEIGHT - 10);
            }
            else {
                g.drawString ("" + cell, xloc - 20, yloc + CELL_HEIGHT - 10);
            }
            g.drawString ("" + curNode.value, xloc + 10, yloc + CELL_HEIGHT - 10);
            curNode = curNode.next;
        }

        paintArrow (g, xbase, ybase, "Front", 0, false);
        if (itemCount == 0) {
            paintArrow (g, xbase, ybase, "Rear", 0, true);
        }
        else {
            paintArrow (g, xbase, ybase, "Rear", itemCount - 1, true);            
        }
                
    }
    
    private void paintArrow (Graphics g, int xbase, int ybase,
        String label, int index, boolean rhs) {
        g.setColor (ARROW_COLOR);
    
        int[] xarrow = new int [X_ARROW.length];
        int[] yarrow = new int [Y_ARROW.length];
        int points = X_ARROW.length;
    
        for (int k = 0; k < points; k++) {
            if (rhs)
                xarrow[k] = X_ARROW [k] + xbase + CELL_WIDTH / 2 + 10;
            else
                xarrow[k] = -X_ARROW [k] + xbase - CELL_WIDTH / 2 - 30;

            yarrow[k] = Y_ARROW [k] + ybase - CELL_HEIGHT * index
                    - CELL_HEIGHT / 2;
        }

        g.fillPolygon (xarrow, yarrow, points);

        // Draw label...
    
        g.setColor (Color.black);
        g.setFont (new Font ("Arial", Font.BOLD, 18));

        if (rhs) {
            g.drawString (label,
                xbase + CELL_WIDTH / 2 + 90,
                ybase - CELL_HEIGHT * index - CELL_HEIGHT / 2 + 5);
        }
        else {
            g.drawString (label, xbase - CELL_WIDTH / 2 - 160,
                ybase - CELL_HEIGHT * index - CELL_HEIGHT / 2 + 5);
        }
    
    }

    private class Node {
        Object value;
        Node next;
        
        public Node (Object value, Node next) {
            this.value = value;
            this.next = next;
        }
    }
}
