package com.redhat.ceylon.eclipse.util;

import java.util.HashSet;
import java.util.Set;

import com.redhat.ceylon.compiler.typechecker.model.Declaration;
import com.redhat.ceylon.compiler.typechecker.model.TypedDeclaration;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.Condition;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;

public class FindReferenceVisitor extends Visitor {
	
	private Declaration declaration;
	private final Set<Node> nodes = new HashSet<Node>();
	
	public FindReferenceVisitor(Declaration declaration) {
	    if (declaration instanceof TypedDeclaration) {
	        Declaration od = declaration;
	        while (od!=null) {
	            declaration = od;
	            od = ((TypedDeclaration) od).getOriginalDeclaration();
	        }
	    }
		this.declaration = declaration;
	}
	
	public Declaration getDeclaration() {
        return declaration;
    }
	
	public Set<Node> getNodes() {
		return nodes;
	}
	
	protected boolean isReference(Declaration ref) {
	    return ref!=null && declaration.refines(ref);
	}
	
    @Override
    public void visit(Tree.IfClause that) {
        Tree.Variable var = null;
        Condition c = that.getCondition();
        if (c instanceof Tree.ExistsOrNonemptyCondition) {
            var = ((Tree.ExistsOrNonemptyCondition) c).getVariable();
        }
        if (c instanceof Tree.IsCondition) {
            var = ((Tree.IsCondition) c).getVariable();
        }
        if (var!=null && var.getType() instanceof Tree.SyntheticVariable) {
            if (var.getDeclarationModel().getOriginalDeclaration()
                    .equals(declaration)) {
                c.visit(this);
                Declaration d = declaration;
                declaration = var.getDeclarationModel();
                that.getBlock().visit(this);
                declaration = d;
                return;
            }
        }
        super.visit(that);
    }
	
    @Override
    public void visit(Tree.ExtendedTypeExpression that) {}
    
	@Override
	public void visit(Tree.MemberOrTypeExpression that) {
		//TODO: handle refinement!
		if (isReference(that.getDeclaration())) {
			nodes.add(that);
		}
		super.visit(that);
	}
		
	@Override
	public void visit(Tree.NamedArgument that) {
		if (isReference(that.getParameter())) {
			nodes.add(that);
		}
		super.visit(that);
	}
		
	@Override
	public void visit(Tree.SimpleType that) {
		if (isReference(that.getTypeModel().getDeclaration())) {
			nodes.add(that);
		}
		super.visit(that);
	}
	
	/*@Override
	public void visit(Tree.SyntheticVariable that) {}*/

	@Override
	public void visit(Tree.ImportMemberOrType that) {
		if (isReference(that.getDeclarationModel())) {
			nodes.add(that);
		}
		super.visit(that);
	}
		
}

@@ -1176,58 +1176,247 @@
     
-@Override%0A    public void visit(Tree.IfClause that
+private Tree.Variable getConditionVariable(Condition c) %7B%0A        if (c instanceof Tree.ExistsOrNonemptyCondition) %7B%0A            return ((Tree.ExistsOrNonemptyCondition) c).getVariable();%0A        %7D%0A        if (c instanceof Tree.IsCondition
 ) %7B%0A
@@ -1427,133 +1427,437 @@
     
+   
-Tree.Variable var = null;%0A        Condition c = that.getCondition();%0A        if (c instanceof Tree.ExistsOrNonemptyCondi
+ return ((Tree.IsCondition) c).getVariable();%0A        %7D%0A        return null;%0A    %7D%0A    %0A    @Override%0A    public void visit(Tree.IfClause that) %7B%0A        Condition c = that.getCondition();%0A        Tree.Variable var = getConditionVariable(c);%0A        if (var!=null && var.getType() instanceof Tree.SyntheticVariable) %7B%0A            if (var.getDeclarationModel().getOriginalDeclaration()%0A                    .equals(declara
 tion)
+)
  %7B%0A 
@@ -1871,148 +1871,424 @@
     
-var = ((Tree.ExistsOrNonemptyCondition) c).getVariable();%0A        %7D%0A        if (c instanceof Tree.IsCondition) %7B%0A            var = ((Tree.Is
+    c.visit(this);%0A                Declaration d = declaration;%0A                declaration = var.getDeclarationModel();%0A                that.getBlock().visit(this);%0A                declaration = d;%0A                return;%0A            %7D%0A        %7D%0A        super.visit(that);%0A    %7D%0A%0A    @Override%0A    public void visit(Tree.WhileClause that) %7B%0A        Condition c = that.getCondition();%0A        Tree.Variable var = get
 Cond
@@ -2288,32 +2288,24 @@
 getCondition
-) c).get
 Variable();%0A
@@ -2297,37 +2297,28 @@
 ionVariable(
+c
 );%0A
-        %7D%0A
         if (
@@ -2784,17 +2784,20 @@
 ;%0A    %7D%0A
-%09
+    
 %0A    @Ov

correct reference finding with while