package testjdt3;

import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;

/**
 * Auxiliary class for additional services of ITypeBinding.
 * We consider SimpleType
 * TODO extends for generic and so on
  * @author jroyer
 *
 */
public class MyIType  {
	
	/**
	 * Resolved type.
	 */
	private ITypeBinding ibind;
	
	/**
	 * The proper structure.
	 */
	private Fields structure;
	
	/**
	 * Full super class name.
	 */
	private String supername;
	
	/**
	 * Defaut constructor.
	 */
	public MyIType(String sup) {
		this.supername = sup;
	}
	
	/**
	 * Constructor.
	 * @param it
	 */
	public MyIType(ITypeBinding it) {
		this.ibind = it;
		this.supername = "Java.lang.Object";
	}
	
	/**
	 * Get full name.
	 * @return
	 */
	public String getFullName() {
		// binary name 
		return this.ibind.getQualifiedName();
	}
	
	/**
	 * Add the fields in the structure and the  TypeInfo.
	 * Recursive method with side effects 
	 */
	public void storeStructure() {
		//System.out.println(" storeStructure " + this.ibind.getQualifiedName());
		// Only for SimpleType
		// get the declared fields of the class
		IVariableBinding[] ivbs = this.ibind.getDeclaredFields();
		// add the  fields and resolved if not yet declared 
		Fields champs = new Fields();
		for (int i = 0; i < ivbs.length; i++) {
			// get the binding variables
			IVariableBinding field = ivbs[i];
			ITypeBinding ibd = field.getType();
			String fullname = ibd.getQualifiedName();
			if (ASTActionDelegate.table.isOfInterest(fullname) &&
					!ASTActionDelegate.table.isDataType(fullname)) {
				// add structure information
				champs.add(field);
				//  recursive resolution and store
				if (!ASTActionDelegate.table.isResolved(fullname)
						&& ibd.isClass()) {
					// set component type indicator
					ASTActionDelegate.table.setComponentType(fullname);
					//  add the resolved type in the table
					// TODO
					//MyIType mit = new MyIType(ibd);
					MyIType mit = ASTActionDelegate.table.get(fullname).getIbind();
					mit.setIbind(ibd);
					// to stop infinite loop
					ASTActionDelegate.table.setType(fullname, mit);
					// compute the structure
					mit.storeStructure();
					ASTActionDelegate.table.setType(fullname, mit);
				}	
			}	
		}
		// analyse inheritance 
		ITypeBinding sup = this.ibind.getSuperclass();
		if (sup != null) {
			String supname = sup.getQualifiedName();
			// test if class and type of interest
			if (sup.isClass() && ASTActionDelegate.table.isOfInterest(supname)
					&& !ASTActionDelegate.table.isDataType(supname)) {
				System.out.println(" Inherits from " + this.ibind.getQualifiedName() + " to " + supname + " struc ");
				// recursive resolution and store
				if (!ASTActionDelegate.table.isResolved(supname)
						|| !ASTActionDelegate.table.hasFields(supname)) {
					// set component type indicator TODO why ?
					ASTActionDelegate.table.setComponentType(supname);
					// add the resolved type in the table
					// TODO
					//MyIType mit = new MyIType(sup);
					MyIType mit = ASTActionDelegate.table.get(supname).getIbind();
					mit.setIbind(sup);
					// to stop infinite loop
					ASTActionDelegate.table.setType(supname, mit);
					// compute the structure
					mit.storeStructure();
					ASTActionDelegate.table.setType(supname, mit);
				}
				// simple merge of locals and inherited fields
				this.structure = champs.merge(ASTActionDelegate.table.getStructure(supname));					
			} else {
				this.structure = champs;
			}
		} else {
			this.structure = champs;
		}
	}

	/**
	 * String representation.
	 */
	public String toString() {
		String result = "";
		if (this.isResolved()) {
			result += this.getFullName() + " super " + this.supername + " -> " + this.structure;
		} else {
			result += "NOT resolved  super " + this.supername;
		}
		return result;
	}
	
	/**
	 * Set the structure.
	 * @param struc
	 */
	public void setStructure(Fields struc) {
		this.structure = struc;
	}

	/**
	 * Get the structure.
	 * @return
	 */
	public Fields getStructure() {
		return structure;
	}

	/**
	 * Test if structure exists.
	 * @return
	 */
	public boolean hasFields() {
		return this.structure != null;
	}

	public String getSupername() {
		return supername;
	}

	public void setSupername(String supername) {
		this.supername = supername;
	}

	/**
	 * Test if typebinding is resolved.
	 * @return
	 */
	public boolean isResolved() {
		return this.ibind != null;
	}

	public ITypeBinding getIbind() {
		return ibind;
	}

	public void setIbind(ITypeBinding ibind) {
		this.ibind = ibind;
	}
}
