package _VisualDVM.Validators;
import Common.CommonConstants;
import Common.Utils.Utils_;

import java.io.InputStreamReader;
import java.util.Vector;
public class ShellParser {
    public static ShellParserState state;
    public static StringBuilder lineBuilder;
    public static String userName;
    public static StringBuilder invitationBuilder;
    public static char c;
    public static char[] buffer = new char[1];
    public static Vector<String> lines = new Vector<>();
    //  public static boolean bracketOpened = false;
    public static boolean return_active = false;
    public static boolean isCommandSymbol() {
        int code = c;
        return code <= 31 || c == 127;
    }
    public static void ResetLine() {
        invitationBuilder = new StringBuilder();
        lineBuilder = new StringBuilder();
        //   bracketOpened = false;
        state = ShellParserState.NewLine;
        return_active = false;
    }
    public static boolean isNameCharacter() {
        //латиница, цифры,подчеркивания. и -
        return String.valueOf(c).matches("[\\w\\-]*") || c == '?';
    }
    public static boolean isRBracket() {
        return c == '(' || c == ')';
    }
    //false наоборот означать что конец строки ЕСТЬ.
    public static boolean checkEndLine() {
        if (return_active) {
            switch (c) {
                case '\n':
                    //ложная тревога. возврат каретки ни на что не влияет.
                    lines.add(lineBuilder.toString());
                    ResetLine();
                    return false;
                case '\r':
                    return false;
                default:
                    //тут был возврат. надо игнорить символ, ибо он уже прочитан.
                    return_active = false;
                    return false;
            }
        } else {
            switch (c) {
                case '\r':
                    return_active = true;
                    return false;
                case '\n':
                    lines.add(lineBuilder.toString());
                    ResetLine();
                    return false;
            }
        }
        return true;
    }
    /*
    public static void NewLine() {
        if (c == '[') {//приглашение со скобками.
         //   bracketOpened = true;
            invitationBuilder.append(c);
            state = ShellParserState.UserName;
        } else {
            if (isNameCharacter()) {
                invitationBuilder.append(c);
                state = ShellParserState.UserName;
            } else
                //не буква и не скобка. значит в этой строке приглашения нет.
                state = ShellParserState.Skip;
        }
    }
     */
    public static void NewLine() {
        if (c == '@') { //собака, признак приглашения.
            String test = invitationBuilder.toString();
            test = test.toLowerCase();
            state = test.endsWith(userName.toLowerCase()) ? ShellParserState.MachineName : ShellParserState.Skip;
            invitationBuilder.append(c);
        } else {
            invitationBuilder.append(c);
        }
/*
        if (c == '[') {//приглашение со скобками.
            //   bracketOpened = true;
            invitationBuilder.append(c);
            state = ShellParserState.UserName;
        } else {
            if (isNameCharacter()) {
                invitationBuilder.append(c);
                state = ShellParserState.UserName;
            } else
                //не буква и не скобка. значит в этой строке приглашения нет.
                state = ShellParserState.Skip;
        }
 */
    }
    /*
        public static void UserName() {
            if (c == '@') { //проверить. а тот ли юзернейм.
                String test = invitationBuilder.toString();
               // if (bracketOpened) test = test.substring(1);
                test = test.toLowerCase();
                state = test.endsWith(userName.toLowerCase()) ? ShellParserState.MachineName : ShellParserState.Skip;
                invitationBuilder.append(c);
            } else if (isNameCharacter() || (c == '['))
                invitationBuilder.append(c);
            else
                state = ShellParserState.Skip;
        }
     */
    public static void MachineName() {
        switch (c) {
            case ' ':
            case ':':
                state = ShellParserState.Path;
                invitationBuilder.append(c);
                break;
            default:
                if (isNameCharacter())
                    invitationBuilder.append(c);
                else state = ShellParserState.Skip;
                break;
        }
    }
    public static void Path() {
        switch (c) {
            case '$':
            case '#':
            case '>':
                invitationBuilder.append(c);
                state = ShellParserState.Space; //приглашение завершено. осталось прочитать пробел после него
                break;
                /*
            case ']':
                if (bracketOpened) {
                    invitationBuilder.append(c);
                    bracketOpened = false;
                } else {
                    //  UI.Info("KEK");
                    state = ShellParserState.Skip; //непарная скобка, все, привет
                }
                break;
                 */
            default:
                invitationBuilder.append(c);
                break;
        }
    }
    public static void Space() {
        if (c == ' ') {
            state = ShellParserState.End;
            invitationBuilder.append(c);
        } else {
            state = ShellParserState.Skip;
        }
    }
    public static void setUserName(String userName_in) {
        userName = userName_in;
    }
    public static void printChar() {
        if (c != CommonConstants.boop) {
            int code = c;
            if ((!return_active) || (c == '\n')) {
                System.out.print(c == '\r' ? ("\\r") :
                        (c == '\n' ? "\\n\n" : c));
                if (isCommandSymbol())
                    System.out.print(Utils_.RBrackets(code));
            }
        }
    }
    public static void ReadInvitation(InputStreamReader fromServer) {
        lines.clear();
        ResetLine();
        do {
            try {
                if (fromServer.read(buffer) >= 0) {
                    c = buffer[0];
                    printChar();
                    // if (!isCommandSymbol()) {
                    if (checkEndLine() && (!isCommandSymbol())) {
                        lineBuilder.append(c);
                        switch (state) {
                            case NewLine:
                                NewLine();
                                break;
                            //  case UserName:
                            //      UserName();
                            //      break;
                            case MachineName:
                                MachineName();
                                break;
                            case Path:
                                Path();
                                break;
                            case Space:
                                Space();
                                break;
                            case Skip:
                                break;
                        }
                    }
                } else
                    state = ShellParserState.End;
            } catch (Exception ex) {
                Utils_.MainLog.PrintException(ex);
                state = ShellParserState.End;
            }
        } while (!state.equals(ShellParserState.End));
    }
    public static String ReadLine(InputStreamReader fromServer) {
        StringBuilder res = new StringBuilder();
        state = ShellParserState.NewLine;
        do {
            try {
                if (fromServer.read(buffer) >= 0) {
                    c = buffer[0];
                    printChar();
                    switch (c) {
                        case '\r':
                            break;
                        case '\n':
                            state = ShellParserState.End;
                            break;
                        default:
                            res.append(c);
                            break;
                    }
                } else
                    state = ShellParserState.End;
            } catch (Exception ex) {
                Utils_.MainLog.PrintException(ex);
                state = ShellParserState.End;
            }
        } while (!state.equals(ShellParserState.End));
        return res.toString();
    }
    public static void ReadCommand(String command, InputStreamReader fromServer) {
        StringBuilder res = new StringBuilder();
        do {
            try {
                if (fromServer.read(buffer) >= 0) {
                    c = buffer[0];
                    printChar();
                    switch (c) {
                        case '\r':
                            break;
                        case '\n':
                            break;
                        default:
                            res.append(c);
                            break;
                    }
                } else
                    return;
            } catch (Exception ex) {
                Utils_.MainLog.PrintException(ex);
                return;
            }
        } while (!res.toString().contains(command));
    }
    public static String getCommandResult(InputStreamReader fromServer) {
        //если последняя строка ответа - кончается на приглашение, то ничего не делаем.
        //если нет. значит ответ кончается на перевод строки. или пуст.
        // нужно прочитать еще одно приглашение.
        String last_line = "";
        String res = "";
        boolean no_extra_read = false;
        if (lines.size() > 0) {
            last_line = lines.lastElement();
            if (no_extra_read = last_line.endsWith(invitationBuilder.toString())) {
                lines.remove(lines.size() - 1);
                //больше ничего не читаем. но. обрезаем ее конец.
                last_line = last_line.substring(0, last_line.length() - invitationBuilder.length());
                lines.add(last_line);
            }
            res = String.join("\n", lines);
        }
        if (!no_extra_read) {
            ReadInvitation(fromServer);
        }
        return res;
    }
}
