package at.oefai.aaa;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.EventQueue;
import java.awt.event.WindowAdapter;
import java.io.File;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JSplitPane;
import javax.swing.WindowConstants;

import at.oefai.aaa.gui.ControlerPanel;
import at.oefai.aaa.gui.DetailPanel;
import at.oefai.aaa.gui.StatusPanel;
import at.oefai.aaa.gui.WorldPanel;

/**
 * The basic component displaying the whole agent action.
 * @author Stefan Rank
 */
class AAAViewerFrame extends JFrame implements IGUIMediator {
    private static final String FRAME_TITLE = "Act Aff Act Viewer";
    private static final int DEFAULT_WIDTH = 600;
    private static final int DEFAULT_HEIGHT = 450;

    /**
     * A simple Runnable to safely change FrameSize after creation.
     * (see Core Java Technologies Tech Tips, December 8, 2003)
     * @author Stefan Rank
     */
    private static class SizeSetterAndFrameShower implements Runnable {
        private final AAAViewerFrame frame;
        public SizeSetterAndFrameShower(final AAAViewerFrame pFrame) {
            this.frame = pFrame;
        }
        public void run() {
            this.frame.pack();
            this.frame.resetScreenSize();
            this.frame.setVisible(true);
        }
    }

    private ControlerPanel controlerPane = null;
    private StatusPanel statusBar = new StatusPanel("Nothing done yet");
    private WorldPanel worldPane = null;
    private DetailPanel detailPane = new DetailPanel();
    private JSplitPane content = null;

    private JFileChooser fileChooser = new JFileChooser();
    private SimpleFileFilter aaaSnapshotFilter =
            new SimpleFileFilter(new String[] {"aaaSnapshot"}, "ActAffAct Snapshot");
    private SimpleFileFilter aaaStageOrSnapshotFilter =
            new SimpleFileFilter(new String[] {"aaaStage", "aaaSnapshot"}, "ActAffAct Stage or Snapshot");

    /** Creates new JFrame, the main windows for the ActAffAct Viewer Application. */
    AAAViewerFrame(final IState stateMan, final WindowAdapter windowMan,
                   final Component animDisplay) {
        // filechooser setup
        this.fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        this.fileChooser.setMultiSelectionEnabled(false);
        this.fileChooser.setAcceptAllFileFilterUsed(false);
        String userdir = System.getProperty("user.dir");
        if (userdir != null) {
            File f = new File(userdir + File.separator + "aaas");
            this.fileChooser.setCurrentDirectory(f);
        }

        setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);

        // controllerpanel and worldpanel have messages to send
        this.controlerPane = new ControlerPanel(stateMan); // statechanges
        this.worldPane = new WorldPanel(animDisplay); // displays world graphics

        addWindowListener(windowMan); // windowevents
        initGUI();
    }

    /** This method is called from within the constructor to initialize the form. */
    private void initGUI() {
        setTitle(FRAME_TITLE);
        getContentPane().setLayout(new BorderLayout());
        // controlerpane, world and detail as splitpane, statusBar
        getContentPane().add(this.controlerPane, BorderLayout.NORTH);
        this.content = new JSplitPane(JSplitPane.VERTICAL_SPLIT, this.worldPane, this.detailPane);
        // use the defaultsize for min and preferred
        Dimension defaultSize = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        this.content.setMinimumSize(defaultSize);
        this.content.setPreferredSize(defaultSize);
        getContentPane().add(this.content, BorderLayout.CENTER);
        getContentPane().add(this.statusBar, BorderLayout.SOUTH);
    }

    /** Call from creating thread to safely show in EventQueue Thread.
     * (see Core Java Technologies Tech Tips, December 8, 2003)*/
    public void scheduleFirstShow() {
        EventQueue.invokeLater(new SizeSetterAndFrameShower(this));
    }

    private void resetScreenSize() {
        // get last dimensions or set reasonable ones
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(this.getGraphicsConfiguration());
        // reduce by insets
        screenSize.width = screenSize.width - screenInsets.left - screenInsets.right;
        screenSize.height = screenSize.height - screenInsets.top - screenInsets.bottom;

        Dimension frameSize = this.getSize();
        int frameHeight = AppPrefs.getFrameHeight();
        int frameWidth = AppPrefs.getFrameWidth();
        if (frameHeight > 0 && frameWidth > 0) {
            frameSize = new Dimension(frameWidth, frameHeight);
        }
        frameSize.height = ((frameSize.height > screenSize.height) ? screenSize.height : frameSize.height);
        frameSize.width = ((frameSize.width > screenSize.width) ? screenSize.width : frameSize.width);

        //Center the frame on screen
        this.setBounds(screenInsets.left + (screenSize.width - frameSize.width) / 2,
                       screenInsets.top + (screenSize.height - frameSize.height) / 2,
                       frameSize.width, frameSize.height);
    }

    /** whom to tell about new stagedetails. */
    public IDetailSink getDetailSink() {
        return this.detailPane;
    }

    /** hook should be called when the frame is visible for the first time. */
    public void justOpened() {
        this.content.setDividerLocation(0.5);
    }

    public void setPaused() {
        this.controlerPane.setPaused();
    }

    public void setRunning() {
        this.controlerPane.setRunning();
    }


    public File getFileToLoad() {
        this.fileChooser.setFileFilter(this.aaaStageOrSnapshotFilter);
        int returnVal = this.fileChooser.showOpenDialog(this);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            return this.fileChooser.getSelectedFile();
        }
        return null;
    }

    public File getFileToSave() {
        this.fileChooser.setFileFilter(this.aaaSnapshotFilter);
        int returnVal = this.fileChooser.showOpenDialog(this);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            return this.fileChooser.getSelectedFile();
        }
        return null;
    }

    public void deactivateGUI() {
        this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        this.setEnabled(false);
    }

    public void activateGUI() {
        this.setEnabled(true);
        this.getContentPane().setCursor(Cursor.getDefaultCursor());
    }

    public void deactivateDetailGUI() {
        this.detailPane.setChildrenEnabled(false);
    }

    public void activateDetailGUI() {
        this.detailPane.setChildrenEnabled(true);
    }

    public void cleanUp() {
        this.detailPane.clearModels();
    }


    public void showException(final Exception ex) {
        String s = ex.getMessage();
        Throwable cause = ex.getCause();
        if (cause != null) { // only one cause considered here
            s += "\nCause: " + cause;
        }
        JOptionPane.showMessageDialog(this, s);
        ex.printStackTrace();
    }

    public void showStatus(final String s) {
        this.statusBar.setStatusText(s);
    }

    public void showStatus(final String s, final File f) {
        if (f != null) {
            this.setTitle(FRAME_TITLE + " - " + f.getPath());
        }
        this.showStatus(s);
    }

    public void showGraphicsStatus(final String s) {
        this.statusBar.setGraphicsText(s);
    }


}
