package mapping.data;

import java.io.Serializable;
import java.util.LinkedList;

import javax.swing.table.AbstractTableModel;

import mapping.Mapper;

/**
 * This class is an implementation of a queue (queue to hold the IDs of
 * Servers). It also implements AbstractTableModel to be used by a JTable to
 * show the servers that this queue has their IDs.
 * 
 * 
 * @author Majd Kokaly
 * 
 * @param <Item>
 *            The Type of objects stored in this Queue
 */
public class IDsQueue<Item> extends AbstractTableModel implements Serializable {

	/**
	 * The serialVersionUID is used to universally identify this version of this
	 * class.
	 */
	private static final long serialVersionUID = -7905134392927161008L;

	/**
	 * A Linked list is used to implement the queue
	 */
	private LinkedList<Item> list;

	/**
	 * The mapper object is used to access the servers
	 */
	private Mapper mapper;

	/**
	 * Default constructor
	 */
	public IDsQueue() {
		super();
		list = new LinkedList<Item>();
	}

	/**
	 * 
	 * @param mapper
	 *            to set the mapper field
	 */
	public IDsQueue(Mapper mapper) {
		super();
		list = new LinkedList<Item>();
		this.mapper = mapper;
	}

	public void printServers() {
		for (int i = 0; i < list.size(); i++) {
			System.out.println(this.mapper.getServer((Integer) list.get(i)).getHostName() + " number of tasks: "
					+ this.mapper.getServer((Integer) list.get(i)).getNumberOfActiveJobs());
		}

		System.out.println("-----------------------\n");
	}

	/**
	 * This method is used to add nodes to the queue.
	 * 
	 * @param item
	 *            is the item to be added
	 */
	public synchronized void enqueue(Item item) {
		if (!list.contains(item))
			list.add(item);
	}

	/**
	 * remove and return the least recently added item
	 * 
	 * @return the the oldest item in the queue after removing it.
	 */
	public synchronized Item dequeue() {
		return list.remove();
	}

	/**
	 * 
	 * @return the the oldest item in the queue.
	 */
	public synchronized Item peak() {
		return list.get(0);
	}
	
	public synchronized Item getVal(int row) {
		return list.get(row);
	}

	/**
	 * This method removes the object Item if it exists
	 * 
	 * @param item
	 *            the object to be deleted
	 * @return the item removed
	 */
	public synchronized Item remove(Item item) {
		for (int i = 0; i < list.size(); i++) {
			if (item.equals(list.get(i))) {
				return list.remove(i);
			}
		}
		return null;
	}

	/**
	 * 
	 * @return true if this queue contains no objects, false otherwise
	 */
	public synchronized boolean isEmpty() {
		return list.isEmpty();
	}

	public synchronized void print() {
		if (this.isEmpty())
			return;
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}
	}

	/**
	 * This method dequeues one element and enqueue it again.
	 */
	public synchronized void advanceInRoundRobinFashion() {
		if (this.list.size() < 2) // if empty or just one
			return;
		else {
			this.enqueue(this.dequeue());
		}
	}

	/**
	 * @see AbstractTableModel
	 */
	public int getColumnCount() {
		return 1;
	}

	/**
	 * @see AbstractTableModel
	 */
	public int getRowCount() {
		return this.list.size();
	}

	/**
	 * @see AbstractTableModel
	 */
	public String getColumnName(int column) {
		return "";
	}

	/**
	 * This method is part of the implementation of the AbstractTableModel
	 * interface. It shows the server hostname using its ID.
	 * 
	 * @see AbstractTableModel
	 */
	public Object getValueAt(int row, int column) {
		if (mapper == null)
			return list.get(row);
		else
			return this.mapper.getServer((Integer) list.get(row)).getHostName();
	}

	// @SuppressWarnings("unchecked")
	public void setValueAt(Object value, int row, int column) {

	}

	public static void main(String[] args) {
		IDsQueue<Integer> queue = new IDsQueue<Integer>();

		queue.enqueue(1);
		queue.enqueue(7);
		queue.enqueue(20);
		queue.enqueue(12);
		queue.enqueue(12);

		queue.print();

		queue.advanceInRoundRobinFashion();
		System.out.println("-----");
		queue.print();

		queue.advanceInRoundRobinFashion();
		System.out.println("-----");
		queue.print();

		queue.advanceInRoundRobinFashion();
		System.out.println("-----");
		queue.print();

		queue.advanceInRoundRobinFashion();
		System.out.println("-----");
		queue.print();

		queue.advanceInRoundRobinFashion();
		System.out.println("-----");
		queue.print();
	}

}
