/*
 * EmptyProgram.java
 *
 * Copyright (C) 2006 - 2007 Martin Slota
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/*
 * History:
 * v1.0.0 (2007-05-05):
 * - extracted from an inner class of DynamicLogicProgram
 *
 * PENDING create a junit test
 */

package lp.unit;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.NoSuchElementException;
import lp.struct.LpRule;

/**
 * An efficient implementation of an empty logic program that is immutable. May
 * be useful in some cases :o)
 *
 * @version 1.0.0
 * @author Martin Slota
 * @see LogicProgram
 * @see DynamicLogicProgram
 */
class EmptyProgram implements LogicProgram {
	/**
	 * The singleton instance.
	 */
	private static EmptyProgram instance = null;
	
	/**
	 * Returns the singleton instance.
	 *
	 * @return the singleton instance of {@code EmptyProgram}
	 */
	public static synchronized EmptyProgram getInstance() {
		if (instance == null) {
			instance = new EmptyProgram();
		}
		return instance;
	}
	
	/**
	 * A static iterator over an empty collection of rules.
	 */
	private static final Iterator<LpRule> ITR = new Iterator<LpRule>() {
		public boolean hasNext() {
			return false;
		}
		
		public LpRule next() {
			throw new NoSuchElementException();
		}
		
		public void remove() {
			throw new IllegalStateException();
		}
	};
	
	/**
	 * Empty array used to return the program as an of rules.
	 */
	private static final Object[] AS_ARRAY = new Object[0];
	
	/**
	 * A private constructor because this class is a singleton.
	 */
	private EmptyProgram() {
		// a private constructor because this class is a singleton
	}
	
	/**
	 * Returns 0.
	 *
	 * @return 0
	 */
	public int size() {
		return 0;
	}
	
	/**
	 * Returns {@code true}.
	 *
	 * @return {@code true}
	 */
	public boolean isEmpty() {
		return true;
	}
	
	/**
	 * Returns {@code false}.
	 *
	 * @param o the object to look for (cannot be contained in an empty
	 * collection)
	 * @return {@code false}
	 */
	public boolean contains(Object o) {
		return false;
	}
	
	/**
	 * Returns the iterator for this empty collection.
	 *
	 * @return the iterator for this empty collection
	 */
	public Iterator<LpRule> iterator() {
		return ITR;
	}
	
	/**
	 * Returns an empty array.
	 *
	 * @return an empty array
	 */
	public Object[] toArray() {
		return AS_ARRAY;
	}
	
	/**
	 * Returns an empty array.
	 *
	 * @return an empty array
	 */
	public <T> T[] toArray(T[] a) {
		if (a.length > 0)
			a[0] = null;
		return a;
	}
	
	/**
	 * Throws an {@link UnsupportedOperationException}.
	 *
	 * @param r the rule to add
	 * @throws UnsupportedOperationException always
	 */
	public boolean add(LpRule r) {
		throw new UnsupportedOperationException();
	}
	
	/**
	 * Throws an {@link UnsupportedOperationException}.
	 *
	 * @param o the rule to remove
	 * @throws UnsupportedOperationException always
	 */
	public boolean remove(Object o) {
		throw new UnsupportedOperationException();
	}
	
	/**
	 * Returns the same as {@code c.isEmpty()}.
	 *
	 * @return as specified above
	 */
	public boolean containsAll(Collection<?> c) {
		return c.isEmpty();
	}
	
	/**
	 * Throws an {@link UnsupportedOperationException}.
	 *
	 * @param c the collection of rules to add
	 * @throws UnsupportedOperationException always
	 */
	public boolean addAll(Collection<? extends LpRule> c) {
		throw new UnsupportedOperationException();
	}
	
	/**
	 * Throws an {@link UnsupportedOperationException}.
	 *
	 * @param c the collection of rules to remove
	 * @throws UnsupportedOperationException always
	 */
	public boolean removeAll(Collection<?> c) {
		throw new UnsupportedOperationException();
	}
	
	/**
	 * Throws an {@link UnsupportedOperationException}.
	 *
	 * @param c the collection of rules to retain
	 * @throws UnsupportedOperationException always
	 */
	public boolean retainAll(Collection<?> c) {
		throw new UnsupportedOperationException();
	}
	
	/**
	 * Throws an {@link IndexOutOfBoundsException}.
	 *
	 * @param index the index of the rule to return
	 * @throws IndexOutOfBoundsException always
	 */
	public LpRule get(int index) {
		throw new IndexOutOfBoundsException("Index: " + index);
	}
	
	/**
	 * Throws an {@link UnsupportedOperationException}.
	 *
	 * @throws UnsupportedOperationException always
	 */
	public void clear() {
		throw new UnsupportedOperationException();
	}
	
	/**
	 * Returns {@code true} iff {@code obj} implements the {@link LogicProgram}
	 * interface and contains no rules.
	 *
	 * @param obj the object to compare with
	 * @return as specified above
	 */
	@Override
	public boolean equals(Object obj) {
		if (obj == this)
			return true;
		
		if (!(obj instanceof LogicProgram))
			return false;
		LogicProgram p = (LogicProgram) obj;
		return p.isEmpty();
	}
	
	/**
	 * Returns the hash code of an empty set.
	 *
	 * @return the hash code of an empty set
	 * @see Collections#emptySet()
	 */
	@Override
	public int hashCode() {
		return Collections.emptySet().hashCode();
	}
	
	/**
	 * Returns {@code true}.
	 *
	 * @return {@code true}
	 */
	public boolean isGround() {
		return true;
	}
	
	/**
	 * Returns the string "[]".
	 *
	 * @return the string "[]"
	 */
	@Override
	public String toString() {
		return "[]";
	}
}