package Common.Visual.Editor;
import Common.MainModule_;
import Common.Utils.Pair;
import Common.Utils.Utils_;
import Common.Visual.Menus.StyledPopupMenu;
import Common.Visual.Menus.TextEditorMenu;
import Common.Visual.Themes.ThemeElement;
import Common.Visual.UI;
import Common.Visual.Windows.Dialog.DialogFields;
import _VisualDVM.Utils;
import _VisualDVM.Visual.Syntax.SPFEditorTheme;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;

import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.net.URI;
import java.util.Vector;
public class BaseEditor extends RSyntaxTextArea implements ThemeElement, DialogFields {
    protected final StyledPopupMenu menu;
    //  protected int changesCount = 0;
    //  protected int insertsCount = 0;
    //  protected int removesCount = 0;
    //  protected boolean ctrlZ = false;
    protected String startText = "";
    private boolean search_enabled = true;
    public BaseEditor() {
        setTabSize(6);
        setPaintTabLines(true);
        setCodeFoldingEnabled(true);
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.isControlDown()) {
                    switch (e.getKeyCode()) {
                        case KeyEvent.VK_ADD: //num lock  +
                        case KeyEvent.VK_EQUALS:    //+
                            FontUp();
                            break;
                        case KeyEvent.VK_SUBTRACT:  //num lock -
                        case KeyEvent.VK_MINUS: //-
                            FontDown();
                            break;
                        case KeyEvent.VK_S:
                            saveText();
                            break;
                        //todo переход в нужную строку по ctrl+g?
                        case KeyEvent.VK_Z:
                            if (getText().equals(startText)) {
                                UI.Info("Начальная версия текста достигнута.");
                                e.consume();
                            }
                            break;
                    }
                }
            }
        });
        setPopupMenu(menu = createMenu());
        applyTheme();
        //-
        this.setHyperlinksEnabled(true);
        HyperlinkListener listener = new HyperlinkListener() {
            @Override
            public void hyperlinkUpdate(HyperlinkEvent event) {
                if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
                    try {
                        Desktop.getDesktop().browse(new URI(event.getURL().toString()));
                    } catch (Exception ioe) {
                        System.err.println("Error loading url from link: " + ioe);
                    }
                }
            }
        };
        this.addHyperlinkListener(listener);
    }
    @Override
    public void setText(String t) {
        super.setText(t);
        startText = t;
    }
    public void setSearchEnabled(boolean f_in) {
        search_enabled = f_in;
    }
    protected StyledPopupMenu createMenu() {
        return new TextEditorMenu(this);
    }
    private void changeFont(int size) {
        if ((size > 1) && (size < 48)) {
            setFont(getFont().deriveFont((float) size));
            saveFont();
        }
    }
    protected void saveFont() {
    }
    protected void saveText() {
    }
    public void ClearSelection() {
        setSelectionStart(0);
        setSelectionEnd(0);
    }
    public void gotoLine(int LineNum) {
        gotoLine_(LineNum - 1);
    }
    //без вычитания.
    public void gotoLine_(int LineNum) {
        //requestFocus();
        try {
            //особеннсть контрола.
            //нельзя полностью скинуть текущую  позицию. пэтому если надо
            //освежить 0 строку, передергиваем до последней.
            if (LineNum == 0)
                setCaretPosition(getLineStartOffset(getLineCount() - 1));
            ClearSelection();
            if (LineNum > 0) {
                setCaretPosition(getLineStartOffset(LineNum));
                setSelectionStart(getLineStartOffset(LineNum));
                setSelectionEnd(getLineStartOffset(LineNum));
            }
        } catch (Exception ex) {
            Utils_.MainLog.Print("Не удалось перейти на строку " + LineNum);
            Utils_.MainLog.PrintException(ex);
        }
    }
    //------------------------------------------
    public void FontUp() {
        changeFont(getFont().getSize() + 1);
    }
    public void FontDown() {
        changeFont(getFont().getSize() - 1);
    }
    @Override
    public Component getContent() {
        return this;
    }
    public void ShowBegin() {
        setCaretPosition(0);
    }
    public boolean lineIsVisible(int lineNum) {
        boolean res = false;
        Rectangle rectangle = this.getVisibleRect();
        try {
            res = rectangle.contains(rectangle.x, yForLine(lineNum));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return res;
    }
    //todo как то вывести из коммон.
    @Override
    public void applyTheme() {
        float font_size = (float) getFont().getSize();
        ((SPFEditorTheme) MainModule_.instance.getUI().getTheme()).getEditorTheme().apply(this);
        setFont(getFont().deriveFont(font_size));
        menu.applyTheme();
        //меню связано с редактором. поэтому тема меняется только вместе с ним.
    }
    //--
    public Vector<Pair<Integer, Integer>> getErrorsForHightlight() {
        Vector<Pair<Integer, Integer>> res = new Vector<>();
        for (int i = 0; i < this.getLineCount(); ++i) {
            try {
                int start = getLineStartOffset(i);
                int end = getLineEndOffset(i);
                String line = this.getText(start, end);
                if (Utils.isCrushedLine(line))
                    res.add(new Pair<>(start, end));
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return res;
    }
}
