package com.boothen.jsonedit.model;

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.Token;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.ITokenScanner;

import com.boothen.jsonedit.antlr.JSONLexer;
import com.boothen.jsonedit.core.JsonLog;

/**
 * Use the ANTLR lexer to extract tokens from a document.
 */
public class AntlrTokenScanner implements ITokenScanner {

    private int offset;
    private Lexer lexer;
    private CommonToken previous;
    private CommonToken current;
    private TokenMapping tokenMapping;

    /**
     * Uses the given JSONLexer
     * @param lexer the lexer to use
     */
    public AntlrTokenScanner(Lexer lexer) {
        this.lexer = lexer;
        this.tokenMapping = new TokenMapping() {
            @Override
            public Object apply(int currentTokenType, int previousTokenType) {
                return null;
            }
        };
    }

    /**
     * @param lexer the lexer to use
     * @param mapping the mapping from token type to result
     */
    public AntlrTokenScanner(Lexer lexer, TokenMapping mapping) {
        this.lexer = lexer;
        this.tokenMapping = mapping;
    }

    @Override
    public void setRange(IDocument document, int offset, int length) {
        this.offset = offset;
        try {
            String text = document.get(offset, length);
            lexer.setInputStream(new ANTLRInputStream(text));
        } catch (BadLocationException e) {
            JsonLog.logError("Attempting to access a non-existing position", e);
        }
    }

    @Override
    public IToken nextToken() {
        Token token = lexer.nextToken();

        previous = current;

        if (!(token instanceof CommonToken)) {
            current = null;
            return org.eclipse.jface.text.rules.Token.UNDEFINED;
        }

        current = (CommonToken) token;

        if (token.getType() == Token.EOF) {
            return org.eclipse.jface.text.rules.Token.EOF;
        }

        if (token.getType() == JSONLexer.WS) {
            return org.eclipse.jface.text.rules.Token.WHITESPACE;
        }

        int currentType = current.getType();
        int previousType = previous != null ? previous.getType() : Token.EOF;
        Object data = tokenMapping.apply(currentType, previousType);

        return new org.eclipse.jface.text.rules.Token(data);
    }

    @Override
    public int getTokenOffset() {
        return offset + current.getStartIndex();
    }

    @Override
    public int getTokenLength() {
        return current.getStopIndex() - current.getStartIndex() + 1;
    }
}

@@ -1844,37 +1844,8 @@
 );%0A%0A
-        previous = current;%0A%0A
     
@@ -1903,87 +1903,354 @@
     
-current = null;%0A            return org.eclipse.jface.text.rules.Token.UNDEFINED
+// this doesn't seem to happen in practice%0A            // if it ever does: don't update current/previous, just bail out%0A            return org.eclipse.jface.text.rules.Token.UNDEFINED;%0A        %7D%0A%0A        // update only if token is relevant (no WS)%0A        if (current == null %7C%7C current.getType() != JSONLexer.WS) %7B%0A            previous = current
 ;%0A  

Fix text presentation reconciler for text values