package com.redhat.ceylon.compiler.typechecker.model;

import java.util.Collections;
import java.util.Map;

/**
 * A produced type or produced reference to a
 * method or attribute
 *
 * @author Gavin King
 */
public abstract class ProducedReference {

    ProducedReference() {}

    private Map<TypeParameter, ProducedType> typeArguments = Collections.emptyMap();
    private Declaration declaration;
    private ProducedType qualifyingType;

    public ProducedType getQualifyingType() {
        return qualifyingType;
    }

    void setQualifyingType(ProducedType qualifyingType) {
        this.qualifyingType = qualifyingType;
    }

    public Declaration getDeclaration() {
        return declaration;
    }

    void setDeclaration(Declaration type) {
        this.declaration = type;
    }

    public Map<TypeParameter, ProducedType> getTypeArguments() {
    	if (declaration instanceof Generic) {
    		for (TypeParameter pt: ((Generic)declaration).getTypeParameters()) {
    			if (!typeArguments.containsKey(pt)) {
    				ProducedType dta = pt.getDefaultTypeArgument();
    				if (dta!=null) {
    					typeArguments.put(pt, dta.substitute(typeArguments));
    				}
    			}
    		}
    	}
        return typeArguments;
    }

    void setTypeArguments(Map<TypeParameter, ProducedType> typeArguments) {
        this.typeArguments = typeArguments;
    }

    public abstract ProducedType getType();
    
    public ProducedType getFullType() {
    	return getFullType(getType());
    }

    public ProducedType getFullType(ProducedType wrappedType) {
    	if (getDeclaration() instanceof Functional) {
    		return getDeclaration().getUnit().getCallableType(this, wrappedType);
    	}
    	else {
    		return wrappedType;
    	}
    }
    
    public boolean isFunctional() {
        return declaration instanceof Functional;
    }

    /**
     * Get the type of a parameter, after substitution of
     * type arguments.
     */
    public ProducedTypedReference getTypedParameter(Parameter p) {
        ProducedTypedReference ptr = new ProducedTypedReference();
        ptr.setDeclaration(p.getModel());
        ptr.setQualifyingType(getQualifyingType());
        ptr.setTypeArguments(getTypeArguments());
        return ptr;
    }
    
}

@@ -78,16 +78,42 @@
 ctions;%0A
+import java.util.HashMap;%0A
 import j
@@ -126,16 +126,16 @@
 il.Map;%0A
-
 %0A/**%0A * 
@@ -539,33 +539,37 @@
 yingType;%0A    %7D%0A
+    
 %0A
-
     void setQual
@@ -654,33 +654,37 @@
 yingType;%0A    %7D%0A
+    
 %0A
-
     public Decla
@@ -735,33 +735,37 @@
 laration;%0A    %7D%0A
+    
 %0A
-
     void setDecl
@@ -823,33 +823,37 @@
 n = type;%0A    %7D%0A
+    
 %0A
-
     public Map%3CT
@@ -905,349 +905,8 @@
 ) %7B%0A
-    %09if (declaration instanceof Generic) %7B%0A    %09%09for (TypeParameter pt: ((Generic)declaration).getTypeParameters()) %7B%0A    %09%09%09if (!typeArguments.containsKey(pt)) %7B%0A    %09%09%09%09ProducedType dta = pt.getDefaultTypeArgument();%0A    %09%09%09%09if (dta!=null) %7B%0A    %09%09%09%09%09typeArguments.put(pt, dta.substitute(typeArguments));%0A    %09%09%09%09%7D%0A    %09%09%09%7D%0A    %09%09%7D%0A    %09%7D%0A
     
@@ -933,25 +933,29 @@
 ents;%0A    %7D%0A
+    
 %0A
-
     void set
@@ -1030,50 +1030,678 @@
     
-this.typeArguments = typeArguments;
+if (declaration==null) throw new IllegalStateException(%22set the Declaration first%22);%0A        this.typeArguments = new HashMap%3CTypeParameter,ProducedType%3E(typeArguments.size());%0A        this.typeArguments.putAll(typeArguments);%0A        if (declaration instanceof Generic) %7B%0A            for (TypeParameter pt: ((Generic)declaration).getTypeParameters()) %7B%0A                if (!typeArguments.containsKey(pt)) %7B%0A                    ProducedType dta = pt.getDefaultTypeArgument();%0A                    if (dta!=null) %7B%0A                        this.typeArguments.put(pt, dta.substitute(typeArguments));%0A                    %7D%0A                %7D%0A            %7D%0A        %7D
 %0A    %7D%0A
+    
 %0A   

stop recomputing default type args