package _VisualDVM.Visual.Menus;
import Common.Utils.Utils_;
import Common.Visual.Menus.TextEditorMenu;
import Common.Visual.Menus.VisualiserMenuItem;
import _VisualDVM.Global;
import _VisualDVM.Passes.PassCode;
import _VisualDVM.ProjectData.Files.DBProjectFile;
import _VisualDVM.ProjectData.Files.UI.Editor.SPFEditor;
import _VisualDVM.ProjectData.SapforData.Functions.FuncCall;
import _VisualDVM.ProjectData.SapforData.Functions.FuncInfo;
import _VisualDVM.ProjectData.SapforData.Functions.FunctionType;
import _VisualDVM.ProjectData.SapforData.Loops.Loop;
import _VisualDVM.Utils;
import _VisualDVM.Visual.Editor.CaretInfo;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MainEditorMenu extends TextEditorMenu {
    FuncCall call = null;
    FuncInfo decl = null;
    Loop loop = null;
    DBProjectFile header = null;
    //------------------
    JMenuItem m_comment;
    JMenuItem m_uncomment;
    JMenuItem m_inline;
    JMenuItem m_add_lines_to_region;
    JMenuItem m_remove_lines_from_region;
    JMenuItem m_loop_union;
    JMenuItem m_undo;
    JMenuItem m_gotoFunction;
    JMenuItem m_gotoHeader;
    //-----------------
    public MainEditorMenu(RSyntaxTextArea editor_in) {
        super(editor_in);
        addSeparator();
        m_gotoHeader = new VisualiserMenuItem("Перейти к заголовочному файлу", "/icons/Transformations/SPF_InsertIncludesPass.png");
        m_gotoHeader.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Global.mainModule.getPass(PassCode.OpenCurrentFile).Do(header);
            }
        });
        add(m_gotoHeader);
        addSeparator();
        m_gotoFunction = new VisualiserMenuItem("Перейти к объявлению процедуры", "/icons/versions/currentVersion.png");
        m_gotoFunction.addActionListener(
                new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        decl.Show(true);
                    }
                });
        add(m_gotoFunction);
        m_inline = new VisualiserMenuItem("Подставить вызов процедуры", "/icons/Transformations/SPF_InlineProcedures.png");
        m_inline.addActionListener(
                new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Global.mainModule.getPass(PassCode.SPF_InlineProcedure).Do(call);
                    }
                });
        add(m_inline);
        addSeparator();
        m_loop_union = new VisualiserMenuItem("Объединить цикл со следующим", "/icons/Transformations/SPF_LoopUnion.png");
        m_loop_union.addActionListener(
                new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Global.mainModule.getPass(PassCode.SPF_LoopUnionCurrent).Do();
                    }
                });
        add(m_loop_union);
        m_add_lines_to_region = new VisualiserMenuItem("Добавить строки в область", "/icons/Menu/AddLines.png");
        m_add_lines_to_region.addActionListener(
                new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        try {
                            Global.mainModule.getPass(PassCode.SPF_ChangeSpfIntervals).Do(
                                    ((RSyntaxTextArea) editor).getLineOfOffset(editor.getSelectionStart()) + 1,
                                    ((RSyntaxTextArea) editor).getLineOfOffset(editor.getSelectionEnd()) + 1,
                                    1
                            );
                        } catch (Exception ex) {
                            Utils_.MainLog.PrintException(ex);
                        }
                    }
                });
        add(m_add_lines_to_region);
        m_remove_lines_from_region = new VisualiserMenuItem("Удалить строки из области", "/icons/Menu/RemoveLines.png");
        m_remove_lines_from_region.addActionListener(
                new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        try {
                            Global.mainModule.getPass(PassCode.SPF_ChangeSpfIntervals).Do(
                                    ((RSyntaxTextArea) editor).getLineOfOffset(editor.getSelectionStart()) + 1,
                                    ((RSyntaxTextArea) editor).getLineOfOffset(editor.getSelectionEnd()) + 1,
                                    0
                            );
                        } catch (Exception ex) {
                            Utils_.MainLog.PrintException(ex);
                        }
                    }
                });
        add(m_remove_lines_from_region);
        addSeparator();
        m_comment = new VisualiserMenuItem("Закомментировать блок", "/icons/Editor/Comment.png");
        m_comment.addActionListener(
                new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        String new_ = "";
                        String[] data = selectedText.split("\n");
                        int i = 0;
                        switch (Global.mainModule.getFile().languageName) {
                            case fortran:
                                for (String line : data) {
                                    if (!line.startsWith("!")) {
                                        new_ += "!" + line;
                                    } else new_ += line;
                                    if (i < data.length - 1) new_ += "\n";
                                    ++i;
                                }
                                break;
                            case c:
                            case cpp:
                                for (String line : data) {
                                    if (!line.startsWith("//")) {
                                        new_ += "//" + line;
                                    } else new_ += line;
                                    if (i < data.length - 1) new_ += "\n";
                                    ++i;
                                }
                                break;
                            default:
                                new_ = selectedText;
                                break;
                        }
                        editor.replaceSelection(new_);
                    }
                });
        add(m_comment);
        m_uncomment = new VisualiserMenuItem("Раскомментировать блок", "/icons/Editor/Uncomment.png");
        m_uncomment.addActionListener(
                new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        String new_ = "";
                        String[] data = selectedText.split("\n");
                        int i = 0;
                        switch (Global.mainModule.getFile().languageName) {
                            case fortran:
                                for (String line : data) {
                                    if (line.startsWith("!")) {
                                        new_ += line.substring(1);
                                    } else new_ += line;
                                    if (i < data.length - 1) new_ += "\n";
                                    ++i;
                                }
                                break;
                            case c:
                            case cpp:
                                for (String line : data) {
                                    if (line.startsWith("//")) {
                                        new_ += line.substring(2);
                                    } else new_ += line;
                                    if (i < data.length - 1) new_ += "\n";
                                    ++i;
                                }
                                break;
                            default:
                                new_ = selectedText;
                                break;
                        }
                        //todo. возможно, изменить концепцию на выделенные строки?
                        editor.replaceSelection(new_);
                    }
                });
        add(m_uncomment);
        addSeparator();
        m_undo = new VisualiserMenuItem("Отменить последнюю модификацию", "/icons/Menu/Undo.png");
        m_undo.addActionListener(
                new AbstractAction() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        try {
                            Global.mainModule.getSapfor().UpdateProjectFiles(false);
                        } catch (Exception ex) {
                            Utils_.MainLog.PrintException(ex);
                        }
                    }
                });
        add(m_undo);
    }
    private void checkFunction() {
        call = null;
        decl = null;
        //--
        m_inline.setEnabled(false);
        m_gotoFunction.setEnabled(false);
        //--
        m_inline.setToolTipText("");
        m_gotoFunction.setToolTipText("");
        //--
        if (selectedText == null) {
            m_inline.setText("Невозможно подставить вызов процедуры. Не выделено имя процедуры.");
            m_gotoFunction.setText("Невозможно перейти к объявлению процедуры. Не выделено имя процедуры");
            return;
        }
        if (selectedText.contains("\n")) {
            m_inline.setText("Невозможно подставить вызов процедуры. Выделено несколько строк");
            m_gotoFunction.setText("Невозможно перейти к объявлению процедуры. Выделено несколько строк.");
            return;
        }
        if (!Utils.isFunctionName(selectedText)) {
            String tip = "Имя процедуры может содержать только английские буквы, цифры и подчеркивания, и не может начинаться с цифры.";
            //-
            m_inline.setText("Невозможно подставить вызов процедуры " + Utils_.Brackets(selectedText) +
                    " . Выделено некорректное имя.");
            m_gotoFunction.setText("Невозможно перейти к объявлению процедуры " + Utils_.Brackets(selectedText) +
                    " . Выделено некорректное имя.");
            //-
            m_inline.setToolTipText(tip);
            m_gotoFunction.setToolTipText(tip);
            return;
        }
        if (!Global.mainModule.getPass(PassCode.SPF_GetGraphFunctions).isDone()) {
            m_inline.setText("Невозможно подставить вызов процедуры " + Utils_.Brackets(selectedText) +
                    " . Выполните проход \"Граф процедур \".");
            m_gotoFunction.setText("Невозможно перейти к объявлению процедуры " + Utils_.Brackets(selectedText) +
                    " . Выполните проход \"Граф процедур \"");
            return;
        }
        if (Global.mainModule.getSapfor().isIntrinsic(selectedText)) {
            m_inline.setText("Невозможно подставить вызов процедуры " + Utils_.Brackets(selectedText) +
                    " . Процедура является стандартной.");
            m_gotoFunction.setText("Невозможно перейти к объявлению процедуры " + Utils_.Brackets(selectedText) +
                    " . Процедура является стандартной.");
            return;
        }
        call = Global.mainModule.getFile().find_func_call(selectedText);
        if (call == null) {
            m_inline.setText("Невозможно подставить вызов процедуры " + Utils_.Brackets(selectedText) +
                    " . Вызов не найден в текущей строке.");
            m_gotoFunction.setText("Невозможно перейти к объявлению процедуры " + Utils_.Brackets(selectedText) +
                    " . Объявление процедуры уже находится в текущей строке.");
            return;
        }
        decl = Global.mainModule.getProject().allFunctions.get(call.funcName);
        if (decl.type.equals(FunctionType.NotFound)) {
            m_inline.setText("Невозможно подставить вызов процедуры " + Utils_.Brackets(selectedText) +
                    " . Объявление процедуры не найдено в проекте.");
            m_gotoFunction.setText("Невозможно перейти к объявлению процедуры " + Utils_.Brackets(selectedText) +
                    " . Объявление процедуры не найдено в проекте.");
            return;
        }
        //---
        m_inline.setEnabled(true);
        m_gotoFunction.setEnabled(true);
        m_inline.setText("Подставить вызов процедуры " + Utils_.Brackets(selectedText));
        m_gotoFunction.setText("Перейти к объявлению процедуры " + Utils_.Brackets(selectedText));
        //--
    }
    private void checkHeader() {
        header = null;
        m_gotoHeader.setEnabled(false);
        //--
        CaretInfo caretInfo = ((SPFEditor) editor).getCaretInfo();
        if (caretInfo != null) {
            String header_ = Utils.extractHeaderName(caretInfo.current_line);
            if (header_ == null) {
                m_gotoHeader.setText("Невозможно перейти к заголовочному файлу. В текущей строке не найдено включений.");
                return;
            }
            if (!Global.mainModule.getPass(PassCode.SPF_GetIncludeDependencies).isDone()) {
                m_gotoHeader.setText("Невозможно перейти к заголовочному файлу. Выполните проход \"Поиск зависимостей по включению\"");
                return;
            }
            if (!Global.mainModule.getFile().dependencies.contains(header_)) {
                m_gotoHeader.setText("Невозможно перейти к заголовочному файлу " + Utils_.Brackets(header_) + " . Файл не найден среди включений текущего файла.");
                return;
            }
            header = Global.mainModule.getProject().db.files.get(header_);
            m_gotoHeader.setText("Переход к заголовочному файлу " + Utils_.Brackets(header_));
            m_gotoHeader.setEnabled(true);
        }
    }
    private void checkLoop() {
        loop = null;
        m_loop_union.setEnabled(false);
        if (!Global.mainModule.getPass(PassCode.SPF_GetGraphLoops).isDone()) {
            m_loop_union.setText("Невозможно объединить цикл в текущей строке со следующим. " +
                    "Выполните проход \"Граф циклов\"");
            return;
        }
        loop = Global.mainModule.getFile().find_current_loop();
        if (loop == null) {
            m_loop_union.setText("Невозможно объединить цикл в текущей строке со следующим. Не найдено циклов в текущей строке.");
            return;
        }
        m_loop_union.setEnabled(true);
        m_loop_union.setText("Объединить цикл в строке " + Utils_.Brackets(loop.line) + " со следующим");
    }
    @Override
    public void CheckElementsVisibility() {
        super.CheckElementsVisibility();
        m_strike.setVisible(false);
        m_unstrike.setVisible(false);
        checkFunction();
        checkHeader();
        checkLoop();
        if (selectedText == null) {
            m_comment.setEnabled(false);
            m_uncomment.setEnabled(false);
            m_add_lines_to_region.setEnabled(false);
            m_remove_lines_from_region.setEnabled(false);
            m_comment.setText("Невозможно закомментировать блок. Не выделено ни одной строки.");
            m_uncomment.setText("Невозможно раскомментировать блок. Не выделено ни одной строки.");
            m_add_lines_to_region.setText("Невозможно добавить строки в область. Не выделено ни одной строки.");
            m_remove_lines_from_region.setText("Невозможно удалить строки из области. Не выделено ни одной строки.");
        } else {
            m_comment.setEnabled(true);
            m_uncomment.setEnabled(true);
            m_add_lines_to_region.setEnabled(true);
            m_remove_lines_from_region.setEnabled(true);
            m_comment.setText("Закомментировать блок");
            m_uncomment.setText("Раскомментировать блок");
            m_add_lines_to_region.setText("Добавить строки в область");
            m_remove_lines_from_region.setText("Удалить строки из области");
        }
        if (Global.mainModule.getSapfor().OldFiles.isEmpty()) {
            m_undo.setEnabled(false);
            m_undo.setText("Невозможно отменить последнюю модификацию. Модификации отсутствуют.");
        } else {
            m_undo.setEnabled(true);
            m_undo.setText("Отменить последнюю модификацию.");
        }
    }
}
