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

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.List;

import com.redhat.ceylon.compiler.typechecker.model.Declaration;
import com.redhat.ceylon.compiler.typechecker.model.Parameter;
import com.redhat.ceylon.compiler.typechecker.model.ProducedType;
import com.redhat.ceylon.compiler.typechecker.tree.NaturalVisitor;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;


public class PrintVisitor extends Visitor implements NaturalVisitor {
    
    int depth=0;
    Writer stream;

    public PrintVisitor() {
        stream = new OutputStreamWriter(System.out);
    }
    
    public PrintVisitor(Writer w) {
        stream = w;
    }
    
    protected void print(String str) {
        try {
            stream.write(str);
        }
        catch (IOException ioe) {
            throw new RuntimeException(ioe);
        }
    }

    void newline() {
        print("\n");
    }

    void indent() {
        for (int i = 0; i < depth; i++)
            print("|  ");
    }

    @Override
    public void visitAny(Node node) {
        if (depth>0) newline();
        indent();
        print("+ ");
        print(node);
        depth++;
        super.visitAny(node);
        depth--;
        if (depth==0) newline();
        try {
            stream.flush();
        }
        catch (IOException ioe) {
            throw new RuntimeException(ioe);
        }
    }

    private void print(Node node) {
        print(node.getText()); 
        print (" [" + node.getNodeType() + "]");
        if (node instanceof Tree.Term) {
            ProducedType type = ((Tree.Term) node).getTypeModel();
            if (type!=null) {
                print(" <" + type.getProducedTypeName() + ">");
            }
        }
        if (node instanceof Tree.Type) {
            ProducedType type = ((Tree.Type) node).getTypeModel();
            if (type!=null) {
                print(" <" + type.getProducedTypeName() + ">");
            }
        }
        if (node instanceof Tree.TypeArguments) {
            List<ProducedType> types = ((Tree.TypeArguments) node).getTypeModels();
            if (types!=null && !types.isEmpty()) {
                print(" <");
                int i=0;
                for (ProducedType pt: types) {
                    if (pt!=null) {
                    	print(pt.getProducedTypeName());
                    }
                    if (++i!=types.size()) {
                        print(", ");
                    }
                }
                print(">");
            }
        }
        if (node.getToken()!=null) {
            print(" (" + node.getLocation() + ")");
        }
        if (node instanceof Tree.MemberOrTypeExpression) {
            Declaration d = ((Tree.MemberOrTypeExpression) node).getDeclaration();
            if (d!=null) {
                print(" => " + d);
            }
        }
        if (node instanceof Tree.Declaration) {
            Declaration d = ((Tree.Declaration) node).getDeclarationModel();
            if (d.isCaptured()) {
                print("[captured]");
            }
            if (d!=null) {
                print(" => " + d);
            }
        }
        if (node instanceof Tree.SimpleType) {
            Declaration d = ((Tree.SimpleType) node).getDeclarationModel();
            if (d!=null) {
                print(" => " + d);
            }
        }
        if (node instanceof Tree.ImportMemberOrType) {
            Declaration d = ((Tree.ImportMemberOrType) node).getDeclarationModel();
            if (d!=null) {
                print(" => " + d);
            }
        }
        if (node instanceof Tree.Return) {
        	Declaration d = ((Tree.Return) node).getDeclaration();
			if (d!=null) {
				print(" => " + d);
			}
        }
        if (node instanceof Tree.PositionalArgument) {
        	Parameter p = ((Tree.PositionalArgument) node).getParameter();
			if (p!=null) {
				print(" => " + p);
			}
        }
        if (node instanceof Tree.NamedArgument) {
        	Parameter p = ((Tree.NamedArgument) node).getParameter();
			if (p!=null) {
				print(" => " + p);
			}
        }
        if (node instanceof Tree.SequencedArgument) {
        	Parameter p = ((Tree.SequencedArgument) node).getParameter();
			if (p!=null) {
				print(" => " + p);
			}
        }
        if (!node.getErrors().isEmpty()) {
            print(" [X]" + node.getErrors());
        }
    }
}
@@ -3171,32 +3171,63 @@
 arationModel();%0A
+            if (d!=null) %7B%0A    
             if (
@@ -3240,24 +3240,28 @@
 ptured()) %7B%0A
+    
             
@@ -3300,37 +3300,14 @@
     
- %7D%0A
      
-       if (d!=null) %7B
+%7D
 %0A   

fix npe in PrintVisitor