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 FortranSPFTokenMaker 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 '!':
                    case '*':
                    case 'C':
                    case 'c':
                    case 'D':
                    case 'd':
                        //комментарий. анализ закончен
                        provider.setType(Token.COMMENT_EOL);
                        provider.stop();
                        break;
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                        //метка.
                        provider.setType(Token.MARKUP_TAG_NAME);
                        provider.label_flag = true;
                        break;
                    case ' ':
                    case '\r':
                        //пробелы
                        provider.setType(Token.WHITESPACE);
                        break;
                    case '\t':
                        provider.SkipWrap();
                        break;
                    default:
                        //все остальное
                        provider.setType(Token.IDENTIFIER);
                        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;
                            case '!':
                                SaveCurrent(provider);
                                provider.start();
                                //комментарий. анализ закончен
                                provider.setType(Token.COMMENT_EOL);
                                provider.stop();
                                break;
                            case ' ':
                                SaveCurrent(provider);
                                provider.start();
                                provider.setType(Token.WHITESPACE);
                                break;
                            case '\t':
                                SaveCurrent(provider);
                                provider.start();
                                provider.SkipWrap();
                                break;
                            default:
                                //это не метка. меняем тип.
                                provider.setType(Token.IDENTIFIER);
                                break;
                        }
                        break;
                    case Token.WHITESPACE:
                        switch (provider.c) {
                            case ' ':
                            case '\r':
                                break;
                            case '\t':
                                provider.SkipWrap();
                                break;
                            case '0':
                            case '1':
                            case '2':
                            case '3':
                            case '4':
                            case '5':
                            case '6':
                            case '7':
                            case '8':
                            case '9':
                                SaveCurrent(provider);
                                provider.start();
                                //если метка уже бывала. значит больше меток нет
                                if (provider.label_flag) {
                                    provider.setType(Token.IDENTIFIER);
                                } else {
                                    provider.setType(Token.MARKUP_TAG_NAME);
                                    provider.label_flag = true;
                                }
                                break;
                            case '!':
                                SaveCurrent(provider);
                                provider.start();
                                //комментарий. анализ закончен
                                provider.setType(Token.COMMENT_EOL);
                                provider.stop();
                                break;
                            default:
                                SaveCurrent(provider);
                                provider.start();
                                provider.setType(Token.IDENTIFIER);
                                break;
                        }
                        break;
                    case Token.IDENTIFIER:
                        switch (provider.c) {
                            case '!':
                                SaveCurrent(provider);
                                provider.start();
                                //комментарий. анализ закончен
                                provider.setType(Token.COMMENT_EOL);
                                provider.stop();
                                break;
                            case '\t':
                                SaveCurrent(provider);
                                provider.start();
                                provider.SkipWrap();
                                break;
                            default:
                                //уже неважно что это.
                                break;
                        }
                        break;
                }
                break;
            case 5:
                switch (provider.c) {
                    case ' ':
                    case '\r':
                    case '\t':
                        switch (provider.currentTokenType) {
                            case Token.WHITESPACE:
                                //это пробел, и нам норм.
                                break;
                            default:
                                SaveCurrent(provider);
                                provider.start();
                                provider.setType(Token.WHITESPACE);
                                break;
                        }
                        //это пробелы. переноса нет. убираем сохранение типа
                        provider.startTokenType = Token.NULL;
                        break;
                    default:
                        //это - позиция переноса. сохраняем все что было до нее.
                        SaveCurrent(provider);
                        provider.start();
                        provider.setType(Token.OPERATOR);
                        SaveCurrent_(provider); //сохраняем его как одиночный оператор.
                        provider.setType(provider.startTokenType);
                        //берем унаследование от предыдущей строки
                        break;
                }
                break;
            //</editor-fold>
            //<editor-fold desc="Основной текст строки">
            default:
                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:
                        provider.checkWrap();
                        SaveCurrent(provider);
                        provider.start();
                        provider.detectType();
                        break;
                    case Token.LITERAL_NUMBER_DECIMAL_INT:
                        provider.checkWrap();
                        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:
                        provider.checkWrap();
                        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:
                        provider.checkWrap();
                        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:
                        provider.checkWrap();
                        if (!
                                (RSyntaxUtilities.isLetter(provider.c) ||
                                        RSyntaxUtilities.isDigit(provider.c) ||
                                        (provider.c == '_') ||
                                        (provider.c == '.')
                                )) {
                            SaveCurrent(provider);
                            provider.start();
                            provider.detectType();
                        }
                        break;
                }
                //</editor-fold>
        }
    }
    @Override
    public void performFinish(TokenProvider provider) {
        switch (provider.currentTokenType) {
            case Token.NULL:
                addNullToken();
                break;
            //   case Token.IDENTIFIER:
            case Token.LITERAL_NUMBER_DECIMAL_INT:
            case Token.LITERAL_NUMBER_FLOAT:
            case Token.RESERVED_WORD_2:
                SaveCurrent(provider);
                break;
            default:
                SaveCurrent(provider);
                addNullToken();
                break;
        }
    }
    //_VisualDVM.
}
