/*******************************************************************************
 * Copyright (c) 2009 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:
 *     IBM Corporation - initial API and implementation
 *     Zend Technologies
 *******************************************************************************/

package org.eclipse.php.core.ast.nodes;

import java.util.List;

import org.eclipse.dltk.ast.Modifiers;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.ti.types.IEvaluatedType;

/**
 * A type binding represents fully-resolved type. There are a number of
 * different kinds of type bindings:
 * <ul>
 * <li>a class - represents the class declaration; possibly with type parameters
 * </li>
 * <li>an interface - represents the class declaration; possibly with type
 * parameters</li>
 * <li>an annotation - represents the annotation type declaration (annotation
 * types do not have have type parameters)</li>
 * <li>an array type - array types are referenced but not explicitly declared
 * </li>
 * <li>a primitive type (including the special return type <code>void</code>) -
 * primitive types are referenced but not explicitly declared</li>
 * <li>the null type - this is the special type of <code>null</code></li>
 * <li>a type variable - represents the declaration of a type variable; possibly
 * with type bounds</li>
 * </ul>
 * <p>
 * This interface is not intended to be implemented by clients.
 * </p>
 * 
 * @see ITypeBinding#getDeclaredTypes()
 * @since 2.0
 */
public interface ITypeBinding extends IBinding {

	/**
	 * Answer an array type binding using the receiver and the given dimension.
	 * 
	 * <p>
	 * If the receiver is an array binding, then the resulting dimension is the
	 * given dimension plus the dimension of the receiver. Otherwise the
	 * resulting dimension is the given dimension.
	 * </p>
	 * 
	 * @param dimension
	 *            the given dimension
	 * @return an array type binding
	 * @throws IllegalArgumentException
	 *             :
	 *             <ul>
	 *             <li>if the receiver represents the void type</li>
	 *             <li>if the resulting dimensions is lower than one or greater
	 *             than 255</li>
	 *             </ul>
	 * @since 3.3
	 */
	public ITypeBinding createArrayType(int dimension);

	/**
	 * Returns the binary name of this type binding. The binary name of a class
	 * is defined in the Java Language Specification 3rd edition, section 13.1.
	 * <p>
	 * Note that in some cases, the binary name may be unavailable. This may
	 * happen, for example, for a local type declared in unreachable code.
	 * </p>
	 * 
	 * @return the binary name of this type, or <code>null</code> if the binary
	 *         name is unknown
	 * @since 3.0
	 */
	public String getBinaryName();

	/**
	 * Returns the binding representing the component type of this array type,
	 * or <code>null</code> if this is not an array type binding. The component
	 * type of an array might be an array type.
	 * <p>
	 * This is subject to change before 3.2 release.
	 * </p>
	 * 
	 * @return the component type binding, or <code>null</code> if this is not
	 *         an array type
	 * @since 3.2
	 */
	public ITypeBinding getComponentType();

	/**
	 * Returns a list of bindings representing all the fields declared as
	 * members of this class or interface type.
	 * 
	 * <p>
	 * These include public, protected, default (package-private) access, and
	 * private fields declared by the class, but excludes inherited fields.
	 * Fields from binary types that reference unresolvable types may not be
	 * included.
	 * </p>
	 * 
	 * <p>
	 * Returns an empty list if the class or interface declares no fields, and
	 * for other kinds of type bindings that do not directly have members.
	 * </p>
	 * 
	 * <p>
	 * The resulting bindings are in no particular order.
	 * </p>
	 * 
	 * @return the list of bindings for the field members of this type, or the
	 *         empty list if this type does not have field members
	 */
	public IVariableBinding[] getDeclaredFields();

	/**
	 * Returns a list of method bindings representing all the methods and
	 * constructors declared for this class, interface or annotation type.
	 * <p>
	 * These include public, protected, default (package-private) access, and
	 * private methods Synthetic methods and constructors may or may not be
	 * included. Returns an empty list if the class or interface type declares
	 * no methods or constructors, if the annotation type declares no members,
	 * or if this type binding represents some other kind of type binding.
	 * Methods from binary types that reference unresolvable types may not be
	 * included.
	 * </p>
	 * <p>
	 * The resulting bindings are in no particular order.
	 * </p>
	 * 
	 * @return the list of method bindings for the methods and constructors
	 *         declared by this class, interface, or annotation type, or the
	 *         empty list if this type does not declare any methods or
	 *         constructors
	 */
	public IMethodBinding[] getDeclaredMethods();

	/**
	 * Returns the declared modifiers for this class or interface binding as
	 * specified in the original source declaration of the class or interface.
	 * The result may not correspond to the modifiers in the compiled binary,
	 * since the compiler may change them (in particular, for inner class
	 * emulation). The <code>getModifiers</code> method should be used if the
	 * compiled modifiers are needed. Returns -1 if this type does not represent
	 * a class or interface.
	 * 
	 * @return the bit-wise or of <code>Modifiers</code> constants
	 * @see Modifiers
	 */
	public int getModifiers();

