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

import static com.redhat.ceylon.compiler.typechecker.model.Util.isTypeUnknown;

import java.util.Collection;

import org.eclipse.core.resources.IFile;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.Region;
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.model.ProducedType;
import com.redhat.ceylon.compiler.typechecker.model.Value;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.Type;

class AssertExistsDeclarationProposal extends CorrectionProposal {
    
	private AssertExistsDeclarationProposal(Declaration dec, 
	        int offset, TextChange change) {
        super("Change to 'assert (exists " + dec.getName() + ")'", change,
                new Region(offset, 0));
    }
    
	private static void addSplitDeclarationProposal(IDocument doc, 
	        Tree.AttributeDeclaration decNode, Tree.CompilationUnit cu, 
	        IFile file, Collection<ICompletionProposal> proposals) {
        Value dec = decNode.getDeclarationModel();
        Tree.SpecifierOrInitializerExpression sie = 
                decNode.getSpecifierOrInitializerExpression();
        if (dec==null || dec.isParameter() || dec.isToplevel() ||
                sie==null || sie.getExpression()==null) { 
            return;
        }
        ProducedType siet = sie.getExpression().getTypeModel();
        ProducedType nvt = cu.getUnit().getNullValueDeclaration().getType();
        if (isTypeUnknown(siet) || !nvt.isSubtypeOf(siet)) {
            return;
        }
        Tree.Identifier id = decNode.getIdentifier();
        if (id==null || id.getToken()==null) {
            return;
        }
//        int idStartOffset = id.getStartIndex();
        int idEndOffset = id.getStopIndex()+1;
        int semiOffset = decNode.getStopIndex();
        
        TextChange change = new TextFileChange("Assert Exists Declaration", file);
        change.setEdit(new MultiTextEdit());

        Type type = decNode.getType();
        Integer typeOffset = type.getStartIndex();
        Integer typeLen = type.getStopIndex()-typeOffset+1;
        change.addEdit(new ReplaceEdit(typeOffset, typeLen, 
                "assert (exists"));
        change.addEdit(new InsertEdit(semiOffset, ")"));
        proposals.add(new AssertExistsDeclarationProposal(dec, 
                idEndOffset + 14 - typeLen, change));
    }

	static void addAssertExistsDeclarationProposals(
			Collection<ICompletionProposal> proposals, IDocument doc,
			IFile file, Tree.CompilationUnit cu, Tree.Declaration decNode) {
	    if (decNode==null) return;
	    Declaration dec = decNode.getDeclarationModel();
	    if (dec!=null) {
	        if (decNode instanceof Tree.AttributeDeclaration) {
	            Tree.AttributeDeclaration attDecNode = 
	                    (Tree.AttributeDeclaration) decNode;
	            Tree.SpecifierOrInitializerExpression sie = 
	                    attDecNode.getSpecifierOrInitializerExpression();
	            if (sie!=null || dec.isParameter()) {
	                addSplitDeclarationProposal(doc, attDecNode, cu, file, proposals);
	            }
	        }
	    }
	}
    
}
@@ -1021,24 +1021,49 @@
 c, %0A%09       
+ String existsOrNonempty,
  int offset,
@@ -1118,22 +1118,40 @@
 assert (
+%22 + 
 exists
+OrNonempty + %22
  %22 + dec
@@ -1173,15 +1173,8 @@
 '%22, 
-change,
 %0A   
@@ -1185,16 +1185,24 @@
         
+ change,
  new Reg
@@ -1828,135 +1828,422 @@
     
-ProducedType nvt = cu.getUnit().getNullValueDeclaration().getType();%0A        if (isTypeUnknown(siet) %7C%7C !nvt.isSubtypeOf(siet))
+String existsOrNonempty;%0A        String desc;%0A        if (isTypeUnknown(siet)) %7B%0A            return;%0A        %7D%0A        else if (cu.getUnit().isOptionalType(siet)) %7B%0A            existsOrNonempty = %22exists%22;%0A            desc = %22Assert Exists%22;%0A        %7D%0A        else if (cu.getUnit().isPossiblyEmptyType(siet)) %7B%0A            existsOrNonempty = %22nonempty%22;%0A            desc = %22Assert Nonempty%22;%0A        %7D%0A        else
  %7B%0A 
@@ -2608,35 +2608,12 @@
 nge(
-%22Assert Exists Declaration%22
+desc
 , fi
@@ -2899,23 +2899,36 @@
 assert (
+%22 + 
 exists
-%22
+OrNonempty
 ));%0A    
@@ -3064,35 +3064,113 @@
     
-idEndOffset + 14 - typeLen,
+existsOrNonempty,%0A                idEndOffset + 8 + existsOrNonempty.length() - typeLen, %0A               
  cha
@@ -3818,24 +3818,24 @@
 ameter()) %7B%0A
-
 %09           
@@ -3872,16 +3872,42 @@
 al(doc, 
+%0A%09                        
 attDecNo

enhance to propose assert(nonempty) as well as assert(exists)