
package paavohuh.sourcream.ui;

import java.awt.*;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import javax.swing.*;
import org.apache.commons.io.FileUtils;
import paavohuh.sourcream.*;
import paavohuh.sourcream.configuration.*;
import paavohuh.sourcream.emulation.*;

/**
 * The main window of the emulator.
 */
public class MainWindow extends JFrame {
    
    private final Device device;
    private EmulatorPanel emulatorPanel;
    private JMenuItem pauseContinueItem;
    private final Configuration config;

    /**
     * Creates a new main window.
     * @param config The configuration.
     */
    public MainWindow(Configuration config) {
        this.config = config;
        this.device = new Device(config);
        
        InputMapper mapper = new InputMapper(device, config);
        KeyboardFocusManager
            .getCurrentKeyboardFocusManager()
            .addKeyEventDispatcher(mapper);
        
        initComponents();
        setDefaultBuffer();
        device.onUpdateGraphics(emulatorPanel::updateScreenBuffer);
    }

    public EmulatorPanel getEmulatorPanel() {
        return emulatorPanel;
    }
    
    private void initComponents() {
        setTitle("SourCream");
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout());
        
        JMenuBar menubar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        
        JMenuItem item = new JMenuItem("Load ROM...");
        item.addActionListener(event -> {
            JFileChooser chooser = new JFileChooser();
            chooser.setCurrentDirectory(new File("../roms"));
            if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
                try {
                    loadProgram(FileUtils.readFileToByteArray(chooser.getSelectedFile()));
                } catch (IOException ex) {
                    JOptionPane.showMessageDialog(
                        this,
                        "Loading ROM " + chooser.getSelectedFile().getName() + " failed.",
                        "Error while loading ROM", 
                        JOptionPane.ERROR_MESSAGE);
                }
            }
        });
        
        fileMenu.add(item);
        fileMenu.addSeparator();
        
        item = new JMenuItem("Exit");
        item.addActionListener(event -> {
            dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
        });
        fileMenu.add(item);
        menubar.add(fileMenu);
        
        JMenu emulationMenu = new JMenu("Emulation");
        pauseContinueItem = new JMenuItem("Not running");
        pauseContinueItem.setEnabled(false);
        pauseContinueItem.addActionListener(event -> {
            if (device.isRunning()) {
                pause();
            } else {
                start();
            }
        });
        emulationMenu.add(pauseContinueItem);
        menubar.add(emulationMenu);
        
        JMenu settingsMenu = new JMenu("Options");
        
        item = new JMenuItem("Configuration...");
        item.addActionListener(event -> {
            device.stop();
            ConfigWindow window = new ConfigWindow(this, config);
            window.setVisible(true);
            device.start();
            emulatorPanel.updateBounds();
            pack();
        });
        
        settingsMenu.add(item);
        menubar.add(settingsMenu);
        add(menubar, BorderLayout.NORTH);
        
        emulatorPanel = new EmulatorPanel(config);
        add(emulatorPanel, BorderLayout.SOUTH);
        pack();
        setVisible(true);
    }
    
    private void setDefaultBuffer() {
        emulatorPanel.updateScreenBuffer(Resource.getLogo());
    }
    
    /**
     * Loads a program to the Chip-8 VM.
     * @param program 
     */
    public void loadProgram(byte[] program) {
        device.stop();  
        device.setState(new State(config).withProgram(program));
        pauseContinueItem.setEnabled(true);
        start();
    }
    
    /**
     * Starts executing the Chip-8 VM.
     */
    public void start() {
        device.start();
        pauseContinueItem.setText("Pause");

    }
    
    /**
     * Pauses the Chip-8 VM.
     */
    public void pause() {
        device.stop();
        pauseContinueItem.setText("Continue");
    }
}

@@ -41,24 +41,90 @@
 java.awt.*;%0A
+import java.awt.event.InputEvent;%0Aimport java.awt.event.KeyEvent;%0A
 import java.
@@ -142,24 +142,24 @@
 indowEvent;%0A
-
 import java.
@@ -613,16 +613,105 @@
  config;
+%0A    %0A    private final State%5B%5D saveStates;%0A    private final JMenuItem%5B%5D loadStateItems;
 %0A%0A    /*
@@ -904,32 +904,120 @@
 Device(config);%0A
+        this.saveStates = new State%5B8%5D;%0A        this.loadStateItems = new JMenuItem%5B8%5D;%0A
         %0A       
@@ -3275,33 +3275,24 @@
 %22Options%22);%0A
-        %0A
         item
@@ -3675,24 +3675,1218 @@
 tingsMenu);%0A
+        %0A        JMenu saveStateMenu = new JMenu(%22Save states%22);%0A        %0A        for (int i = 1; i %3C= saveStates.length; i++) %7B%0A            final int index = i;%0A            JMenuItem saveItem = new JMenuItem(%22Save to slot %22 + i);%0A            saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1 + (i - 1), 0));%0A            saveItem.addActionListener(event -%3E %7B%0A                saveStates%5Bindex - 1%5D = device.getState();%0A                loadStateItems%5Bindex - 1%5D.setEnabled(true);%0A            %7D);%0A            saveStateMenu.add(saveItem);%0A        %7D%0A        %0A        saveStateMenu.addSeparator();%0A        %0A        for (int i = 1; i %3C= saveStates.length; i++) %7B%0A            final int index = i;%0A            JMenuItem loadItem = new JMenuItem(%22Load slot %22 + i);%0A            loadItem.setEnabled(false);%0A            loadItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1 + (i - 1), InputEvent.CTRL_DOWN_MASK));%0A            loadItem.addActionListener(event -%3E %7B%0A                device.setState(saveStates%5Bindex - 1%5D);%0A            %7D);%0A            saveStateMenu.add(loadItem);%0A            loadStateItems%5Bi - 1%5D = loadItem;%0A        %7D%0A        %0A        menubar.add(saveStateMenu);%0A        %0A
         add(
@@ -4915,25 +4915,16 @@
 NORTH);%0A
-        %0A
         

Implement save states