package code.space;

import code.term.*;
import code.subst.*;

import java.util.*;

/**
 * Queue of the computations in the narrowing space.
 * The queue is circular, i.e., every time the first element
 * in the queue is processed, it is placed back into the queue.
 *
 * @author Sergio Antoy
 * @since Dec 20, 2000
 */

public class Queue {

    public class UnderflowException extends Exception {
    }

    /**
     * Vector holding the computations in the queue.
     */
    private Vector vector = new Vector();

    /**
     * Index of element last requested (was first) in the queue.
     */
    private int first = -1;

    /**
     * This is needed by the pre and post debugging choice and
     * narrow instructions to see all of the computations
     * that were created by the choice or narrow instruction.
     *
     * @return int
     */
    public int first() {
        return first;
    }

    /**
     * Place a computation in the queue.
     *
     * @param computation the computation to place in the queue.
     */
    public void enqueue(Computation computation) {
        if (first == -1)
            vector.add(computation);
        else
            vector.insertElementAt(computation, first);
    }

    /**
     * Return the first computation in the queue.
     *
     * @return The first computation in the queue.
     */
    public Computation next() throws UnderflowException {
        ++first;
        if (first >= vector.size()) first = 0;
        try {
            Computation computation = (Computation) vector.elementAt(first);
            return computation;
        } catch (ArrayIndexOutOfBoundsException ex) {
            throw new UnderflowException();
        }
    }

    /**
     * Take out the last returned (was first) computation of the queue.
     */
    public Computation dequeue() {
        Computation computation = (Computation) vector.remove(first);
        return computation;
    }

//    /**
//     *  Take out the last returned (was first) computation of the queue.
//     */
//    public void dequeue (Computation computation) { 
//	int size = vector.size();
//	for (int i = 0; i < size; i++)
//	    if (vector.elementAt (i) == computation) {
//		vector.remove (i);
//		break;
//	    }
//    }

    public Computation remove(Computation c) {
        int indx = vector.indexOf(c);
        if (indx >= 0) {
            Computation comp = (Computation) vector.remove(indx);
            if (first > indx) {
                first--;
            }
            if (first >= vector.size()) first = 0;
            return comp;
        }
        return null;
    }

    /**
     * Return the number of computations in the queue.
     *
     * @return the number of computations in the queue.
     */
    public int size() {
        return vector.size();
    }

    /**
     * Return an enumeration of the computations in this queue.
     *
     * @return An enumeration of the computations in this queue.
     */
    public Enumeration elements() {
        return vector.elements();
    }

    /**
     * Return a printable representation of this queue.
     *
     * @return A printable representation of this queue.
     */
    public String toString() {
        int size = vector.size();
        String result = "Queue: size=" + size + " index=" + first + " content=\n";
        for (int i = 0; i < size; i++) {
            int index = (first + i) % size;
            Computation computation
                    = (Computation) vector.elementAt(index);
            Term term = computation.getTerm();
            Subst subst = computation.getSubst();
            String string = term.toString(subst);
            result += "  " + index + " " + string + " " + computation.debug() + " "
                    + computation.stateName[computation.getState()] + "\n";
        }
        return result;
    }
}
