package com.bitmester;

import com.bitmester.io.PrgExporter;
import com.bitmester.io.PrgImporter;
import com.bitmester.model.PictureInfo;
import com.bitmester.model.Plus4Palette;
import com.bitmester.ui.EditorCanvas;
import com.bitmester.ui.PalettePanel;
import com.bitmester.ui.PaintChannelPanel;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.*;
import java.io.File;

/**
 * v1.3.1-src4-PointerPanels • Ref: [UI-POINTER-016]
 * Base:
 *   - v1.3.0-src4-BrushSize • Ref: [DRAW-BRUSH-012]
 *   - v1.2.4-src4-ColorEyedropper (Alt+Click) [UX-EYEDROP-005]
 *
 * Új:
 *   - Pointer panel a jobb oldali eszközoszlop tetején:
 *       1. sor:  Curs.x / Curs.y / DFLI Row / DFLI Column
 *       2. sor:  Actual color + színnégyzet + Hex + Color indicator
 *   - Tools szekció:
 *       3×2 rács: Undo, Clear/Fill, Remap, Brush size, Color Filter, Help/About
 *   - Section header-ek: [Pointer], [Tools], [I/O], [PaintChannel]
 *
 * Megmaradó funkciók:
 *   - Alt+Click szín-pipetta (Eyedropper)
 *   - jobb klikkes cycle (0→1→2→3→0)
 *   - Heatmap overlay
 *   - Undo ×3
 *   - Remap Color Bands dialog
 *   - Brush size popup (Normal..64×64)
 *   - Import/Export PRG + ASM (io/dfli.prg template-ből)
 */
public class DFLIEditor extends JFrame {
    private final PictureInfo pic;
    private final EditorCanvas canvas;
    private final PalettePanel palette;
    private final PaintChannelPanel paintPanel;
    private final JSlider lineSlider, zoomSlider;
    private final JLabel status;

    // Pointer panelhez tartozó mezők
    private JLabel lblCursX;
    private JLabel lblCursY;
    private JLabel lblDFLIRow;
    private JLabel lblDFLICol;
    private JLabel lblActualHex;
    private JLabel lblColorIndicator;
    private JPanel pnlActualColor;

