PcollectionsSymbolicSequence.java

/*******************************************************************************
 * Copyright (c) 2013 Stephen F. Siegel, University of Delaware.
 * 
 * This file is part of SARL.
 * 
 * SARL is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 * 
 * SARL 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 Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with SARL. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package edu.udel.cis.vsl.sarl.collections.common;

import java.util.Collection;
import java.util.Iterator;

import org.pcollections.PVector;
import org.pcollections.TreePVector;

import edu.udel.cis.vsl.sarl.IF.Transform;
import edu.udel.cis.vsl.sarl.IF.expr.SymbolicExpression;
import edu.udel.cis.vsl.sarl.collections.IF.SymbolicCollection;
import edu.udel.cis.vsl.sarl.collections.IF.SymbolicSequence;
import edu.udel.cis.vsl.sarl.object.common.CommonObjectFactory;

/**
 * Note TreePVector cannot take null elements!!! Use the symbolic expression
 * "nullExpression()" instead.
 * 
 * @author siegel
 * 
 */
public class PcollectionsSymbolicSequence<T extends SymbolicExpression> extends
		CommonSymbolicCollection<T> implements SymbolicSequence<T> {

	private PVector<T> pvector;

	public PcollectionsSymbolicSequence() {
		super(SymbolicCollectionKind.SEQUENCE);
		pvector = TreePVector.empty();
	}

	public PcollectionsSymbolicSequence(Collection<T> elements) {
		super(SymbolicCollectionKind.SEQUENCE);
		for (T element : elements) {
			if (element == null)
				throw new NullPointerException(
						"Attempt to place null element in a symbolic sequence");
		}
		pvector = TreePVector.from(elements);
	}

	public PcollectionsSymbolicSequence(Iterable<? extends T> elements) {
		this();
		for (T expr : elements) {
			if (expr == null)
				throw new NullPointerException(
						"Attempt to place null element in a symbolic sequence");
			pvector = pvector.plus(expr);
		}
	}

	public PcollectionsSymbolicSequence(T[] elements) {
		this();
		for (T expr : elements) {
			if (expr == null)
				throw new NullPointerException(
						"Attempt to place null element in a symbolic sequence");
			pvector = pvector.plus(expr);
		}
	}

	public PcollectionsSymbolicSequence(T element) {
		this();
		if (element == null)
			throw new NullPointerException(
					"Attempt to place null element in a symbolic sequence");
		pvector = pvector.plus(element);
	}

	@Override
	public Iterator<T> iterator() {
		return pvector.iterator();
	}

	@Override
	public int size() {
		return pvector.size();
	}

	@Override
	public T get(int index) {
		return pvector.get(index);
	}

	@Override
	public SymbolicSequence<T> add(T element) {
		return new PcollectionsSymbolicSequence<T>(pvector.plus(element));
	}

	@Override
	public SymbolicSequence<T> set(int index, T element) {
		return new PcollectionsSymbolicSequence<T>(pvector.with(index, element));
	}

	@Override
	public SymbolicSequence<T> remove(int index) {
		return new PcollectionsSymbolicSequence<T>(pvector.minus(index));
	}

	@Override
	protected boolean collectionEquals(SymbolicCollection<T> o) {
		if (this == o)
			return true;
		if (size() != o.size())
			return false;

		SymbolicSequence<T> that = (SymbolicSequence<T>) o;
		Iterator<T> these = this.iterator();
		Iterator<T> those = that.iterator();

		while (these.hasNext())
			if (!those.hasNext() || !these.next().equals(those.next()))
				return false;
		return !those.hasNext();
	}

	@Override
	protected int computeHashCode() {
		return pvector.hashCode();
	}

	@Override
	public SymbolicSequence<T> subSequence(int start, int end) {
		return new PcollectionsSymbolicSequence<T>(pvector.subList(start, end));
	}

	@Override
	public void canonizeChildren(CommonObjectFactory factory) {
		Iterator<T> iter = iterator();
		int count = 0;

		while (iter.hasNext()) {
			T expr = iter.next();

			if (!expr.isCanonic()) {
				PVector<T> newVector = pvector.subList(0, count);
				
				T canonic = factory.canonic(expr);

				assert canonic != null;
				newVector = newVector.plus(canonic);
				while (iter.hasNext()) {
					canonic = factory.canonic(iter.next());
					assert canonic != null;
					newVector = newVector.plus(canonic);
				}
				pvector = newVector;
				return;
			}
			count++;
		}
	}

	@Override
	public SymbolicSequence<T> setExtend(int index, T value, T filler) {
		int size = pvector.size();

		if (index < size)
			return set(index, value);
		else {
			PVector<T> newVector = pvector;

			for (int i = size; i < index; i++)
				newVector = newVector.plus(filler);
			newVector = newVector.plus(value);
			return new PcollectionsSymbolicSequence<T>(newVector);
		}
	}

	@Override
	public <U extends SymbolicExpression> SymbolicSequence<U> apply(
			Transform<T, U> transform) {
		int count = 0;
		Iterator<T> iter = pvector.iterator();

		while (iter.hasNext()) {
			T t = iter.next();
			U u = transform.apply(t);

			if (t != u) {
				@SuppressWarnings("unchecked")
				PVector<U> newVector = (PVector<U>) pvector.subList(0, count);

				newVector = newVector.plus(u);
				while (iter.hasNext())
					newVector = newVector.plus(transform.apply(iter.next()));
				return new PcollectionsSymbolicSequence<U>(newVector);
			}
			count++;
		}
		{
			@SuppressWarnings("unchecked")
			SymbolicSequence<U> result = (SymbolicSequence<U>) this;

			return result;
		}
	}

	@Override
	public StringBuffer toStringBuffer(boolean atomize) {
		StringBuffer result = new StringBuffer();
		boolean first = true;

		result.append("<");

		for (T element : this) {
			if (first)
				first = false;
			else
				result.append(",");
			result.append(element == null ? "null" : element
					.toStringBuffer(false));
		}
		result.append(">");
		return result;
	}

	@Override
	public StringBuffer toStringBufferLong() {
		StringBuffer result = new StringBuffer("Sequence");

		result.append(toStringBuffer(true));
		return result;
	}

}