content: /*******************************************************************************
   * Copyright (c) 2000, 2007 IBM Corporation and others.
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *   Robert M. Fuhrer (rfuhrer@watson.ibm.com), IBM Corporation - initial API and implementation
   *******************************************************************************/
  package org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets;
  
  import java.util.Iterator;
  
  import org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.types.ArrayType;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.types.TType;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints2.TTypes;
  
  public class SuperTypesSet extends TypeSet {
  	private TypeSet fLowerBounds;
  
  	SuperTypesSet(TType subType, TypeSetEnvironment typeSetEnvironment) {
  		super(typeSetEnvironment);
  		fLowerBounds= new SingletonTypeSet(subType, typeSetEnvironment);
  	}
  
  	SuperTypesSet(TypeSet subTypes, TypeSetEnvironment typeSetEnvironment) {
  		super(typeSetEnvironment);
  		fLowerBounds= subTypes;
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#isUniverse()
  	 */
  	public boolean isUniverse() {
  		return fLowerBounds.isUniverse();
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#makeClone()
  	 */
  	public TypeSet makeClone() {
  		return this; //new SuperTypesSet(fLowerBounds.makeClone(), getTypeSetEnvironment());
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#upperBound()
  	 */
  	public TypeSet upperBound() {
  		return new SingletonTypeSet(getTypeSetEnvironment().getJavaLangObject(), getTypeSetEnvironment());
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#lowerBound()
  	 */
  	public TypeSet lowerBound() {
  		// Ask the operand for its lower-bound, in case it's something like an
  		// EnumeratedTypeSet, which may have things in it other than the lower
  		// bound...
  		return fLowerBounds.lowerBound();
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#intersectedWith(org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.EnumeratedTypeSet)
  	 */
  	protected TypeSet specialCasesIntersectedWith(TypeSet s2) {
  		if (fLowerBounds.equals(s2))
  			return s2; // xsect(superTypes(A),A) = A
  		if (s2 instanceof SuperTypesSet) {
  			SuperTypesSet st2= (SuperTypesSet) s2;
  
  			if (fLowerBounds.isSingleton() && st2.fLowerBounds.isSingleton()) {
  				TType t1= this.fLowerBounds.anyMember();
  				TType t2= st2.fLowerBounds.anyMember();
  
  				if (TTypes.canAssignTo(t1, t2))
  					return new SuperTypesSet(st2.fLowerBounds, getTypeSetEnvironment());
  			} else if (fLowerBounds instanceof SubTypesSet) {
  				// xsect(superTypes(subTypes(A)), superTypes(A)) = superTypes(A)
  				SubTypesSet myLowerSubTypes= (SubTypesSet) fLowerBounds;
  
  				if (myLowerSubTypes.upperBound().equals(st2.upperBound()))
  					return st2;
  			}
  		}
  		if (s2 instanceof SuperTypesOfSingleton) {
  			SuperTypesOfSingleton st2= (SuperTypesOfSingleton) s2;
  
  			if (fLowerBounds.isSingleton()) {
  				TType t1= this.fLowerBounds.anyMember();
  				TType t2= st2.uniqueLowerBound();
  
  				if (TTypes.canAssignTo(t1, t2))
  					return getTypeSetEnvironment().createSuperTypesOfSingleton(t2);
  			} else if (fLowerBounds instanceof SubTypesOfSingleton) {
  				// xsect(superTypes(subTypes(A)), superTypes(A)) = superTypes(A)
  				SubTypesOfSingleton myLowerSubTypes= (SubTypesOfSingleton) fLowerBounds;
  
  				if (myLowerSubTypes.uniqueUpperBound().equals(st2.uniqueUpperBound()))
  					return st2;
  			}
  		}
  		if (s2 instanceof SubTypesSet) {
  			SubTypesSet st2= (SubTypesSet) s2;
  			if (fLowerBounds.equals(st2.upperBound()))
  				return fLowerBounds;
  
  			if (fLowerBounds instanceof TypeSetIntersection) {
  				// (intersect (superTypes (intersect (subTypes A) B))
  				//            (subTypes A)) =>
  				// (intersect (subTypes A) (superTypes B))
  				TypeSetIntersection lbXSect= (TypeSetIntersection) fLowerBounds;
  				TypeSet xsectLeft= lbXSect.getLHS();
  				TypeSet xsectRight= lbXSect.getRHS();
  
  				if (xsectLeft.equals(st2.upperBound()))
  					return new TypeSetIntersection(s2, new SuperTypesSet(xsectRight, getTypeSetEnvironment()));
  			}
  		}
  		return null;
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#superTypes()
  	 */
  	public TypeSet superTypes() {
  		return this; // makeClone();
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#isEmpty()
  	 */
  	public boolean isEmpty() {
  		return fLowerBounds.isEmpty();
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#contains(TType)
  	 */
  	public boolean contains(TType t) {
  		if (fEnumCache != null) return fEnumCache.contains(t);
  
  		if (t.equals(getJavaLangObject()))
  			return true;
  		if (fLowerBounds.contains(t))
  			return true;
  
  		// Find the "lower frontier", i.e. the lower bound, and see whether
  		// the given type is a supertype of any of those.
  		for(Iterator lbIter= fLowerBounds /*.lowerBound() */.iterator(); lbIter.hasNext(); ) {
  			TType lb= (TType) lbIter.next();
  
  			if (TTypes.canAssignTo(lb, t))
  				return true;
  		}
  		return false;
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#containsAll(org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.EnumeratedTypeSet)
  	 */
  	public boolean containsAll(TypeSet s) {
  		if (fEnumCache != null) return fEnumCache.containsAll(s);
  
  		if (!isUniverse() && s.isUniverse()) // this is more general than just SuperTypesSet; probably belongs in TypeSet
  			return false;
  		if (equals(s))
  			return true;
  		if (fLowerBounds.containsAll(s))
  			return true;
  
  		// Make sure all elements of s are contained in this set
  		for(Iterator sIter= s.iterator(); sIter.hasNext(); ) {
  			TType t= (TType) sIter.next();
  			boolean found= false;
  
  			// Scan the "lower frontier", i.e. the lower bound set, and see whether
  			// 't' is a supertype of any of those.
  			for(Iterator lbIter= fLowerBounds /*.lowerBound()*/.iterator(); lbIter.hasNext(); ) {
  				TType lb= (TType) lbIter.next();
  
  				if (TTypes.canAssignTo(lb, t)) {
  					found= true;
  					break;
  				}
  			}
  			if (!found) return false;
  		}
  		return true;
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#isSingleton()
  	 */
  	public boolean isSingleton() {
  		if (fEnumCache != null) return fEnumCache.isSingleton();
  
  		return fLowerBounds.isSingleton() && (fLowerBounds.anyMember() == getJavaLangObject());
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#anyMember()
  	 */
  	public TType anyMember() {
  		return fLowerBounds.anyMember();
  	}
  
  	/* (non-Javadoc)
  	 * @see java.lang.Object#equals(java.lang.Object)
  	 */
  	public boolean equals(Object o) {
  		if (o instanceof SuperTypesSet) {
  			SuperTypesSet other= (SuperTypesSet) o;
  			return other.fLowerBounds.equals(fLowerBounds);
  //		} else if (o instanceof TypeSet) {
  //			TypeSet other= (TypeSet) o;
  //			if (other.isUniverse() && isUniverse())
  //				return true;
  //			return enumerate().equals(other.enumerate());
  		} else
  			return false;
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#iterator()
  	 */
  	public Iterator iterator() {
  		return enumerate().iterator();
  	}
  
  	public String toString() {
  		return "<" + fID + ": superTypes(" + fLowerBounds + ")>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#hasUniqueLowerBound()
  	 */
  	public boolean hasUniqueLowerBound() {
  		return fLowerBounds.isSingleton();
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#hasUniqueUpperBound()
  	 */
  	public boolean hasUniqueUpperBound() {
  		return false;
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#uniqueLowerBound()
  	 */
  	public TType uniqueLowerBound() {
  		return fLowerBounds.isSingleton() ? fLowerBounds.anyMember() : null;
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#uniqueUpperBound()
  	 */
  	public TType uniqueUpperBound() {
  		return null;
  	}
  
  	private EnumeratedTypeSet fEnumCache= null;
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet#enumerate()
  	 */
  	public EnumeratedTypeSet enumerate() {
  		if (fEnumCache == null) {
  			fEnumCache= new EnumeratedTypeSet(getTypeSetEnvironment());
  			boolean anyLBIsIntfOrArray= false;
  
  			for(Iterator iter= fLowerBounds.iterator(); iter.hasNext(); ) {
  				TType lb= (TType) iter.next();
  
  				if (lb instanceof ArrayType) {
  					ArrayType at= (ArrayType) lb;
  					int numDims= at.getDimensions();
  					for(Iterator elemSuperIter=TTypes.getAllSuperTypesIterator(at.getElementType()); elemSuperIter.hasNext(); )
  						fEnumCache.add(TTypes.createArrayType((TType) elemSuperIter.next(), numDims));
  					anyLBIsIntfOrArray= true;
  				} else {
  					for (Iterator iterator= TTypes.getAllSuperTypesIterator(lb); iterator.hasNext(); )
  					fEnumCache.fMembers.add(iterator.next());
  				}
  				fEnumCache.add(lb);
  			}
  			if (anyLBIsIntfOrArray) fEnumCache.add(getJavaLangObject());
  			//fEnumCache.initComplete();
  		}
  		return fEnumCache;
  	}
  }
  