    public DFLIEditor() {
        super("DFLI Editor (Java) – Bytehexer");
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        // --- Model ---
        pic = new PictureInfo(320, 200);
        status = new JLabel();

        // --- Vászon ---
        canvas = new EditorCanvas(pic);
        canvas.setHeatmapListener(this::refreshStatusAndRepaint);

        // Pointer: egérmozgás figyelése közvetlenül a canvas-on
        canvas.addMouseMotionListener(new MouseMotionAdapter() {
            @Override public void mouseMoved(MouseEvent e) { updatePointerFromMouse(e); }
            @Override public void mouseDragged(MouseEvent e) { updatePointerFromMouse(e); }
        });

        JScrollPane scroller = new JScrollPane(canvas);
        add(scroller, BorderLayout.CENTER);

        // --- Jobb oszlop: Paletta + Pointer + Tools + I/O + Paint channel ---
        palette = new PalettePanel(pic, this::refreshStatusAndRepaint);

        // Pointer panel (új)
        JPanel pointerPanel = buildPointerPanel();

        // ---- TOOLS: Undo, Clear/Fill, Remap, Brush size, Color Filter, Help/About ----

        // Undo ×3
        JButton btnUndo = bigButton("Undo × 0");
        btnUndo.setEnabled(false);
        btnUndo.addActionListener(e -> {
            if (canvas.performUndo()) {
                int left = canvas.getUndoCount();
                btnUndo.setText("Undo × " + left);
                btnUndo.setEnabled(left > 0);
                refreshStatusAndRepaint();
            }
        });
        canvas.setUndoListener(count -> {
            btnUndo.setText("Undo × " + count);
            btnUndo.setEnabled(count > 0);
        });

        // Clear/Fill GFX
        JButton btnClearFill = bigButton("Clear GFX or ReFill Colors");
        btnClearFill.addActionListener(e -> showClearFillDialog());

        // Remap Color Bands…
        JButton btnRemap = bigButton("Remap Color Bands");
        btnRemap.addActionListener(e -> {
            new com.bitmester.ui.RemapColorBandsDialog(
                    this,
                    pic,
                    () -> {
                        // Undo snapshot KIZÁRÓLAG akkor, ha az Apply lefut
                        canvas.pushUndoSnapshot();
                        int left = canvas.getUndoCount();
                        btnUndo.setText("Undo × " + left);
                        btnUndo.setEnabled(left > 0);
                    }
            ).setVisible(true);

            refreshStatusAndRepaint();
        });

        // Brush size selector
        JPanel brushPanel = new JPanel(new BorderLayout(4, 0));
        // JLabel brushLabel = new JLabel(""); // dísz, gyakorlatilag üres
        // Ugyanaz a “big” stílus, mint a többi gombnak
        JButton brushButton = bigButton("Brush size: normal");
        brushButton.setFocusPainted(false);

                brushButton.addActionListener(e -> {
            // Modális dialog a Brush size-hoz
            JDialog dlg = new JDialog(this, "Brush size", true);

            JPanel grid = new JPanel(new GridLayout(0, 2, 8, 8));
            grid.setBorder(new EmptyBorder(8, 8, 8, 8));

            // Helper lambda egy méret-gomb hozzáadásához
            java.util.function.BiConsumer<String, Integer> addSizeButton = (label, sizePx) -> {
                JButton b = new JButton(label);
                b.setFocusPainted(false);
                b.addActionListener(ev -> {
                    canvas.setBrushSize(sizePx);
                    brushButton.setText(label);
                    dlg.dispose();
                });
                grid.add(b);
            };

            addSizeButton.accept("Brush size: normal", 1);
            addSizeButton.accept("Brush size: 2×2", 2);
            addSizeButton.accept("Brush size: 4×4", 4);
            addSizeButton.accept("Brush size: 6×6", 6);
            addSizeButton.accept("Brush size: 8×8", 8);
            addSizeButton.accept("Brush size: 10×10", 10);
            addSizeButton.accept("Brush size: 12×12", 12);
            addSizeButton.accept("Brush size: 16×16", 16);
            addSizeButton.accept("Brush size: 32×32", 32);
            addSizeButton.accept("Brush size: 64×64", 64);

            dlg.getContentPane().add(grid);
            dlg.pack();
            dlg.setLocationRelativeTo(brushButton);
            dlg.setVisible(true);
        });


               

        //brushPanel.add(brushLabel, BorderLayout.CENTER); //west
        brushPanel.add(brushButton, BorderLayout.CENTER);

        // ÚJ: Color Filter + Help/About gombok (egyelőre stub dialógusokkal)
        JButton btnColorFilter = bigButton("Color Filter");
        btnColorFilter.addActionListener(e -> showColorFilterDialog());

        JButton btnHelpAbout = bigButton("Help / About");
        btnHelpAbout.addActionListener(e -> showHelpAboutDialog());

        // Tools blokk: 3×2 rács – Undo / Clear-Fill / Remap / Brush / Color Filter / Help
        JPanel toolsGrid = new JPanel(new GridLayout(3, 2, 8, 8));
        toolsGrid.add(btnUndo);
        toolsGrid.add(btnClearFill);
        toolsGrid.add(btnRemap);
        toolsGrid.add(brushPanel);
        toolsGrid.add(btnColorFilter);
        toolsGrid.add(btnHelpAbout);

        JPanel toolsSection = new JPanel();
        toolsSection.setLayout(new BoxLayout(toolsSection, BoxLayout.Y_AXIS));
        toolsSection.add(makeSectionHeader("Tools"));
        toolsSection.add(Box.createVerticalStrut(4));
        toolsSection.add(toolsGrid);

        // ---- I/O: Import / Export ----
        JPanel ioButtons = new JPanel(new GridLayout(1,2,8,8));
        JButton btnImport = bigButton("Import PRG…");
        JButton btnExport = bigButton("Export PRG…");
        btnImport.addActionListener(e -> doImport(btnUndo));
        btnExport.addActionListener(e -> doExport());
        ioButtons.add(btnImport);
        ioButtons.add(btnExport);

        JPanel ioSection = new JPanel();
        ioSection.setLayout(new BoxLayout(ioSection, BoxLayout.Y_AXIS));
        ioSection.add(makeSectionHeader("I/O"));
        ioSection.add(Box.createVerticalStrut(4));
        ioSection.add(ioButtons);

        // Paint channel panel (0:FF15, 1:AUX1, 2:AUX0, 3:FF16)
        paintPanel = new PaintChannelPanel(pic, idx -> {
            pic.setCurrentPaint(idx);
            refreshStatusAndRepaint();
        });

        JPanel paintWrapper = new JPanel();
        paintWrapper.setLayout(new BoxLayout(paintWrapper, BoxLayout.Y_AXIS));
        paintWrapper.add(makeSectionHeader("PaintChannel"));
        paintWrapper.add(Box.createVerticalStrut(4));
        paintWrapper.add(paintPanel);

        // Jobb oldali oszlop összeállítás
        JPanel eastTop = new JPanel();
        eastTop.setLayout(new BoxLayout(eastTop, BoxLayout.Y_AXIS));
        eastTop.add(palette);
        eastTop.add(Box.createVerticalStrut(8));
        eastTop.add(pointerPanel);
        eastTop.add(Box.createVerticalStrut(8));
        eastTop.add(toolsSection);
        eastTop.add(Box.createVerticalStrut(8));
        eastTop.add(ioSection);
        eastTop.add(Box.createVerticalStrut(8));
        eastTop.add(paintWrapper);

        JPanel eastColumn = new JPanel(new BorderLayout(0,8));
        eastColumn.add(eastTop, BorderLayout.CENTER);
        add(eastColumn, BorderLayout.EAST);

        // Alsó sáv
        lineSlider = new JSlider(0, pic.getYs() - 1, 0);
        lineSlider.addChangeListener(e -> {
            if (!lineSlider.getValueIsAdjusting()) {
                pic.setCurY(lineSlider.getValue());
                refreshStatusAndRepaint();
            }
        });

        // Zoom 100–600%
        JSlider z = new JSlider(100, 600, 100);
        this.zoomSlider = z;
        zoomSlider.setPaintTicks(true);
        zoomSlider.setMajorTickSpacing(100);
        zoomSlider.setMinorTickSpacing(25);
        zoomSlider.addChangeListener(e -> {
            int val = zoomSlider.getValue();
            canvas.setZoomPercent(val);
            refreshStatusAndRepaint();
        });

        JPanel south = new JPanel(new BorderLayout(8,0));
        JPanel southTop = new JPanel(new GridLayout(1,2,12,0));
        southTop.add(new Labeled("CurY", lineSlider));
        southTop.add(new Labeled("Zoom %", zoomSlider));
        south.add(southTop, BorderLayout.CENTER);
        south.add(status, BorderLayout.SOUTH);
        add(south, BorderLayout.SOUTH);

        setJMenuBar(buildMenu());
        setSize(1220, 800);

        // Indításkor: bitmap + GFX color mapok törlése
        clearGfxAll();

        setLocationRelativeTo(null);
        refreshStatusAndRepaint();
    }

            


