/*     */
package org.ui.editors.code;

import org.renderer.PostProcessConfig;
import org.run.GyteCompiler;
import org.ui.UICreator;
import org.ui.debug.Console;
import org.world.World;

import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.*;
import java.util.Formatter;

public class CodeEditor extends JFrame {
    private static final long serialVersionUID = -5830316930709180479L;
    private volatile boolean closeRequest;
    private JSplitPane consoleSplitter;
    private JPanel editorPane;
    private JScrollPane scrollPane;
    private JLineNumberTextPane lineNumbers;
    private JPanel editorBase;
    private JPanel controlPanel;
    private JLabel programStatus;
    private GraphicsConfig configs;
    private JTextPane codeEditor;
    private Console console;
    private JButton run;
    private JButton stop;
    private JButton load;
    private JButton save;
    private JButton settings;
    private JavaSyntaxHighlighter highligher;
    private GyteCompiler compiler;

    public CodeEditor(World world, PostProcessConfig postProcessConfig) {
        setOpacity(1.0f);
        setBackground(Color.BLACK);

        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        this.configs = new GraphicsConfig(postProcessConfig);

        createUIComponents();
        setupUIComponents();
        createUIListener(world);

        this.compiler = new GyteCompiler(world, this.console, this);

        setTitle("RTX-GYTEBOT - Logic Editor");
        getContentPane().add(this.consoleSplitter);
        setSize(screenSize.width / 2, screenSize.height);
        setLocation(screenSize.width / 2, 0);
        setVisible(true);

        this.consoleSplitter.setDividerLocation(0.7D);
    }

    private void createUIComponents() {
        /* 120 */
        this.codeEditor = new JTextPane();
        /* 121 */
        this.lineNumbers = new JLineNumberTextPane(this.codeEditor);
        /* 122 */
        this.highligher = new JavaSyntaxHighlighter(this.codeEditor, 16);
        /* 123 */
        this.console = new Console();
        this.controlPanel = new JPanel(new FlowLayout(0, 6, 4));
        /* 127 */
        this.editorBase = new JPanel(new BorderLayout());
        /* 128 */
        this.consoleSplitter = new JSplitPane(0);
        /* 129 */
        this.editorPane = new JPanel(new BorderLayout());

        this.run = UICreator.createIconifiedButton('e');
        /* 133 */
        this.run.setToolTipText("Compile and run the program.");
        /* 134 */
        this.stop = UICreator.createIconifiedButton('d');
        /* 135 */
        this.stop.setToolTipText("Kill the current running program");
        /* 136 */
        this.load = UICreator.createIconifiedButton('a');
        /* 137 */
        this.load.setToolTipText("Import an external file of code");
        this.save = UICreator.createIconifiedButton('b');
        this.save.setToolTipText("Save the current code to disk");
        this.settings = UICreator.createIconifiedButton('i');
        this.settings.setToolTipText("Open settings");
        this.programStatus = new JLabel();
    }

