CommonObjectFactory.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.object.common;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

import edu.udel.cis.vsl.sarl.IF.SARLException;
import edu.udel.cis.vsl.sarl.IF.expr.SymbolicExpression;
import edu.udel.cis.vsl.sarl.IF.number.Number;
import edu.udel.cis.vsl.sarl.IF.number.NumberFactory;
import edu.udel.cis.vsl.sarl.IF.object.BooleanObject;
import edu.udel.cis.vsl.sarl.IF.object.CharObject;
import edu.udel.cis.vsl.sarl.IF.object.IntObject;
import edu.udel.cis.vsl.sarl.IF.object.NumberObject;
import edu.udel.cis.vsl.sarl.IF.object.StringObject;
import edu.udel.cis.vsl.sarl.IF.object.SymbolicObject;
import edu.udel.cis.vsl.sarl.IF.type.SymbolicType;
import edu.udel.cis.vsl.sarl.IF.type.SymbolicTypeSequence;
import edu.udel.cis.vsl.sarl.collections.IF.SymbolicCollection;
import edu.udel.cis.vsl.sarl.object.IF.ObjectFactory;

/**
 * The primary Factory for creating objects
 */
public class CommonObjectFactory implements ObjectFactory {

	private NumberFactory numberFactory;

	private Map<SymbolicObject, SymbolicObject> objectMap = new HashMap<SymbolicObject, SymbolicObject>();

	private ArrayList<SymbolicObject> objectList = new ArrayList<SymbolicObject>();

	// TODO: think about this: cache the total order for fast
	// comparisons...
	// private NavigableSet<SymbolicObject> sortedSet;

	private BooleanObject trueObj, falseObj;

	private IntObject zeroIntObj, oneIntObj;

	private NumberObject zeroIntegerObj, zeroRealObj, oneIntegerObj,
			oneRealObj;

	private ObjectComparator comparator;

	public CommonObjectFactory(NumberFactory numberFactory) {
		this.numberFactory = numberFactory;
		this.comparator = new ObjectComparator();
		this.trueObj = canonic(new CommonBooleanObject(true));
		this.falseObj = canonic(new CommonBooleanObject(false));
		this.zeroIntObj = canonic(intObject(0));
		this.oneIntObj = canonic(intObject(1));
		this.zeroIntegerObj = canonic(numberObject(numberFactory.zeroInteger()));
		this.zeroRealObj = canonic(numberObject(numberFactory.zeroRational()));
		this.oneIntegerObj = canonic(numberObject(numberFactory.oneInteger()));
		this.oneRealObj = canonic(numberObject(numberFactory.oneRational()));
	}

	@Override
	public NumberFactory numberFactory() {
		return numberFactory;
	}

	@Override
	public void setExpressionComparator(Comparator<SymbolicExpression> c) {
		comparator.setExpressionComparator(c);
	}

	@Override
	public void setCollectionComparator(Comparator<SymbolicCollection<?>> c) {
		comparator.setCollectionComparator(c);
	}

	@Override
	public void setTypeComparator(Comparator<SymbolicType> c) {
		comparator.setTypeComparator(c);
	}

	@Override
	public void setTypeSequenceComparator(Comparator<SymbolicTypeSequence> c) {
		comparator.setTypeSequenceComparator(c);
	}

	@Override
	public void init() {
		assert comparator.expressionComparator() != null;
		assert comparator.collectionComparator() != null;
		assert comparator.typeComparator() != null;
		assert comparator.typeSequenceComparator() != null;
		// TODO set the orders of all the objects you already created??
		// maybe only do this the first time they are used in
		// a comparison. How will the other comparators
		// do this
	}

	@Override
	public ObjectComparator comparator() {
		return comparator;
	}

	@Override
	public <T extends SymbolicObject> T canonic(T object) {
		if (object == null)
			throw new SARLException("null object");
		if (object.isCanonic())
			return object;
		else {
			SymbolicObject result = objectMap.get(object);

			if (result == null) {
				((CommonSymbolicObject) object).setId(objectList.size());
				objectMap.put(object, object);
				objectList.add(object);
				return object;
			}
			@SuppressWarnings("unchecked")
			T result2 = (T) result;

			// TODO set the order if you can.

			return result2;
		}
	}

	@Override
	public BooleanObject trueObj() {
		return trueObj;
	}

	@Override
	public BooleanObject falseObj() {
		return falseObj;
	}

	@Override
	public IntObject zeroIntObj() {
		return zeroIntObj;
	}

	@Override
	public IntObject oneIntObj() {
		return oneIntObj;
	}

	@Override
	public NumberObject zeroIntegerObj() {
		return zeroIntegerObj;
	}

	@Override
	public NumberObject oneIntegerObj() {
		return oneIntegerObj;
	}

	@Override
	public NumberObject zeroRealObj() {
		return zeroRealObj;
	}

	@Override
	public NumberObject oneRealObj() {
		return oneRealObj;
	}

	@Override
	public NumberObject numberObject(Number value) {
		if (value == null)
			throw new SARLException("null value");
		return new CommonNumberObject(value);
	}

	@Override
	public StringObject stringObject(String string) {
		if (string == null)
			throw new SARLException("null string");
		return canonic(new CommonStringObject(string));
	}

	@Override
	public IntObject intObject(int value) {
		return new CommonIntObject(value);
	}

	@Override
	public CharObject charObject(char value) {
		return new CommonCharObject(value);
	}

	@Override
	public BooleanObject booleanObject(boolean value) {
		return value ? trueObj : falseObj;
	}

	@Override
	public SymbolicObject objectWithId(int index) {
		return objectList.get(index);
	}

	@Override
	public Collection<SymbolicObject> objects() {
		return objectList;
	}

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