    // =========================
    // Pointer panel felépítése
    // =========================
    private JPanel buildPointerPanel() {
        JPanel p = new JPanel();
        p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
        p.setBorder(new EmptyBorder(4,0,4,0));

        p.add(makeSectionHeader("Pointer"));
        p.add(Box.createVerticalStrut(4));

        // 1. sor: Curs.x / Curs.y / DFLI Row / DFLI Column
        JPanel row1 = new JPanel(new GridLayout(1, 4, 8, 3)); //1, 4, 8, 0
        lblCursX   = new JLabel("Actual X: ---");
	lblCursX.setFont(lblCursX.getFont().deriveFont(Font.BOLD, 14f));
        lblCursY   = new JLabel("Actual Y: ---");
	lblCursY.setFont(lblCursY.getFont().deriveFont(Font.BOLD, 14f));
        lblDFLIRow = new JLabel("DFLI Row: --");
	lblDFLIRow.setFont(lblCursY.getFont().deriveFont(Font.BOLD, 14f));
        lblDFLICol = new JLabel("DFLI Column: --");
	lblDFLICol.setFont(lblCursY.getFont().deriveFont(Font.BOLD, 14f));
        row1.add(lblCursX);
        row1.add(lblCursY);
        row1.add(lblDFLIRow);
        row1.add(lblDFLICol);
        p.add(row1);

        //p.add(Box.createVerticalStrut(4));

                // 2. sor: Actual color + színnégyzet + Hex + Color indicator
        // 4 fix oszlop, mint a felső sorban
        JPanel row2 = new JPanel(new GridLayout(1, 4, 8, 3));

        Font f = row2.getFont().deriveFont(Font.BOLD, 14f);

        // --- 1. oszlop: Actual color + színnégyzet ---
        JPanel cell1 = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 0));
        JLabel lblActualTitle = new JLabel("Actual color:");
        lblActualTitle.setFont(f);

        pnlActualColor = new JPanel();
        pnlActualColor.setPreferredSize(new Dimension(24, 16));
        pnlActualColor.setMinimumSize(new Dimension(24, 16));
        pnlActualColor.setMaximumSize(new Dimension(24, 16));
        pnlActualColor.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));

        cell1.add(lblActualTitle);
        cell1.add(pnlActualColor);

        // --- 2. oszlop: Hex érték ---
        JPanel cell2 = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 0));
        lblActualHex = new JLabel("Hex: $00");
        lblActualHex.setFont(f);
        cell2.add(lblActualHex);

        // --- 3. oszlop: PaintChannel címke ---
        JPanel cell3 = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 0));
        JLabel lblIndicatorTitle = new JLabel("PaintChannel:");
        lblIndicatorTitle.setFont(f);
        cell3.add(lblIndicatorTitle);

        // --- 4. oszlop: PaintChannel érték (0–FF15 BG, stb.) ---
        JPanel cell4 = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 0));
        lblColorIndicator = new JLabel("");
        lblColorIndicator.setFont(f);
        cell4.add(lblColorIndicator);

        row2.add(cell1);
        row2.add(cell2);
        row2.add(cell3);
        row2.add(cell4);

        p.add(row2);


	return p;

    }

    // =========================
    // Pointer frissítése egér alapján
    // =========================
    private void updatePointerFromMouse(MouseEvent e) {
        int w = canvas.getWidth();
        int h = canvas.getHeight();
        if (w <= 0 || h <= 0) {
            return;
        }

        double base = pic.getZoomPercent() / 100.0;
        double scaleX = 2.0 * base;
        double scaleY = 1.0 * base;
        int imgW = (int)Math.floor(160 * scaleX);
        int imgH = (int)Math.floor(200 * scaleY);
        int offX = (w - imgW) / 2;
        int offY = (h - imgH) / 2;

        int px = e.getX();
        int py = e.getY();
        if (px < offX || py < offY || px >= offX + imgW || py >= offY + imgH) {
            // kint van a képen kívül → reset display
            setPointerDisplayInvalid();
            return;
        }

        int x = (int)Math.floor((px - offX) / scaleX);
        int y = (int)Math.floor((py - offY) / scaleY);
        if (x < 0 || x >= 160 || y < 0 || y >= 200) {
            setPointerDisplayInvalid();
            return;
        }

        // DFLI koordináták
        int dfliCol = x / 4;           // 0..39
        int dfliRow = (y / 2) * 2;     // 00,00,02,02,...,98,98

        lblCursX.setText(String.format("Actual X: %03d", x));
        lblCursY.setText(String.format("Actual Y: %03d", y));
        lblDFLIRow.setText(String.format("DFLI Row: %02d", dfliRow));
        lblDFLICol.setText(String.format("DFLI Column: %02d", dfliCol));

        // Aktuális csatorna (2bpp) + valós színindex
        int v = pic.getPixel2bpp(x, y) & 3;
        int idx;
        String indicator;

        switch (v) {
            case 0: // FF15 (BG)
                idx = pic.getFF15Line()[y] & 0xFF;
                indicator = "0 – FF15 (BG)";
                break;
            case 1: // AUX1
                idx = pic.getAuxColorsAt(x, y)[1] & 0xFF;
                indicator = "1 – FF14 AUX1";
                break;
            case 2: // AUX0
                idx = pic.getAuxColorsAt(x, y)[0] & 0xFF;
                indicator = "2 – FF14 AUX0";
                break;
            default: // 3 → FF16 (MC1)
                idx = pic.getFF16Line()[y] & 0xFF;
                indicator = "3 – FF16 (MC1)";
                break;
        }

        pnlActualColor.setBackground(Plus4Palette.getColor(idx));
        lblActualHex.setText(String.format("Hex: $%02X", idx & 0xFF));
        lblColorIndicator.setText(indicator);

        pnlActualColor.repaint();
    }

    private void setPointerDisplayInvalid() {
        if (lblCursX != null) lblCursX.setText("Actual X: ---");
        if (lblCursY != null) lblCursY.setText("Actual Y: ---");
        if (lblDFLIRow != null) lblDFLIRow.setText("DFLI Row: --");
        if (lblDFLICol != null) lblDFLICol.setText("DFLI Column: --");
        if (lblActualHex != null) lblActualHex.setText("Hex: $00");
        if (lblColorIndicator != null) lblColorIndicator.setText("--");
        if (pnlActualColor != null) {
            pnlActualColor.setBackground(Color.BLACK);
            pnlActualColor.repaint();
        }
    }

    // --- Color Filter stub (helyfoglaló a jövőbeli funkciónak) ---
    private void showColorFilterDialog() {
        JOptionPane.showMessageDialog(
                this,
                "Color Filter – reserved for future color operations.\n\n"
                        + "Jelenleg még nincs implementálva, csak helyfoglaló.",
                "Color Filter",
                JOptionPane.INFORMATION_MESSAGE
        );
    }

    // --- Help / About dialógus ---
    private void showHelpAboutDialog() {
        JOptionPane.showMessageDialog(
                this,
                "DFLI Editor (Java)\n"
                        + "Version: v1.3.1-src4-PointerPanels [UI-POINTER-016]\n"
                        + "Author: Bytehexer\n\n"
                        + "Alt+Click: Color Eyedropper\n"
                        + "H: Heatmap toggle\n"
                        + "Right-click: channel cycle (0..3)\n"
                        + "Brush size: popup a Tools blokkban.",
                "About DFLI Editor",
                JOptionPane.INFORMATION_MESSAGE
        );
    }

    // ------------------------------------------------------------
    // Clear/Fill GFX – változatlan (a te alapod)
    // ------------------------------------------------------------
    private void showClearFillDialog() {
        int ff15Idx = pic.getFF15Line()[pic.getCurY()] & 0xFF;
        int aux1Idx = pic.getColmapPaintIndex3() & 0xFF; // slot1
        int aux0Idx = pic.getColmapPaintIndex2() & 0xFF; // slot0
        int ff16Idx = pic.getFF16Line()[pic.getCurY()] & 0xFF;

        final int[] chosen = { ff15Idx, aux1Idx, aux0Idx, ff16Idx };

        JPanel root = new JPanel();
        root.setLayout(new BoxLayout(root, BoxLayout.Y_AXIS));
        root.setBorder(new EmptyBorder(8,8,8,8));

        JPanel pClear = new JPanel(new BorderLayout(8,8));
        JLabel lblClear = new JLabel("This will clear the bitmap GFX and all color Maps! Are you sure?");
        pClear.add(lblClear, BorderLayout.CENTER);
        JPanel pClearBtns = new JPanel(new FlowLayout(FlowLayout.RIGHT, 8, 0));
        JButton yes = new JButton("Yes");
        JButton no  = new JButton("No");
        pClearBtns.add(no);
        pClearBtns.add(yes);
        pClear.add(pClearBtns, BorderLayout.SOUTH);
        root.add(pClear);

        root.add(Box.createVerticalStrut(6));
        root.add(new JSeparator(SwingConstants.HORIZONTAL));
        root.add(Box.createVerticalStrut(6));

        JPanel pRefillTitle = new JPanel(new FlowLayout(FlowLayout.LEFT, 0,0));
        pRefillTitle.add(new JLabel("Refill color maps with selected colors"));
        root.add(pRefillTitle);
        root.add(Box.createVerticalStrut(6));

        JCheckBox cbFF15 = new JCheckBox("$FF15", true);
        JCheckBox cbAUX1 = new JCheckBox("AUX 1", true);
        JCheckBox cbAUX0 = new JCheckBox("AUX 0", true);
        JCheckBox cbFF16 = new JCheckBox("$FF16", true);

        JPanel rowChecks = new JPanel(new GridLayout(1, 4, 12, 6));
        rowChecks.add(cbFF15);
        rowChecks.add(cbAUX1);
        rowChecks.add(cbAUX0);
        rowChecks.add(cbFF16);
        root.add(rowChecks);
        root.add(Box.createVerticalStrut(4));

        JPanel rowSwatches = new JPanel(new GridLayout(1, 4, 12, 6));
        Swatch ff15Sw = new Swatch(chosen[0]);
        Swatch aux1Sw = new Swatch(chosen[1]);
        Swatch aux0Sw = new Swatch(chosen[2]);
        Swatch ff16Sw = new Swatch(chosen[3]);
        rowSwatches.add(ff15Sw);
        rowSwatches.add(aux1Sw);
        rowSwatches.add(aux0Sw);
        rowSwatches.add(ff16Sw);
        root.add(rowSwatches);
        root.add(Box.createVerticalStrut(8));

        JPanel pApply = new JPanel(new FlowLayout(FlowLayout.RIGHT, 8, 0));
        JButton cancel = new JButton("Cancel");
        JButton apply  = new JButton("Apply");
        pApply.add(cancel);
        pApply.add(apply);
        root.add(pApply);

        JDialog dlg = new JDialog(this, "Clear/Fill GFX", true);
        dlg.setContentPane(root);
        dlg.pack();
        dlg.setLocationRelativeTo(this);

        ff15Sw.setOnClick(() -> {
            int sel = PaletteIndexChooser.choose(this, chosen[0]);
            if (sel >= 0) { chosen[0] = sel; ff15Sw.setIndex(sel); }
        });
        aux1Sw.setOnClick(() -> {
            int sel = PaletteIndexChooser.choose(this, chosen[1]);
            if (sel >= 0) { chosen[1] = sel; aux1Sw.setIndex(sel); }
        });
        aux0Sw.setOnClick(() -> {
            int sel = PaletteIndexChooser.choose(this, chosen[2]);
            if (sel >= 0) { chosen[2] = sel; aux0Sw.setIndex(sel); }
        });
        ff16Sw.setOnClick(() -> {
            int sel = PaletteIndexChooser.choose(this, chosen[3]);
            if (sel >= 0) { chosen[3] = sel; ff16Sw.setIndex(sel); }
        });

        no.addActionListener(e -> dlg.dispose());
        yes.addActionListener(e -> { clearGfxAll(); dlg.dispose(); });
        cancel.addActionListener(e -> dlg.dispose());
        apply.addActionListener(e -> {
            boolean doFF15 = cbFF15.isSelected();
            boolean doAUX1 = cbAUX1.isSelected();
            boolean doAUX0 = cbAUX0.isSelected();
            boolean doFF16 = cbFF16.isSelected();
            refillGfxColorMapsSelective(doFF15, doAUX1, doAUX0, doFF16,
                    chosen[0], chosen[1], chosen[2], chosen[3]);
            dlg.dispose();
        });

        dlg.setVisible(true);
    }

    // --- Import PRG (istvanv layout) — indítás előtti törléssel és Undo UI nullázással
    private void doImport(JButton btnUndo) {
        JFileChooser ch = new JFileChooser();
        ch.setDialogTitle("Import DFLI PRG (istvanv layout)");
        if (ch.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            try {
                File f = ch.getSelectedFile();

                // Import előtt: bitmap + color mapok törlése, hogy tiszta állapotba jöjjön
                clearGfxAll();

                PrgImporter.importPRG(pic, f);
                refreshStatusAndRepaint();

                // Undo vizuális nullázása
                btnUndo.setText("Undo × 0");
                btnUndo.setEnabled(false);

                JOptionPane.showMessageDialog(this, "Import OK:\n" + f.getName());
            } catch (Exception ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(this,
                        "Import error: " + ex.getMessage(),
                        "Error", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    // --- Export PRG + kísérő .ASM (beépített io/dfli.prg sablon felhasználásával)
    private void doExport() {
        JFileChooser chOut = new JFileChooser();
        chOut.setDialogTitle("Save as PRG (ASM will be created alongside)");
        chOut.setSelectedFile(new File("export.prg"));
        if (chOut.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return;

        File outPrg = chOut.getSelectedFile();

        String baseName = outPrg.getName();
        int dot = baseName.lastIndexOf('.');
        String asmName = (dot > 0 ? baseName.substring(0, dot) : baseName) + ".asm";
        File outAsm = new File(outPrg.getParentFile(), asmName);

        try {
            PrgExporter.exportUsingIoTemplate(pic, outPrg, outAsm);

            JOptionPane.showMessageDialog(this,
                    "Export OK:\n" + outPrg.getName() + "\n" + outAsm.getName());
        } catch (Exception ex) {
            ex.printStackTrace();
            JOptionPane.showMessageDialog(this,
                    "Export error: " + ex.getMessage(),
                    "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

    private void clearGfxAll() {
        for (int y = 0; y < 200; y++)
            for (int x = 0; x < 160; x++)
                pic.setPixel2bpp(x, y, 0);
        for (int y = 0; y < pic.getYs(); y++) {
            pic.getFF15Line()[y] = 0;
            pic.getFF16Line()[y] = 0;
        }
        for (int y = 0; y < 200; y++)
            for (int x = 0; x < 160; x++) {
                pic.setAuxColorAt(x, y, 0, 0);
                pic.setAuxColorAt(x, y, 1, 0);
            }
        refreshStatusAndRepaint();
    }

    private void refillGfxColorMapsSelective(boolean doFF15, boolean doAUX1, boolean doAUX0, boolean doFF16,
                                             int ff15Idx, int aux1Idx, int aux0Idx, int ff16Idx) {
        if (doFF15 || doFF16) {
            for (int y = 0; y < pic.getYs(); y++) {
                if (doFF15) pic.getFF15Line()[y] = (byte) (ff15Idx & 0xFF);
                if (doFF16) pic.getFF16Line()[y] = (byte) (ff16Idx & 0xFF);
            }
        }
        if (doAUX0 || doAUX1) {
            for (int y = 0; y < 200; y++)
                for (int x = 0; x < 160; x++) {
                    if (doAUX0) pic.setAuxColorAt(x, y, 0, aux0Idx & 0xFF);
                    if (doAUX1) pic.setAuxColorAt(x, y, 1, aux1Idx & 0xFF);
                }
        }
        refreshStatusAndRepaint();
    }

    // --------------------- Segéd UI osztályok (swatch+hex) ------------------
    static class Swatch extends JPanel {
        private int index;
        private Runnable onClick;
        Swatch(int idx) {
            setPreferredSize(new Dimension(40, 24));
            setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
            setIndex(idx);
            addMouseListener(new java.awt.event.MouseAdapter() {
                @Override public void mouseClicked(java.awt.event.MouseEvent e) {
                    if (onClick != null) onClick.run();
                }
            });
            setToolTipText("Click to choose color…");
        }
        void setOnClick(Runnable r) { this.onClick = r; }
        void setIndex(int idx) { this.index = (idx & 0xFF); setBackground(Plus4Palette.getColor(this.index)); repaint(); }
        int  getIndex() { return index; }
    }

    static class SwatchHex {
        final JPanel panel = new JPanel(new BorderLayout(6,0));
        final Swatch sw;
        final JLabel hex = new JLabel();
        SwatchHex(int idx) {
            sw = new Swatch(idx);
            hex.setText(String.format("$%02X", idx & 0xFF));
            panel.add(sw,  BorderLayout.WEST);
            panel.add(hex, BorderLayout.CENTER);
        }
        void setOnClick(Runnable r) { sw.setOnClick(() -> { r.run(); hex.setText(String.format("$%02X", sw.getIndex()&0xFF)); }); }
        void setIndex(int idx) { sw.setIndex(idx); hex.setText(String.format("$%02X", sw.getIndex()&0xFF)); }
        int  getIndex() { return sw.getIndex(); }
    }

    static class ColCell {
        final JPanel panel = new JPanel();
        final JCheckBox ckA0 = new JCheckBox("A0", true);
        final JCheckBox ckA1 = new JCheckBox("A1", true);
        final SwatchHex swAux0;
        final SwatchHex swAux1;
        ColCell(int col, int a0, int a1) {
            panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
            panel.setBorder(new EmptyBorder(4,4,4,4));
            JLabel lab = new JLabel(String.valueOf(col));
            lab.setAlignmentX(Component.LEFT_ALIGNMENT);
            panel.add(lab);
            panel.add(Box.createVerticalStrut(4));

            swAux0 = new SwatchHex(a0);
            swAux1 = new SwatchHex(a1);
            swAux0.sw.setToolTipText("AUX0 $" + String.format("%02X", a0 & 0xFF));
            swAux1.sw.setToolTipText("AUX1 $" + String.format("%02X", a1 & 0xFF));

            JPanel r0 = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 0));
            r0.add(ckA0); r0.add(swAux0.panel);
            JPanel r1 = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 0));
            r1.add(ckA1); r1.add(swAux1.panel);

            r0.setAlignmentX(Component.LEFT_ALIGNMENT);
            r1.setAlignmentX(Component.LEFT_ALIGNMENT);

            panel.add(r0);
            panel.add(r1);
        }
    }
    // -----------------------------------------------------------------------

    private JButton bigButton(String text) {
        JButton b = new JButton(text);
        b.setFocusPainted(false);
        b.setFont(b.getFont().deriveFont(Font.BOLD, 14f));
        b.setPreferredSize(new Dimension(240, 40));
        return b;
    }

        // Szekció-fejléc (titled separator): egyszínű vonal + középen cím
    private JComponent makeSectionHeader(String title) {
        JPanel p = new JPanel();
        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
        p.setBorder(new EmptyBorder(6, 0, 4, 0)); //6, 0, 4, 0

        // Egyszínű vékony vonal komponens (nem LAF-függő JSeparator)
        JComponent leftLine = new JComponent() {
            @Override protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(new Color(110, 110, 110)); // fix szín
                int y = getHeight() / 2;
                g.drawLine(0, y, getWidth(), y);
            }
        };
        leftLine.setPreferredSize(new Dimension(0, 1));

        JComponent rightLine = new JComponent() {
            @Override protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(new Color(110, 110, 110)); // ugyanaz a fix szín
                int y = getHeight() / 2;
                g.drawLine(0, y, getWidth(), y);
            }
        };
        rightLine.setPreferredSize(new Dimension(0, 1));

        JLabel lbl = new JLabel(title);
        // Itt nagyítjuk a fontot és félkövérre tesszük
        lbl.setFont(lbl.getFont().deriveFont(Font.BOLD, 15f));
        lbl.setBorder(new EmptyBorder(0, 8, 0, 8));

        p.add(leftLine);
        p.add(lbl);
        p.add(rightLine);

        return p;
    }


    private JMenuBar buildMenu() {
        JMenuBar mb = new JMenuBar();
        JMenu file = new JMenu("File");
        file.add(new AbstractAction("Exit") {
            @Override public void actionPerformed(ActionEvent e) { System.exit(0); }
        });
        mb.add(file);
        return mb;
    }

    private void refreshStatusAndRepaint() {
        String heatmapStr = "off";
        if (canvas.isHeatmapEnabled()) heatmapStr = String.valueOf(pic.getCurrentPaint() & 0xFF);

        status.setText(String.format(
                "CurY=%d  FF15=%02X  FF16=%02X  Paint=%d  aux0Paint=%02X  aux1Paint=%02X  Zoom=%d%%  Heatmap=%s",
                pic.getCurY(),
                pic.getFF15Line()[pic.getCurY()] & 0xFF,
                pic.getFF16Line()[pic.getCurY()] & 0xFF,
                pic.getCurrentPaint(),
                pic.getColmapPaintIndex2() & 0xFF,
                pic.getColmapPaintIndex3() & 0xFF,
                pic.getZoomPercent(),
                heatmapStr
        ));
        palette.repaint();
        paintPanel.repaint();
        canvas.repaint();
    }

    private static class Labeled extends JPanel {
        Labeled(String title, JComponent inner) {
            super(new BorderLayout(6,0));
            add(new JLabel(title + ": "), BorderLayout.WEST);
            add(inner, BorderLayout.CENTER);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new DFLIEditor().setVisible(true));
    }

    // ===== Paletta választó a swatchokhoz =====
    static class PaletteIndexChooser {
        static int choose(Window parent, int initialIndex) {
            final JDialog dlg = new JDialog(parent, "Choose Plus/4 color", Dialog.ModalityType.APPLICATION_MODAL);
            JPanel grid = new JPanel(new GridLayout(8, 16, 2, 2));
            grid.setBorder(new EmptyBorder(8,8,8,8));

            final int[] result = { -1 };
            int total = Plus4Palette.size();
            for (int i = 0; i < total; i++) {
                JPanel cell = new JPanel();
                cell.setBackground(Plus4Palette.getColor(i));
                cell.setPreferredSize(new Dimension(22, 18));
                cell.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
                final int idx = i;
                cell.setToolTipText(String.format("#%d (0x%02X)", idx, idx));
                cell.addMouseListener(new java.awt.event.MouseAdapter() {
                    @Override public void mouseClicked(java.awt.event.MouseEvent e) {
                        result[0] = idx;
                        dlg.dispose();
                    }
                });
                grid.add(cell);
            }

            JPanel south = new JPanel(new FlowLayout(FlowLayout.RIGHT, 8, 8));
            JButton cancel = new JButton("Cancel");
            cancel.addActionListener(e -> { result[0] = -1; dlg.dispose(); });
            south.add(cancel);

            dlg.setLayout(new BorderLayout());
            dlg.add(grid, BorderLayout.CENTER);
            dlg.add(south, BorderLayout.SOUTH);
            dlg.pack();
            dlg.setLocationRelativeTo(parent);
            dlg.setVisible(true);
            return result[0];
        }
    }
}