    private void setupUIComponents() {
        /* 152 */
        this.editorBase.add(this.codeEditor, "Center");
        /* 153 */
        this.editorBase.add(this.lineNumbers, "West");
        this.codeEditor.setText(getDefaultCode());
        this.codeEditor.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 16));
        this.highligher.updateSource();
        this.lineNumbers.updateLineNumbers();
        this.programStatus.setOpaque(true);
        /* 167 */
        this.programStatus.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createMatteBorder(1, 1, 1, 1, Color.GRAY),
                BorderFactory.createEmptyBorder(4, 8, 4, 16)));
        this.programStatus.setText("Off");

        this.consoleSplitter.setTopComponent(this.editorPane);

        this.consoleSplitter.setBottomComponent((Component) this.console);

        this.scrollPane = new JScrollPane(this.editorBase);
        this.scrollPane.getVerticalScrollBar().setUnitIncrement(16);

        this.editorPane.add(this.controlPanel, "North");
        /* 183 */
        this.editorPane.add(this.scrollPane, "Center");

        this.controlPanel.add(Box.createHorizontalStrut(12));
        /* 187 */
        this.controlPanel.add(this.settings);
        /* 188 */
        this.controlPanel.add(Box.createHorizontalStrut(8));
        /* 189 */
        this.controlPanel.add(this.load);
        /* 190 */
        this.controlPanel.add(this.save);
        /* 191 */
        this.controlPanel.add(Box.createHorizontalStrut(8));
        /* 192 */
        this.controlPanel.add(this.run);
        /* 193 */
        this.controlPanel.add(this.stop);
        /* 194 */
        this.controlPanel.add(Box.createHorizontalStrut(8));
        /* 195 */
        this.controlPanel.add(this.programStatus);
    }

    private void createUIListener(World world) {
        this.settings.addActionListener(e -> this.configs.open());

        addWindowListener(new WindowAdapter()
                /*     */ {
            /*     */
            /*     */
            public void windowClosing(WindowEvent event)
            /*     */ {
                CodeEditor.this.closeRequest = true;
            }
            /*     */
        });

        this.save.addActionListener(e -> {

            JFileChooser chooser = new JFileChooser();
            chooser.setDialogType(1);

            int value = chooser.showDialog(null, "Choose File to Save to");

            if (value == 0) {
                saveCodeToFile(chooser.getSelectedFile());
            }
        });

        this.load.addActionListener(e -> {

            JFileChooser chooser = new JFileChooser();
            chooser.setDialogType(0);

            int value = chooser.showDialog(null, "Choose File to Load");

            if (value == 0) {
                try {

                    BufferedReader reader = new BufferedReader(new FileReader(chooser.getSelectedFile()));
                    this.codeEditor.setText(reader.lines().reduce("", (a, b) -> a + b));
                    this.highligher.updateSource();
                    this.lineNumbers.updateLineNumbers();
                    reader.close();

                } catch (Exception e1) {

                    e1.printStackTrace();

                    JOptionPane.showMessageDialog(null, "Unable to find/open/read selected file", "Error - loading file", 0);

                }

            }
        });
        /*     */
        /* 267 */
        this.codeEditor.addKeyListener(new KeyAdapter()
                /*     */ {
            /*     */
            /*     */
            /*     */
            public void keyReleased(KeyEvent event)
            /*     */ {
                final int scrollValue = CodeEditor.this.scrollPane.getVerticalScrollBar().getValue();

                CodeEditor.this.highligher.updateSource();
                CodeEditor.this.lineNumbers.updateLineNumbers();

                SwingUtilities.invokeLater(new Runnable()
                        /*     */ {
                    /*     */
                    public void run()
                    /*     */ {
                        scrollPane.getVerticalScrollBar().setValue(scrollValue);
                        /*     */
                    }
                    /*     */
                });
                /*     */
            }
            /*     */
        });
        /*     */
        /*     */
        /* 290 */
        this.stop.addActionListener(e -> {
            /*     */
            if (this.compiler.getProcessor() != null) {
                /*     */
                this.compiler.getProcessor().halt();
                /*     */
            }
            /*     */
        });
        /*     */
        /*     */
        /*     */
        /* 298 */
        this.run.addActionListener(e -> {

            if (world.getGytebot() != null) {
                SwingUtilities.invokeLater(() -> this.compiler.compileAndRunProgram(this.codeEditor.getText()));
            } else {
                JOptionPane.showMessageDialog(null, "No GYTEBOT is associated with the current code", "Exception - Headless processor", 0);
            }
            /*     */
        });
        /*     */
    }

    private void saveCodeToFile(File saveFile) {
        /*     */
        try {
            /* 319 */
            Formatter formatter = new Formatter(saveFile);
            /*     */
            /* 321 */
            formatter.format("%s", new Object[]{this.codeEditor.getText()});
            /*     */
            /* 323 */
            formatter.close();
            /* 324 */
        } catch (FileNotFoundException e) {
            /*     */
            /* 326 */
            JOptionPane.showMessageDialog(null, "Could not save code to file: " + saveFile.toURI(), "Error - saving code", 0);
            /* 327 */
            e.printStackTrace();
            /*     */
        }
        /*     */
    }

    /*     */
    /*     */
    /*     */
    /*     */
    /*     */
    /*     */
    /*     */
    /*     */
    public final void markLine(int lineNumber) {
        /*     */
        try {
            /* 339 */
            String text = this.codeEditor.getStyledDocument().getText(0, this.codeEditor.getStyledDocument().getLength());
            /*     */
            /* 341 */
            int lineCounter = lineNumber - 1;
            /*     */
            /*     */
            /* 344 */
            int start = 0;
            /* 345 */
            int end = 0;
            /*     */
            /*     */
            /* 348 */
            for (int i = 0; i < text.length(); i++) {
                /* 349 */
                if (text.charAt(i) == '\n') {
                    /*     */
                    /*     */
                    /* 352 */
                    lineCounter--;
                    /*     */
                    /*     */
                    /* 355 */
                    if (lineCounter == 0) {
                        /*     */
                        /* 357 */
                        start = i;
                        /*     */
                        /*     */
                        /* 360 */
                        for (int k = i + 1; k < text.length(); k++) {
                            /* 361 */
                            if (text.charAt(k) == '\n') {
                                /*     */
                                /* 363 */
                                end = k;
                                /*     */
                                /*     */
                                break;
                                /*     */
                            }
                            /*     */
                        }
                        /*     */
                        /*     */
                        break;
                        /*     */
                    }
                    /*     */
                }
                /*     */
            }
            /*     */
            /* 374 */
            StyleContext sc = StyleContext.getDefaultStyleContext();
            /*     */
            /*     */
            /* 377 */
            AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Background, new Color(16537688));
            /*     */
            /* 379 */
            this.codeEditor.getStyledDocument().setCharacterAttributes(start, end - start, aset, false);
            /* 380 */
        } catch (BadLocationException e) {
            /* 381 */
            e.printStackTrace();
            /*     */
        }
        /*     */
    }


    public void setProgramStatus(boolean isRunning) {
        /* 391 */
        this.programStatus.setText(isRunning ? "Running..." : "Off");
        /* 392 */
        this.programStatus.setBackground(isRunning ? Color.GREEN : Color.LIGHT_GRAY);
        /*     */
    }


    private String getDefaultCode() {
        /*     */
        try {
            /* 403 */
            return new String(getClass().getResourceAsStream("/data/defaultCode.java.example").readAllBytes());
            /* 404 */
        } catch (IOException e) {
            /* 405 */
            JOptionPane.showMessageDialog(null, "Unable to read or open default code template", "Error - loading default code template", 0);
            /*     */
            /* 407 */
            return null;
            /*     */
        }
        /*     */
    }

    public boolean getWindowCloseRequest() {
        /* 417 */
        return this.closeRequest;
        /*     */
    }
    /*     */
}
