package org.elmlang.intellijplugin.manualParsing;

import com.intellij.lang.ITokenTypeRemapper;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;

import java.util.*;

import org.elmlang.intellijplugin.psi.ElmTypes;

public class IndentationTokenTypeRemapper implements ITokenTypeRemapper {
    private static final Map<Long, IndentationTokenTypeRemapper> instances =
            Collections.synchronizedMap(new HashMap<Long, IndentationTokenTypeRemapper>());

    private Stack<Integer> indentations;

    private IndentationTokenTypeRemapper() {
        this.indentations = new Stack<Integer>();
    }

    public static <T> T use(Callback<T> callback, T input) {
        IndentationTokenTypeRemapper instance = getInstance();
        Stack<Integer> indentationsBackup = instance.indentations;
        instance.indentations = (Stack<Integer>)instance.indentations.clone();
        input = callback.call(instance, input);
        instance.indentations = indentationsBackup;
        return input;
    }

    public void pushIndentation(int indentation) {
        if (indentation > 0) {
            this.indentations.push(indentation);
        }
    }

    @Override
    public IElementType filter(IElementType type, int start, int end, CharSequence text) {
        if (!this.indentations.empty() && TokenType.WHITE_SPACE.equals(type)) {
            int i = IndentationHelper.getIndentation(text, start, end);
            if (i > 0) {
                if (this.indentations.search(i) > 0) {
                    return ElmTypes.SEPARATION_BY_INDENTATION;
                }
            }
        }
        return type;
    }

    private static IndentationTokenTypeRemapper getInstance() {
        long key = Thread.currentThread().getId();
        if (!instances.containsKey(key)) {
            instances.put(key, new IndentationTokenTypeRemapper());
        }
        return instances.get(key);
    }

    // T is a hack for lack of non-final closures in Java
    public interface Callback<T> {
        T call(IndentationTokenTypeRemapper instance, T input);
    }
}

@@ -586,41 +586,13 @@
 his.
-indentations = new Stack%3CInteger%3E
+reset
 ();%0A
@@ -1590,29 +1590,302 @@
    %7D
-%0A        return type;
+ else if (ElmTypes.FRESH_LINE.equals(type) %7C%7C end == text.length()) %7B%0A            this.reset();%0A        %7D%0A        return type;%0A    %7D%0A%0A    public void reset() %7B%0A        if (this.indentations == null %7C%7C !this.indentations.empty()) %7B%0A            this.indentations = new Stack%3CInteger%3E();%0A        %7D
 %0A   

Fix of a bug in `IndentationTokenTypeRemapper`.