package com.redhat.ceylon.eclipse.code.quickfix;

import static com.redhat.ceylon.eclipse.code.parse.CeylonSourcePositionLocator.findStatement;
import static com.redhat.ceylon.eclipse.code.parse.CeylonSourcePositionLocator.getIdentifyingNode;
import static com.redhat.ceylon.eclipse.code.refactor.AbstractRefactoring.guessName;

import java.util.Collection;

import org.eclipse.core.resources.IFile;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.ltk.core.refactoring.TextChange;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;

import com.redhat.ceylon.compiler.typechecker.model.Declaration;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.BaseMemberExpression;
import com.redhat.ceylon.eclipse.code.editor.Util;
import com.redhat.ceylon.eclipse.util.FindReferenceVisitor;

class ShadowReferenceProposal extends ChangeCorrectionProposal {
    
    final IFile file;
    final int offset;
    final int length;
    
    ShadowReferenceProposal(int offset, int length, IFile file, 
            TextChange change) {
        super("Shadow reference inside control structure", change);
        this.file=file;
        this.offset=offset;
        this.length=length;
    }
    
    @Override
    public void apply(IDocument document) {
        super.apply(document);
        Util.gotoLocation(file, offset, length);
    }
    
    static void addShadowSwitchReferenceProposal(IFile file, Tree.CompilationUnit cu, 
            Collection<ICompletionProposal> proposals, Node node) {
        if (node instanceof Tree.Term) {
        	Tree.Statement statement = findStatement(cu, node);
        	if (statement instanceof Tree.SwitchStatement) {
        		String name = guessName(node);
        		TextChange change = new TextFileChange("Shadow Reference", file);
        		change.setEdit(new MultiTextEdit());
        		Integer offset = statement.getStartIndex();
				change.addEdit(new ReplaceEdit(offset, 
        				node.getStartIndex()-offset,
        				"value " + name + " = "));
        		change.addEdit(new InsertEdit(node.getStopIndex()+1, "; switch (" + name));
        		if (node instanceof BaseMemberExpression) {
        			Declaration d = ((BaseMemberExpression) node).getDeclaration();
        			if (d!=null) {
        				FindReferenceVisitor frv = new FindReferenceVisitor(d);
        				frv.visit(((Tree.SwitchStatement) statement).getSwitchCaseList());
        				for (Node n: frv.getNodes()) {
        					Node identifyingNode = getIdentifyingNode(n);
        					Integer start = identifyingNode.getStartIndex();
        					if (start!=node.getStartIndex()) {
        						change.addEdit(new ReplaceEdit(start, 
        								identifyingNode.getText().length(), name));
        					}
        				}
        			}
        		}
        		proposals.add(new ShadowReferenceProposal(offset+6, name.length(), file, change));
        	}
        }
    }
    
    static void addShadowReferenceProposal(IFile file, Tree.CompilationUnit cu, 
            Collection<ICompletionProposal> proposals, Node node) {
        if (node instanceof Tree.Variable) {
            Tree.Variable var = (Tree.Variable) node;
            int offset = var.getIdentifier().getStartIndex();
            String name = guessName(var.getSpecifierExpression().getExpression().getTerm());
            TextChange change = new TextFileChange("Shadow Reference", file);
            change.setEdit(new MultiTextEdit());
            change.addEdit(new InsertEdit(offset, name + " = "));
            Tree.Statement statement = findStatement(cu, node);
            FindReferenceVisitor frv = new FindReferenceVisitor(var.getDeclarationModel());
            frv.visit(statement);
            for (Node n: frv.getNodes()) {
                Node identifyingNode = getIdentifyingNode(n);
                Integer start = identifyingNode.getStartIndex();
                if (start!=offset) {
                    change.addEdit(new ReplaceEdit(start, 
                            identifyingNode.getText().length(), name));
                }
            }
            proposals.add(new ShadowReferenceProposal(offset, 1, file, change));
        }
        else if (node instanceof Tree.Term) {
            String name = guessName(node);
            TextChange change = new TextFileChange("Shadow Reference", file);
//            change.setEdit(new MultiTextEdit());
            Integer offset = node.getStartIndex();
            change.setEdit(new InsertEdit(offset, name + " = "));
            proposals.add(new ShadowReferenceProposal(offset, 1, file, change));
        }
    }
}
@@ -991,24 +991,93 @@
 Expression;%0A
+import com.redhat.ceylon.eclipse.code.editor.CeylonAutoEditStrategy;%0A
 import com.r
@@ -1115,16 +1115,16 @@
 r.Util;%0A
-
 import c
@@ -2380,24 +2380,18 @@
  = %22));%0A
-        
+%09%09
 %09%09change
@@ -2441,11 +2441,110 @@
 +1, 
-%22; 
+%0A        %09%09%09%09%22;%22 + System.lineSeparator() + %0A        %09%09%09%09getStatementIndent(statement) +%0A        %09%09%09%09%22
 swit
@@ -3344,16 +3344,16 @@
      %09%7D%0A
-
         
@@ -3355,24 +3355,491 @@
      %7D%0A    %7D
+%0A%0A    //TODO: this is rubbish, we need a much better way to get indents%0A    //      when we don't have an IDocument%0A%09private static String getStatementIndent(Tree.Statement statement) %7B%0A%09    int pos = statement.getToken().getCharPositionInLine();%0A%09    String di = CeylonAutoEditStrategy.getDefaultIndent();%0A%09    StringBuffer indent = new StringBuffer();%0A%09    for (int i=0; i%3Cpos/di.length(); i++) %7B%0A%09    %09indent.append(di);%0A%09    %7D%0A%09    return indent.toString();%0A    %7D
 %0A    %0A    st

fix ws in shadow reference for switch