	/**
	 * Returns the dimensionality of this array type, or <code>0</code> if this
	 * is not an array type binding.
	 * 
	 * @return the number of dimension of this array type binding, or
	 *         <code>0</code> if this is not an array type
	 */
	public int getDimensions();

	/**
	 * Returns the binding representing the element type of this array type, or
	 * <code>null</code> if this is not an array type binding. The element type
	 * of an array is never itself an array type.
	 * 
	 * @return the element type binding, or <code>null</code> if this is not an
	 *         array type
	 */
	public ITypeBinding getElementType();

	/**
	 * Returns a list of type bindings representing the direct superinterfaces
	 * of the class, interface, or enum type represented by this type binding.
	 * <p>
	 * If this type binding represents a class or enum type, the return value is
	 * an array containing type bindings representing all interfaces directly
	 * implemented by this class. The number and order of the interface objects
	 * in the array corresponds to the number and order of the interface names
	 * in the <code>implements</code> clause of the original declaration of this
	 * type.
	 * </p>
	 * <p>
	 * If this type binding represents an interface, the array contains type
	 * bindings representing all interfaces directly extended by this interface.
	 * The number and order of the interface objects in the array corresponds to
	 * the number and order of the interface names in the <code>extends</code>
	 * clause of the original declaration of this interface.
	 * </p>
	 * <p>
	 * If the class or enum implements no interfaces, or the interface extends
	 * no interfaces, or if this type binding represents an array type, a
	 * primitive type, the null type, a type variable, an annotation type, a
	 * wildcard type, or a capture binding, this method returns an array of
	 * length 0.
	 * </p>
	 * 
	 * @return the list of type bindings for the interfaces extended by this
	 *         class or enum, or interfaces extended by this interface, or
	 *         otherwise the empty list
	 */
	public ITypeBinding[] getInterfaces();

	/**
	 * Returns the unqualified name of the type represented by this binding if
	 * it has one.
	 * <ul>
	 * <li>For top-level types, member types, and local types, the name is the
	 * simple name of the type. Example: <code>"String"</code> or
	 * <code>"Collection"</code>. Note that the type parameters of a generic
	 * type are not included.</li>
	 * <li>For primitive types, the name is the keyword for the primitive type.
	 * Example: <code>"int"</code>.</li>
	 * <li>For the null type, the name is the string "null".</li>
	 * <li>For anonymous classes, which do not have a name, this method returns
	 * an empty string.</li>
	 * <li>For array types, the name is the unqualified name of the component
	 * type (as computed by this method) followed by "[]". Example:
	 * <code>"String[]"</code>. Note that the component type is never an an
	 * anonymous class.</li>
	 * <li>For type variables, the name is just the simple name of the type
	 * variable (type bounds are not included). Example: <code>"X"</code>.</li>
	 * <li>For type bindings that correspond to particular instances of a
	 * generic type arising from a parameterized type reference, the name is the
	 * unqualified name of the erasure type (as computed by this method)
	 * followed by the names (again, as computed by this method) of the type
	 * arguments surrounded by "&lt;&gt;" and separated by ",". Example:
	 * <code>"Collection&lt;String&gt;"</code>.</li>
	 * <li>For type bindings that correspond to particular instances of a
	 * generic type arising from a raw type reference, the name is the
	 * unqualified name of the erasure type (as computed by this method).
	 * Example: <code>"Collection"</code>.</li>
	 * <li>For wildcard types, the name is "?" optionally followed by a single
	 * space followed by the keyword "extends" or "super" followed a single
	 * space followed by the name of the bound (as computed by this method) when
	 * present. Example: <code>"? extends InputStream"</code>.</li>
	 * <li>Capture types do not have a name. For these types, and array types
	 * thereof, this method returns an empty string.</li>
	 * </ul>
	 * 
	 * @return the unqualified name of the type represented by this binding, or
	 *         the empty string if it has none
	 * @see #getQualifiedName()
	 */
	public String getName();

	/**
	 * Returns the type associated with this binding.
	 * 
	 * @return the type
	 */
	public IEvaluatedType getEvaluatedType();

	/**
	 * Returns the binding for the package in which this type is declared.
	 * 
	 * <p>
	 * The package of a recovered type reference binding is either the package
	 * of the enclosing type, or, if the type name is the name of a
	 * {@linkplain AST#resolveWellKnownType(String) well-known type}, the
	 * package of the matching well-known type.
	 * </p>
	 * 
	 * @return the binding for the package in which this class, interface, enum,
	 *         or annotation type is declared, or <code>null</code> if this type
	 *         binding represents a primitive type, an array type, the null
	 *         type, a type variable, a wildcard type, a capture binding. public
	 *         IPackageBinding getPackage();
	 */

