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

import static com.redhat.ceylon.eclipse.code.editor.EditorUtil.getCurrentEditor;

import java.util.List;
import java.util.StringTokenizer;

import org.eclipse.jface.viewers.StyledString;
import org.eclipse.ui.IEditorPart;

import com.redhat.ceylon.compiler.typechecker.context.PhasedUnit;
import com.redhat.ceylon.compiler.typechecker.model.ProducedType;
import com.redhat.ceylon.compiler.typechecker.model.Unit;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.eclipse.code.complete.CompletionUtil;
import com.redhat.ceylon.eclipse.code.editor.CeylonEditor;
import com.redhat.ceylon.eclipse.code.parse.CeylonParseController;

class CorrectionUtil {
    
    static int getLevenshteinDistance(String x, String y) {
        
        int n = x.length(); // length of s
        int m = y.length(); // length of t
              
        if (n == 0) return m;
        if (m == 0) return n;

        int p[] = new int[n+1]; //'previous' cost array, horizontally
        int d[] = new int[n+1]; // cost array, horizontally
        int _d[]; //placeholder to assist in swapping p and d

        // indexes into strings s and t
        int i; // iterates through s
        int j; // iterates through t

        char t_j; // jth character of t

        int cost; // cost

        for (i = 0; i<=n; i++) {
           p[i] = i;
        }
              
        for (j = 1; j<=m; j++) {
           t_j = y.charAt(j-1);
           d[0] = j;
              
           for (i=1; i<=n; i++) {
              cost = x.charAt(i-1)==t_j ? 0 : 1;
              // minimum of cell to the left+1, to the top+1, diagonally left and up +cost                
              d[i] = Math.min(Math.min(d[i-1]+1, p[i]+1),  p[i-1]+cost);  
           }

           // copy current distance counts to 'previous row' distance counts
           _d = p;
           p = d;
           d = _d;
        } 
              
        // our last action in the above loop was to switch d and p, so p now 
        // actually has the most recent cost counts
        return p[n];
    }

    static Tree.Body getClassOrInterfaceBody(Tree.Declaration decNode) {
        if (decNode instanceof Tree.ClassDefinition) {
            return ((Tree.ClassDefinition) decNode).getClassBody();
        }
        else if (decNode instanceof Tree.InterfaceDefinition){
            return ((Tree.InterfaceDefinition) decNode).getInterfaceBody();
        }
        else if (decNode instanceof Tree.ObjectDefinition){
            return ((Tree.ObjectDefinition) decNode).getClassBody();
        }
        else {
            return null;
        }
    }

    static Tree.CompilationUnit getRootNode(PhasedUnit unit) {
        IEditorPart ce = getCurrentEditor();
        if (ce instanceof CeylonEditor) {
            CeylonParseController cpc = ((CeylonEditor) ce).getParseController();
            if (cpc!=null) {
                Tree.CompilationUnit rn = cpc.getRootNode();
                if (rn!=null) {
                    Unit u = rn.getUnit();
                    if (u.equals(unit.getUnit())) {
                        return rn;
                    }
                }
            }
        }       
        return unit.getCompilationUnit();
    }

    static StyledString styleProposal(String name) {
        StyledString result = new StyledString();
        StringTokenizer tokens = new StringTokenizer(name, "'", false);
        result.append(tokens.nextToken());
        while (tokens.hasMoreTokens()) {
            result.append('\'');
            CompletionUtil.styleProposal(result, tokens.nextToken());
            result.append('\'');
            if (tokens.hasMoreTokens()) {
                result.append(tokens.nextToken());
            }
        }
        return result;
    }

    static String asIntersectionTypeString(List<ProducedType> types) {
        StringBuffer missingSatisfiedTypesText = new StringBuffer();
        for( ProducedType missingSatisfiedType: types ) {
            if( missingSatisfiedTypesText.length() != 0 ) {
                missingSatisfiedTypesText.append(" & ");
            }
            missingSatisfiedTypesText.append(missingSatisfiedType.getProducedTypeName());   
        }
        return missingSatisfiedTypesText.toString();
    }

	static String defaultValue(Unit unit, ProducedType t) {
	    if (t==null) {
	        return "nothing";
	    }
	    String tn = t.getProducedTypeQualifiedName();
	    if (tn.equals("ceylon.language::Boolean")) {
	        return "false";
	    }
	    else if (tn.equals("ceylon.language::Integer")) {
	        return "0";
	    }
	    else if (tn.equals("ceylon.language::Float")) {
	        return "0.0";
	    }
	    else if (unit.isOptionalType(t)) {
	        return "null";
	    }
	    else if (tn.equals("ceylon.language::String")) {
	        return "\"\"";
	    }
	    else {
	        return "nothing";
	    }
	}
    
}

@@ -397,16 +397,85 @@
 edType;%0A
+import com.redhat.ceylon.compiler.typechecker.model.TypeDeclaration;%0A
 import c
@@ -4491,99 +4491,167 @@
     
-String tn = t.getProducedTypeQualifiedName();%0A%09    if (tn.equals(%22ceylon.language::Boolean%22
+TypeDeclaration tn = t.getDeclaration();%0A%09    if (unit.isOptionalType(t)) %7B%0A%09        return %22null%22;%0A%09    %7D%0A%09    else if (tn.equals(unit.getBooleanDeclaration()
 )) %7B
@@ -4711,34 +4711,36 @@
 als(
-%22ceylon.language::Integer%22
+unit.getIntegerDeclaration()
 )) %7B
@@ -4796,32 +4796,34 @@
 als(
-%22ceylon.language::Float%22
+unit.getFloatDeclaration()
 )) %7B
@@ -4867,37 +4867,53 @@
 lse if (
-unit.isOptionalType(t
+tn.equals(unit.getStringDeclaration()
 )) %7B%0A%09  
@@ -4918,36 +4918,36 @@
         return %22
-null
+%5C%22%5C%22
 %22;%0A%09    %7D%0A%09    e
@@ -4958,71 +4958,206 @@
 if (
-tn.equals(%22ceylon.language::String%22)) %7B%0A%09        return %22%5C%22%5C%22%22;
+unit.getEmptyDeclaration().getType()%0A%09    %09%09.isSubtypeOf(t)) %7B%0A%09    %09if (t.getSupertype(unit.getSequentialDeclaration())==null) %7B%0A%09    %09%09return %22%7B%7D%22;%0A%09    %09%7D%0A%09    %09else %7B%0A%09    %09%09return %22%5B%5D%22;%0A%09    %09%7D
 %0A%09  

improve default values in generated code