/*
 * LpAbstractStructureUnit.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:
 * v0.1 (2007-01-05): initial version
 * v0.2 (2007-01-05): initial implementation, tests, documentation
 * v0.2.1 (2007-01-12):
 * - NullPointerException replaced by IllegalArgumentException in
 *   appendNormalForm
 * v0.2.2 (2007-01-18):
 * - "normal form" methods deleted, the same functionality now provided by
 *   LpPrettyPrinter
 * v0.2.3 (2007-01-20):
 * - import for LpPrettyPrinter added (moved to a separate package)
 * - docs updated
 * v0.2.4 (2007-02-11):
 * - toUnmodifiableList added
 * v0.2.5 (2007-03-06):
 * - toUnmodifiableList made static
 * - test for toUnmodifiableList added
 * v1.0.0 (2007-05-04):
 * - toUnmodifiableSet added
 */

package lp.struct;

import java.util.Collections;
import java.util.List;
import java.util.Set;
import lp.struct.util.EvolpPrettyPrinter;
import lp.struct.util.LpBuffer;

/**
 * This abstract class offers a default implementation of the
 * {@link #toString()} method for all classes implementing the
 * {@link LpStructureUnit} interface.
 *
 * @author Martin Slota
 * @version 1.0.0
 * @see LpStructureUnit
 * @see LpConstant
 * @see LpVariable
 * @see LpCompoundTerm
 * @see LpFunction
 * @see LpPredicate
 * @see LpAtom
 * @see LpLiteral
 * @see LpRule
 */
public abstract class LpAbstractStructureUnit implements LpStructureUnit {
	/**
	 * A single {@link LpBuffer} instance for the toString() method. All calls
	 * to {@link #toString()} are synchronized on it, so it is not a good idea
	 * to call {@code toString()} on {@link LpStructureUnit}s from many
	 * threads...
	 */
	protected static final LpBuffer TO_STRING_BUFFER =
			EvolpPrettyPrinter.getBuffer();
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public String toString() {
		synchronized (TO_STRING_BUFFER) {
			return TO_STRING_BUFFER.asString(this);
		}
	}
	
	/**
	 * Converts the given list to an unmodifiable list using the
	 * {@link Collections#unmodifiableList(List)} method. But there are two
	 * differences:
	 *
	 * <ul>
	 *   <li>on {@code null} input an empty list is returned (see
	 *   {@link Collections#emptyList()})</li>
	 *   <li>if the list throws an {@link UnsupportedOperationException} when we
	 *   call its {@link List#addAll(Collection)} method, it is not wrapped in
	 *   another protecting object. This prevents stacking of
	 *   {@code UnmodifiableList} instances.</li>
	 * </ul>
	 *
	 * @param list the list whose read-only view should be returned
	 * @return as specified above
	 */
	protected static <T> List<T> toUnmodifiableList(List<T> list) {
		if (list == null) {
			return Collections.emptyList();
		} else {
			boolean modifiable = true;
			try {
				List<T> empty = Collections.emptyList();
				list.addAll(empty);
			} catch (UnsupportedOperationException e) {
				modifiable = false;
			}
			return modifiable ? Collections.unmodifiableList(list) : list;
		}
	}
	
	/**
	 * Converts the given set to an unmodifiable set using the
	 * {@link Collections#unmodifiableSet(Set)} method. But there are two
	 * differences:
	 *
	 * <ul>
	 *   <li>on {@code null} input an empty set is returned (see
	 *   {@link Collections#emptySet()})</li>
	 *   <li>if the set throws an {@link UnsupportedOperationException} when we
	 *   call its {@link Set#addAll(Collection)} method, it is not wrapped in
	 *   another protecting object. This prevents stacking of
	 *   {@code UnmodifiableSet} instances.</li>
	 * </ul>
	 *
	 * @param set the set whose read-only view should be returned
	 * @return as specified above
	 */
	protected static <T> Set<T> toUnmodifiableSet(Set<T> set) {
		if (set == null) {
			return Collections.emptySet();
		} else {
			boolean modifiable = true;
			try {
				Set<T> empty = Collections.emptySet();
				set.addAll(empty);
			} catch (UnsupportedOperationException e) {
				modifiable = false;
			}
			return modifiable ? Collections.unmodifiableSet(set) : set;
		}
	}
}