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

import static com.redhat.ceylon.eclipse.code.style.CeylonFormatterConstants.*;

import java.util.Observable;
import java.util.Observer;

import org.eclipse.core.runtime.Assert;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;

public class FormatterTabIndent extends FormatterTabPage {

    private final String PREVIEW = 
            "import ceylon.collection { MutableList }\n\n\n"
            + "shared class Example() {"
            + "value test => 0;"
            + "}";

    private CeylonPreview ceylonPreview;

    private String oldTabChar;

    public FormatterTabIndent(FormatterModifyProfileDialog modifyDialog,
            FormatterPreferences workingValues) {
        super(modifyDialog, workingValues);
    }

    @Override
    protected void doCreatePreferences(Composite composite, int numColumns) {

        final Group generalGroup = createGroup(numColumns, composite,
                "Indent Mode");

        final String[] indentModeValues = new String[] {
                FORMATTER_indentMode_Spaces.toLowerCase(),
                FORMATTER_indentMode_Tabs.toLowerCase(),
                FORMATTER_indentMode_Mixed.toLowerCase() };
        final String[] indentModeLabels = new String[] {
                FORMATTER_indentMode_Spaces, FORMATTER_indentMode_Tabs,
                FORMATTER_indentMode_Mixed };
        final ComboPreference indentMode = createComboPref(generalGroup,
                numColumns, "Indent Mode", FORMATTER_indentMode,
                indentModeValues, indentModeLabels);

        final NumberPreference indentSpacesSize = createNumberPref(
                generalGroup, numColumns, "Indent Mode Spaces Size",
                FORMATTER_indentMode_Spaces_Size, 0, 32);

        final NumberPreference indentTabsSize = createNumberPref(generalGroup,
                numColumns, "Indent Mode Tabs Size",
                FORMATTER_indentMode_Tabs_Size, 0, 32);

        updateTabPreferences(this.workingValues.get(FORMATTER_indentMode),
                indentSpacesSize, indentTabsSize);

        indentMode.addObserver(new Observer() {
            public void update(Observable o, Object arg) {
                updateTabPreferences((String) arg, indentSpacesSize,
                        indentTabsSize);
            }
        });

        // group ended
        final Group otherGroup = createGroup(numColumns, composite,
                "Other Indent Options");
        createCheckboxPref(otherGroup, numColumns, "Indent Blank Lines",
                FORMATTER_indent_Blank_Lines, FALSE_TRUE);
        createNumberPref(otherGroup, 3, "Indent before type info",
                FORMATTER_indent_Before_Type_Info, 0, 32);
        createComboPref(otherGroup, 3, "Indent after specifier expression start", 
                FORMATTER_indent_After_Specifier_Expression_Start,
                new String[] {"stack", "addindentbefore"}, // not camel case
                new String[] {"Stack", "Add Indent Before"});
    }

    @Override
    public void initializePage() {
        ceylonPreview.setPreviewText(PREVIEW);
    }

    @Override
    protected CeylonPreview doCreateCeylonPreview(Composite parent) {
        ceylonPreview = new CeylonPreview(this.workingValues, parent);
        return ceylonPreview;
    }

    @Override
    protected void doUpdatePreview() {
        super.doUpdatePreview();
        ceylonPreview.update();
    }

    private void updateTabPreferences(String tabPolicy,
            NumberPreference indentSpacesSize, NumberPreference indentTabsSize) {

        if (FORMATTER_indentMode_Spaces.equalsIgnoreCase(tabPolicy)) {
            indentSpacesSize.setEnabled(true);
            indentTabsSize.setEnabled(false);
        } else if (FORMATTER_indentMode_Tabs.equalsIgnoreCase(tabPolicy)) {
            indentSpacesSize.setEnabled(false);
            indentTabsSize.setEnabled(true);
        } else if (FORMATTER_indentMode_Mixed.equalsIgnoreCase(tabPolicy)) {
            indentSpacesSize.setEnabled(true);
            indentTabsSize.setEnabled(true);
        } else {
            Assert.isTrue(false);
        }
        oldTabChar = tabPolicy;
    }
}

@@ -394,69 +394,650 @@
 VIEW
- = %0A            %22import ceylon.collection %7B MutableList %7D%5Cn%5Cn
+%0A            = %22shared class AccessCountingIterable%3CElement,Absent%3E(Iterable%3CElement,Absent%3E wrapped)%5Cn%22%0A            + %22        extends Object()%5Cn%22%0A            + %22        satisfies Iterable%3CElement,Absent%3E%5Cn%22%0A            + %22        given Absent satisfies Null %7B%5Cn%22%0A            + %22    %5Cn%22%0A            + %22    variable Integer accessCounter = 0;%5Cn%22%0A            + %22    shared Integer accessCount =%3E accessCounter;%5Cn%22%0A            + %22    %5Cn%22%0A            + %22    shared actual Iterator%3CElement%3E iterator() %7B%5Cn%22%0A            + %22        accessCounter++;%5Cn%22%0A            + %22        return wrapped.iterator();%5Cn%22%0A            + %22    %7D%5Cn%22%0A            + %22    
 %5Cn%22%0A
@@ -1055,32 +1055,123 @@
  + %22
+    
 shared 
-class Example(
+actual Boolean equals(Object that) %7B%5Cn%22%0A            + %22        if (is Iterable%3CElement,Absent%3E that
 ) %7B
+%5Cn
 %22%0A  
@@ -1187,24 +1187,397 @@
  + %22
-value test =%3E 0;
+            return wrapped == that;%5Cn%22%0A            + %22        %7D else %7B%5Cn%22%0A            + %22            return false;%5Cn%22%0A            + %22        %7D%5Cn%22%0A            + %22    %7D%5Cn%22%0A            + %22    %5Cn%22%0A            + %22    shared actual Integer hash =%3E%5Cn%22%0A            + %22            sum %7B%5Cn%22%0A            + %22        accessCounter.hash,%5Cn%22%0A            + %22        wrapped.hash%5Cn%22%0A            + %22    %7D;%5Cn
 %22%0A  
@@ -1590,16 +1590,18 @@
     + %22%7D
+%5Cn
 %22;%0A%0A    

Update preview code of formatter config indent tab