package simulator;

import java.util.PriorityQueue;


/*
 * MyPriorityQueue.java
 * Created on Jan 20, 2005
 *
 */

/**
 *  MyPriorityQueue - This is a specialized implementation of the priority queue.
 *  It is not a direct extension of the Java PriorityQueue since we want our own
 *  queue interface that allows the user to specify the priority of the items
 *  (which is not allowed in the Java PriorityQueue).
 *
 *  Note: as with the Java implementation, the priority queue is min-priority
 *  based so that 0 has a higher priority than 1.
 *  @author Ping
 *
 */
public class MyPriorityQueue<T, P extends Comparable<P>> implements Cloneable
{

    protected final static int INITIAL_SIZE = 13;

    protected PriorityQueue<PrioritizedElement<T, P>> queue;

    /**
     * Default constructor
     *
     */
    public MyPriorityQueue()
    {
        queue = new PriorityQueue<PrioritizedElement<T, P>>(INITIAL_SIZE);
    }

    private MyPriorityQueue(MyPriorityQueue<T, P> other)
    {
    	this.queue = new PriorityQueue<PrioritizedElement<T, P>>(other.queue);
    }
    
    /**
     * This puts the element into the the priority queue based on the priority
     * specified.  The lower the priority number, the greater the priority (so the lowest
     * priority number will be dequeued first)
     *
     * @param element The element to enqueue
     * @param priority The element's priority
     */
    public void enqueue(T element, P priority)
    {
        queue.offer(new PrioritizedElement<T, P>(element, priority));
    }

    /**
     * This function returns the first element in the priority queue
     * (the one with highest priority - least priority value) without
     * removing it from the queue.
     *
     * @return the first element in the priority queue, or null if the
     *  queue is empty
     */
    public T peek()
    {
        PrioritizedElement<T, P> e = queue.peek();
        // just incase the queue is empty
        if(e != null)
            return e.getElement();
        else
            return null;
    }

    /**
     * This function returns the first element in the priority queue and
     * actually removes it from the queue.
     * @return returns the first element in the priority queue, or null if
     *  the queue is empty
     */
    public T dequeue()
    {
        PrioritizedElement<T, P> e = queue.poll();
        // just incase the queue is empty
        if(e != null)
            return e.getElement();
        else
            return null;
    }

    /**
     * This function returns true if the queue is empty
     * @return true if the queue is empty, false otherwise
     */
    public boolean isEmpty()
    {
        return queue.isEmpty();
    }

    /**
     * This function returns the size of the priority queue
     * @return
     */
    public int size()
    {
        return queue.size();
    }

    /**
     * This function updates the priority of one of the elements in the queue
     *
     * @param element The element whose priority is being changed
     * @param oldPriority The original priority of the item
     * @param newPriority the new priority of the item
     */
    public void  updatePriority(T element, P oldPriority, P newPriority)
    {
        boolean removed = queue.remove(
                new PrioritizedElement<T, P>(element, oldPriority));

        if(removed)
        {
            queue.offer(new PrioritizedElement<T, P>(element, newPriority));
        }
    }

    public MyPriorityQueue<T, P> clone() throws CloneNotSupportedException
    {
    	return new MyPriorityQueue<T, P>(this);
    }

    public static void main(String[] args) throws CloneNotSupportedException
    {
        MyPriorityQueue<String, Integer> queue =
            new MyPriorityQueue<String, Integer>();



        queue.enqueue("String 2", 2);
        queue.enqueue("String 1", 1);

        MyPriorityQueue<String, Integer> clone =
            (MyPriorityQueue<String, Integer>)queue.clone();

        System.out.println(queue.peek());
        queue.updatePriority("String 2", 2, 0);

        System.out.println(queue.peek());
        System.out.println(clone.peek());

        queue.dequeue();
        System.out.println(queue.peek());
        System.out.println(clone.peek());
        System.out.println(clone.size());
    }
}