	/**
	 * Returns the type binding for the superclass of the type represented by
	 * this class binding.
	 * <p>
	 * If this type binding represents any class other than the class
	 * <code>java.lang.Object</code>, then the type binding for the direct
	 * superclass of this class is returned. If this type binding represents the
	 * class <code>java.lang.Object</code>, then <code>null</code> is returned.
	 * <p>
	 * Loops that ascend the class hierarchy need a suitable termination test.
	 * Rather than test the superclass for <code>null</code>, it is more
	 * transparent to check whether the class is <code>Object</code>, by
	 * comparing whether the class binding is identical to
	 * <code>ast.resolveWellKnownType("java.lang.Object")</code>.
	 * </p>
	 * <p>
	 * If this type binding represents an interface, an array type, a primitive
	 * type, the null type, a type variable, an enum type, an annotation type, a
	 * wildcard type, or a capture binding then <code>null</code> is returned.
	 * </p>
	 * 
	 * @return the superclass of the class represented by this type binding, or
	 *         <code>null</code> if none
	 * @see AST#resolveWellKnownType(String)
	 */
	public ITypeBinding getSuperclass();

	/**
	 * Returns the binding for the type declaration corresponding to this type
	 * binding.
	 * <p>
	 * For parameterized types ({@link #isParameterizedType()}) and most raw
	 * types ({@link #isRawType()}), this method returns the binding for the
	 * corresponding generic type.
	 * </p>
	 * <p>
	 * For raw member types ({@link #isRawType()}, {@link #isMember()}) of a raw
	 * declaring class, the type declaration is a generic or a non-generic type.
	 * </p>
	 * <p>
	 * A different non-generic binding will be returned when one of the
	 * declaring types/methods was parameterized.
	 * </p>
	 * <p>
	 * For other type bindings, this returns the same binding.
	 * </p>
	 * 
	 * @return the type binding
	 * @since 3.1
	 */
	public ITypeBinding getTypeDeclaration();

	/**
	 * Returns whether this type binding represents an annotation type.
	 * <p>
	 * Note that an annotation type is always an interface.
	 * </p>
	 * 
	 * @return <code>true</code> if this object represents an annotation type,
	 *         and <code>false</code> otherwise
	 * @since 3.1
	 */
	// public boolean isAnnotation();
	/**
	 * Returns whether this type binding represents an array type.
	 * 
	 * @return <code>true</code> if this type binding is for an array type, and
	 *         <code>false</code> otherwise
	 * @see #getElementType()
	 * @see #getDimensions()
	 */
	public boolean isArray();

	/**
	 * Returns whether this type binding represents a class type or a recovered
	 * binding.
	 * 
	 * @return <code>true</code> if this object represents a class or a
	 *         recovered binding, and <code>false</code> otherwise
	 */
	public boolean isClass();

	/**
	 * Returns whether this type binding represents a class type or a recovered
	 * binding.
	 * 
	 * @return <code>true</code> if this object represents a trait or a
	 *         recovered binding, and <code>false</code> otherwise
	 */
	public boolean isTrait();

	/**
	 * Returns whether this type binding represents an interface type.
	 * <p>
	 * Note that an interface can also be an annotation type.
	 * </p>
	 * 
	 * @return <code>true</code> if this object represents an interface, and
	 *         <code>false</code> otherwise
	 */
	public boolean isInterface();

	/**
	 * Returns whether this type binding represents the null type.
	 * <p>
	 * The null type is the type of a <code>NullLiteral</code> node.
	 * </p>
	 * 
	 * @return <code>true</code> if this type binding is for the null type, and
	 *         <code>false</code> otherwise
	 */
	public boolean isNullType();

	/**
	 * Returns whether this type binding represents a primitive type.
	 * <p>
	 * There are nine predefined type bindings to represent the eight primitive
	 * types and <code>void</code>. These have the same names as the primitive
	 * types that they represent, namely boolean, byte, char, short, int, long,
	 * float, and double, and void.
	 * </p>
	 * 
	 * @return <code>true</code> if this type binding is for a primitive type,
	 *         and <code>false</code> otherwise
	 */
	public boolean isPrimitive();

	/**
	 * Returns whether this type is subtype compatible with the given type.
	 * 
	 * @param type
	 *            the type to check compatibility against
	 * @return <code>true</code> if this type is subtype compatible with the
	 *         given type, and <code>false</code> otherwise
	 */
	public boolean isSubTypeCompatible(ITypeBinding type);

	/**
	 * Returns whether this type is exact or ambiguous (may relate to two or
	 * more types) i.e. if there are
	 * 
	 * @return <code>true</code> if this type is ambiguous and
	 *         <code>false</code> otherwise
	 */
	public boolean isAmbiguous();

	/**
	 * Returns whether this type is known (found) by our binding engine
	 * 
	 * @return <code>true</code> if this type is known and <code>false</code>
	 *         otherwise
	 */
	public boolean isUnknown();

	public List<IType> getTraitList(boolean isMethod, String classMemberName, boolean includeSuper);

	public org.eclipse.dltk.core.IModelElement[] getPHPElements();
}
