package _VisualDVM.Visual.Syntax;
import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
import org.fife.ui.rsyntaxtextarea.Token;
import org.fife.ui.rsyntaxtextarea.TokenMap;

import javax.swing.text.Segment;
public class FreeFortranSPFTokenMaker extends ProvidedTokenMaker {
    @Override
    public TokenMap getWordsToHighlight() {
        TokenMap tokenMap = new TokenMap(true);
        fillTokenMap(tokenMap, Token.RESERVED_WORD,
                "FORALL", "ENDFORALL", "PUBLIC", "PRIVATE", "ADMIT", "ASSIGNMENT", "CALL", "COMMON",
                "CYCLE", "DIMENSION", "END", "ENDDO", "ENTRY", "FORMAT", "IMPLICIT", "INTENT", "MAP",
                "OPEN", "POINTER", "PROGRAM", "RECURSIVE", "STOP", "THEN", "WHILE", "ALLOCATABLE",
                "ATEND", "CASE", "COMPLEX", "DATA", "DO", "ENDFILE", "EQUIVALENCE", "FUNCTION",
                "INCLUDE", "INTERFACE", "MODULE", "OPTIONAL", "PRINT", "PURE", "READ", "RETURN",
                "STRUCTURE", "TYPE", "WRITE", "ALLOCATE", "BACKSPACE", "CHARACTER", "CONTAINS",
                "DEALLOCATE", "DOUBLE", "ENDIF", "EXIT", "GOTO", "INQUIRE", "INTRINSIC", "NAMELIST",
                "PARAMETER", "PRECISION", "REAL", "REWIND", "SUBROUTINE", "UNION", "ASSIGN", "BLOCKDATA",
                "CLOSE", "CONTINUE", "DEFAULT", "ELSE", "ELSEIF", "ENDSELECT", "EXTERNAL", "IF", "INTEGER",
                "LOGICAL", "NONE", "PAUSE", "PROCEDURE", "RECORD", "SAVE", "TARGET", "USE", "SELECT", "BLOCK", "WHERE"
        );
        fillTokenMap(tokenMap, Token.OPERATOR,
                ".EQ.",
                ".NE.", ".LT.", ".LE.",
                ".GT.", ".GE.",
                ".NOT.", ".AND.", ".EQV.", ".NEQV.",
                ".OR.", ".TRUE.", ".FALSE."
        );
        return tokenMap;
    }
    @Override
    public void addToken(Segment segment, int start, int end, int tokenType, int startOffset) {
        int finalTokenType = tokenType;
        switch (tokenType) {
            case Token.COMMENT_EOL:
                if (segment.count >= 5) {
                    switch (segment.subSequence(1, 5).toString().toUpperCase()) {
                        case "$SPF":
                            finalTokenType = Token.COMMENT_DOCUMENTATION;
                            break;
                        case "DVM$":
                            finalTokenType = Token.COMMENT_MARKUP;
                            break;
                        case "$OMP":
                            finalTokenType = Token.COMMENT_KEYWORD;
                            break;
                        default:
                            break;
                    }
                }
                break;
            case Token.IDENTIFIER:
                int value = wordsToHighlight.get(segment, start, end);
                //ключевое слово
                if (value != -1) {
                    finalTokenType = value;
                }
                break;
            default:
                break;
        }
        super.addToken(segment, start, end, finalTokenType, startOffset);
    }
    @Override
    public void Body(TokenProvider provider) {
        /*
        switch (provider.position) {
            //<editor-fold desc="Зона переноса">
            case 0:
                //тут всегда currentTokenType=NULL. переносимый известеи в startTokenType
                provider.start();
                switch (provider.c) {
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                        //метка. может появиться только с 0-4 позиций. остальной анализ. аналогичен обычному.
                        provider.setType(Token.MARKUP_TAG_NAME);
                        provider.label_flag = true;
                        break;
                    default:
                        //все остальное
                        provider.detectType();
                        break;
                }
                break;
            case 1:
            case 2:
            case 3:
            case 4:
                switch (provider.currentTokenType) {
                    case Token.MARKUP_TAG_NAME:
                        switch (provider.c) {
                            case '0':
                            case '1':
                            case '2':
                            case '3':
                            case '4':
                            case '5':
                            case '6':
                            case '7':
                            case '8':
                            case '9':
                            case '\r':
                                break;
                            default:
                                SaveCurrent(provider);
                                provider.start();
                                provider.detectType();
                                break;
                        }
                        break;
                    default:
                        DefaultLineParse(provider);
                        break;
                }
                break;
            case 5:
                switch (provider.c) {
                    case '&':
                        //это - позиция переноса. сохраняем все что было до нее.
                        SaveCurrent(provider);
                        provider.start();
                        provider.setType(Token.OPERATOR);
                        SaveCurrent_(provider); //сохраняем его как одиночный оператор.
                        provider.setType(provider.startTokenType);
                        //берем унаследование от предыдущей строки
                        break;
                    default:
                        if (provider.currentTokenType==Token.MARKUP_TAG_NAME){
                            //метка на этом символе уже обязана закончиться.
                            SaveCurrent(provider);
                            provider.start();
                            provider.detectType();
                        }else
                        DefaultLineParse(provider);
                        break;
                }
                break;
            //</editor-fold>
            //<editor-fold desc="Основной текст строки">
            default:
                DefaultLineParse(provider);
                //</editor-fold>
        }
         */
        DefaultLineParse(provider);
    }
    public void DefaultLineParse(TokenProvider provider) {
        switch (provider.currentTokenType) {
            case Token.NULL:
                provider.start();
                provider.detectType();
                break;
            case Token.WHITESPACE:
                switch (provider.c) {
                    case ' ':
                    case '\t':
                    case '\r':
                        break;
                    default:
                        SaveCurrent(provider);
                        provider.start();
                        provider.detectType();
                        break;
                }
                break;
            case Token.OPERATOR:
                SaveCurrent(provider);
                provider.start();
                provider.detectType();
                break;
            case Token.LITERAL_NUMBER_DECIMAL_INT:
                switch (provider.c) {
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                    case '\r':
                        break;
                    case '.':
                    case 'e':
                    case 'E':
                    case 'd':
                    case 'D':
                        provider.setType(Token.LITERAL_NUMBER_FLOAT);
                        break;
                    default:
                        SaveCurrent(provider);
                        provider.start();
                        provider.detectType();
                        break;
                }
                break;
            case Token.LITERAL_NUMBER_FLOAT:
                switch (provider.c) {
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                    case '\r':
                        break;
                    case 'e':
                    case 'E':
                    case 'd':
                    case 'D':
                        SaveCurrent_(provider);
                        provider.setType(Token.NULL);
                        break;
                    default:
                        SaveCurrent(provider);
                        provider.start();
                        provider.detectType();
                        break;
                }
                break;
            case Token.RESERVED_WORD_2:
                switch (provider.c) {
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                        //подозрения подтвердились. это дробь.
                        provider.setType(Token.LITERAL_NUMBER_FLOAT);
                        break;
                    case '\r':
                        break;
                    default:
                        provider.setType(Token.IDENTIFIER);
                        break;
                }
                break;
            case Token.LITERAL_CHAR:
                switch (provider.c) {
                    case '\'':
                        SaveCurrent_(provider);
                        provider.setType(Token.NULL);
                        break;
                    default:
                        break;
                }
                break;
            case Token.LITERAL_STRING_DOUBLE_QUOTE:
                switch (provider.c) {
                    case '"':
                        SaveCurrent_(provider);
                        provider.setType(Token.NULL);
                        break;
                    default:
                        break;
                }
                break;
            case Token.IDENTIFIER:
                if (!
                        (RSyntaxUtilities.isLetter(provider.c) ||
                                RSyntaxUtilities.isDigit(provider.c) ||
                                (provider.c == '_') ||
                                (provider.c == '.')
                        )) {
                    SaveCurrent(provider);
                    provider.start();
                    provider.detectType();
                }
                break;
        }
    }
    @Override
    public void performFinish(TokenProvider provider) {
        SaveCurrent(provider);
        addNullToken();
    }
}
