package _VisualDVM.Visual.Windows;
import Common.Utils.Pair;
import Common.Utils.Utils_;
import Common.Visual.TextField.StyledTextField;
import Common.Visual.Trees.StyledTree;
import Common.Visual.UI;
import Common.Visual.Windows.Form;
import _VisualDVM.Global;
import _VisualDVM.Passes.PassCode;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rtextarea.SearchContext;
import org.fife.ui.rtextarea.SearchEngine;
import org.fife.ui.rtextarea.SearchResult;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.LinkedHashMap;
public class SearchReplaceForm extends Form {
    public static String lastProjectPath = "";
    public static LinkedHashMap<String, Long> matches = new LinkedHashMap<>();
    public JPanel MainPanel;
    public boolean forward = true;
    SearchContext context = null;
    RSyntaxTextArea editor = null;
    boolean replace_mode = false;
    private JTextField tfFind;
    private JTextField tfReplace;
    private JCheckBox replaceOn;
    private JCheckBox registerOn;
    private JCheckBox wholeWordOn;
    private JRadioButton rbUp;
    private JRadioButton rbDown;
    private JButton bAll;
    private JButton bNext;
    private JCheckBox loopOn;
    private JLabel lCount;
    private SearchResult result = null;
    //------------------
    //-
    private JButton bSearchInFiles;
    private JPanel filesTreePanel;
    private JLabel lFilesMatchesCount;
    public SearchReplaceForm() {
        context = new SearchContext();
        //-
        context.setRegularExpression(true);
        //-
        rbDown.addActionListener(e -> SwitchDirection(!forward));
        rbUp.addActionListener(e -> SwitchDirection(!forward));
        bAll.addActionListener(e -> onAll());
        bNext.addActionListener(e -> onNext());
        replaceOn.addActionListener(e -> {
            setMode(replaceOn.isSelected());
        });
        bNext.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER)
                    bNext.doClick();
            }
        });
        tfFind.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                switch (e.getKeyCode()) {
                    case KeyEvent.VK_ENTER:
                        bNext.requestFocus();
                        bNext.doClick();
                        break;
                }
            }
        });
        bSearchInFiles.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    showNoFilesMatches();
                    lastProjectPath = Global.mainModule.getProject().Home.getAbsolutePath();
                    matches = Global.mainModule.getProject().getMatches(
                            tfFind.getText(),
                            registerOn.isSelected(),
                            wholeWordOn.isSelected());
                    showFilesMatches();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
    }
    //https://techarks.ru/qa/java/kak-uznat-kakoj-iz-jlist-s-Y4/
    public void ClearMarkers() {
        //сброс выделения. решается подсовыванием пустой строки
        context.setSearchFor("");
        SearchEngine.find(editor, context);
        DropMatchCount();
    }
    public void DropMatchCount() {
        lCount.setText("0");
    }
    public void updateEditor(RSyntaxTextArea editor_in) {
        editor = editor_in;
        if (isVisible())
            requestFocus();
    }
    @Override
    protected JPanel getMainPanel() {
        return MainPanel;
    }
    @Override
    public void Close() {
        ClearMarkers();
        super.Close();
    }
    public void setMode(boolean replace) {
        replace_mode = replace;
        tfReplace.setEnabled(replace_mode);
        String prefix = replace_mode ? "Заменить" : "Найти";
        bNext.setText(prefix + " далее");
        bAll.setText(prefix + " всё");
    }
    public void ShowMode() {
        replaceOn.setSelected(replace_mode);
    }
    @Override
    public Component getRelative() {
        return (Component) Global.mainModule.getUI().getMainWindow();
    }
    @Override
    public int getDefaultWidth() {
        return 650;
    }
    @Override
    public int getDefaultHeight() {
        return 400;
    }
    public void Refresh() {
        String text = editor.getSelectedText();
        if ((text != null) && !text.isEmpty())
            tfFind.setText(text);
        tfFind.requestFocus();
    }
    //-------------------------------
    public void SwitchDirection(boolean direction_in) {
        forward = direction_in;
        if (forward) {
            rbUp.setSelected(false);
            rbDown.setSelected(true);
        } else {
            rbDown.setSelected(false);
            rbUp.setSelected(true);
        }
    }
    public void applyParams() {
        String toFind = Utils_.hideRegularMetasymbols(tfFind.getText());
        String toReplace = Utils_.hideRegularMetasymbols(tfReplace.getText());
        context.setSearchFor(toFind);
        context.setMatchCase(registerOn.isSelected());
        context.setWholeWord(wholeWordOn.isSelected());
        if (replace_mode)
            context.setReplaceWith(toReplace);
        DropMatchCount();
    }
    public void onAll() {
        applyParams();
        result = replace_mode ?
                SearchEngine.replaceAll(editor, context) : SearchEngine.markAll(editor, context);
        lCount.setText(String.valueOf(
                replace_mode ? result.getCount() : result.getMarkedCount()));
    }
    public void onNext() {
        applyParams();
        context.setSearchForward(forward);
        result = replace_mode ? SearchEngine.replace(editor, context) : SearchEngine.find(editor, context);
        if (loopOn.isSelected() && !result.wasFound()) SwitchDirection(!forward);
        lCount.setText(String.valueOf(result.getMarkedCount()));
    }
    @Override
    public String getFormKey() {
        return "SearchReplace";
    }
    private void createUIComponents() {
        // TODO: place custom component creation code here
        tfFind = new StyledTextField();
        tfReplace = new StyledTextField();
    }
    public void dropFilesMatches() {
        matches = new LinkedHashMap<>();
    }
    public void showNoFilesMatches() {
        lFilesMatchesCount.setText("—");
        UI.Clear(filesTreePanel);
    }
    public void showFilesMatches() {
        long total = 0;
        DefaultMutableTreeNode res = new DefaultMutableTreeNode("файлов " + matches.size());
        for (String fileName : matches.keySet()) {
            DefaultMutableTreeNode fileNode = new DefaultMutableTreeNode(new Pair(fileName, matches.get(fileName)) {
                @Override
                public String toString() {
                    return getKey() + ":" + getValue();
                }
            });
            res.add(fileNode);
            total += matches.get(fileName);
        }
        StyledTree matchesTree = new StyledTree(res) {
            {
                setRootVisible(false);
            }
            @Override
            public void LeftMouseAction2() {
                DefaultMutableTreeNode selectedFile = (DefaultMutableTreeNode) getLastSelectedPathComponent();
                if (selectedFile != null) {
                    Pair<String, Long> info = (Pair<String, Long>) selectedFile.getUserObject();
                    if (Global.mainModule.getProject().db.files.containsKey(info.getKey())) {
                        Global.mainModule.getPass(PassCode.OpenCurrentFile).Do(Global.mainModule.getProject().db.files.get(info.getKey()));
                        //--->>>
                        replaceOn.setSelected(false);
                        setMode(false);
                        SwitchDirection(true);
                        //-
                        bNext.requestFocus();
                        bNext.doClick();
                    }
                }
            }
        };
        filesTreePanel.add(matchesTree);
        filesTreePanel.revalidate();
        filesTreePanel.repaint();
        lFilesMatchesCount.setText(String.valueOf(total));
    }
    @Override
    public void Show() {
        super.Show();
        //------->>
        showNoFilesMatches();
        if (lastProjectPath.equals(Global.mainModule.getProject().Home.getAbsolutePath()))
            showFilesMatches();
        else
            dropFilesMatches();
        //------->>
        Refresh();
        // setAlwaysOnTop(true);
    }
}
