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

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

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.Change;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.text.edits.DeleteEdit;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;

import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;

class ConvertToInterpolationProposal extends CorrectionProposal {

    private ConvertToInterpolationProposal(String name, Change change) {
        super(name, change, null);
    }
    
    private static List<Tree.Term> flatten(Tree.SumOp sum) {
        Tree.Term lt = sum.getLeftTerm();
        Tree.Term rt = sum.getRightTerm();
        List<Tree.Term> result;
        if (lt instanceof Tree.SumOp) {
            result = flatten((Tree.SumOp) lt);
            result.add(rt);
        }
        else {
            result = new ArrayList<Tree.Term>();
            result.add(lt);
            result.add(rt);
        }
        return result;
    }

    private static boolean isConcatenation(Tree.SumOp sum) {
        List<Tree.Term> terms = flatten(sum);
        Tree.Term lt = terms.get(0);
        boolean expectingLiteral =
                lt instanceof Tree.StringLiteral ||
                lt instanceof Tree.StringTemplate;
        for (Tree.Term term: terms) {
            if (expectingLiteral) {
                if (!(term instanceof Tree.StringLiteral ||
                      term instanceof Tree.StringTemplate)) {
                    return false;
                }
                expectingLiteral = false;
            }
            else {
                expectingLiteral = true;
            }
        }
        return true;
    }
    
    static class ConcatenationVisitor extends Visitor {
        Node node;
        Tree.SumOp result;
        ConcatenationVisitor(Node node) {
            this.node = node;
        }
        @Override
        public void visit(Tree.SumOp that) {
            if (that.getStartIndex()<=node.getStartIndex() &&
                that.getEndIndex()>=node.getEndIndex()) {
                if (isConcatenation(that)) {
                    result = that;
                    return;
                }
            }
            super.visit(that);
        }
    }
    
    static void addConvertToInterpolationProposal(
            Collection<ICompletionProposal> proposals,
            IFile file, Tree.CompilationUnit cu, Node node, 
            IDocument doc) {
        ConcatenationVisitor tv = 
                new ConcatenationVisitor(node);
        tv.visit(cu);
        Tree.SumOp sum = tv.result;
        if (sum!=null) {
            TextFileChange change = 
                    new TextFileChange(
                            "Convert to Interpolation", 
                            file);
            change.setEdit(new MultiTextEdit());
            List<Tree.Term> terms = flatten(sum);
            Tree.Term lt = terms.get(0);
            Tree.Term rt = terms.get(terms.size()-1);
            boolean expectingLiteral =
                    lt instanceof Tree.StringLiteral ||
                    lt instanceof Tree.StringTemplate;
            if (!expectingLiteral) {
                change.addEdit(new InsertEdit(lt.getStartIndex(), "\"``"));
            }
            for (int i=0; i<terms.size(); i++) {
                Tree.Term term = terms.get(i);
                if (i>0) {
                    Tree.Term previous = terms.get(i-1);
                    int from = previous.getEndIndex();
                    int to = term.getStartIndex();
                    change.addEdit(new DeleteEdit(from, to-from));
                }
                if (expectingLiteral) {
                    if (i>0) {
                        change.addEdit(new ReplaceEdit(term.getStartIndex(), 1, "``"));
                    }
                    if (i<terms.size()-1) {
                        change.addEdit(new ReplaceEdit(term.getEndIndex()-1, 1, "``"));
                    }
                    expectingLiteral = false;
                }
                else {
                    if (term instanceof Tree.QualifiedMemberExpression) {
                        Tree.QualifiedMemberExpression lrt = 
                                (Tree.QualifiedMemberExpression) term;
                        if (lrt.getDeclaration().getName().equals("string")) {
                            int from = lrt.getMemberOperator().getStartIndex();
                            int to = lrt.getIdentifier().getEndIndex();
                            change.addEdit(new DeleteEdit(from, to-from));
                        }
                    }
                    expectingLiteral = true;
                }
            }
            if (expectingLiteral) {
                change.addEdit(new InsertEdit(rt.getEndIndex(), "``\""));
            }
            proposals.add(new ConvertToInterpolationProposal(
                    "Convert to string interpolation", change));
        }
    }
    
    
}
@@ -1373,706 +1373,8 @@
    %7D
-%0A%0A    private static boolean isConcatenation(Tree.SumOp sum) %7B%0A        List%3CTree.Term%3E terms = flatten(sum);%0A        Tree.Term lt = terms.get(0);%0A        boolean expectingLiteral =%0A                lt instanceof Tree.StringLiteral %7C%7C%0A                lt instanceof Tree.StringTemplate;%0A        for (Tree.Term term: terms) %7B%0A            if (expectingLiteral) %7B%0A                if (!(term instanceof Tree.StringLiteral %7C%7C%0A                      term instanceof Tree.StringTemplate)) %7B%0A                    return false;%0A                %7D%0A                expectingLiteral = false;%0A            %7D%0A            else %7B%0A                expectingLiteral = true;%0A            %7D%0A        %7D%0A        return true;%0A    %7D
 %0A   
@@ -1738,19 +1738,19 @@
 dIndex()
-) %7B
+ &&
 %0A       
@@ -1762,41 +1762,87 @@
     
-if (isConcatenation(that
+that.getTypeModel()!=null &&%0A                that.getTypeModel().isString(
 )) %7B%0A
-    
     
@@ -1888,20 +1888,16 @@
     
-    
 return;%0A
     
@@ -1892,34 +1892,16 @@
 return;%0A
-                %7D%0A
         
@@ -3323,32 +3323,349 @@
               %7D%0A
+                if (expectingLiteral && %0A                        !(term instanceof Tree.StringLiteral %7C%7C%0A                          term instanceof Tree.StringTemplate)) %7B%0A                    change.addEdit(new InsertEdit(term.getStartIndex(), %22%60%60%60%60%22));%0A                    expectingLiteral = false;%0A                %7D%0A
                 

make convert to string interpolation much less finicky