/**
 *  Licensed under GPL. For more information, see
 *    http://jaxodraw.sourceforge.net/license.html
 *  or the LICENSE file in the jaxodraw distribution.
 */
package net.sf.jaxodraw.gui.panel;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import java.util.HashMap;
import java.util.Map;

import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import net.sf.jaxodraw.gui.JaxoTab;
import net.sf.jaxodraw.gui.panel.button.JaxoButtonPanel;
import net.sf.jaxodraw.io.JaxoIO;
import net.sf.jaxodraw.util.JaxoConstants;
import net.sf.jaxodraw.util.JaxoDictionary;
import net.sf.jaxodraw.util.JaxoLocalized;


/** Displays the status bar.
 * @since 2.0
 */
public class JaxoStatusBar extends JPanel implements JaxoLocalized,
    PropertyChangeListener, ChangeListener {
    private static final JaxoDictionary LANGUAGE = new JaxoDictionary(JaxoStatusBar.class);

    private static final long serialVersionUID = 7526471155622776147L;
    private static final String VERTEX = "/Vertex";
    private static final Map<Integer, String> MODE_KEYS;

    private static final int MAX_NAME_LENGTH = 46;

    static {
        MODE_KEYS = new HashMap<Integer, String>(44);
        // standby
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.STANDBY), "");
        // particle mode
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.FLINE), "/Fermion_Line");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.FLOOP), "/Fermion_Loop");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.FARC), "/Fermion_Arc");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.FBEZ), "/Fermion_Bezier");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.SLINE), "/Scalar_Line");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.SLOOP), "/Scalar_Loop");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.SARC), "/Scalar_Arc");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.SBEZ), "/Scalar_Bezier");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.GLINE), "/Ghost_Line");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.GLOOP), "/Ghost_Loop");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.GARC), "/Ghost_Arc");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.GBEZ), "/Ghost_Bezier");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.PLINE), "/Photon_Line");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.PLOOP), "/Photon_Loop");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.PARC), "/Photon_Arc");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.PBEZ), "/Photon_Bezier");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.GLLINE), "/Gluon_Line");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.GLLOOP), "/Gluon_Loop");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.GLARC), "/Gluon_Arc");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.GLBEZ), "/Gluon_Bezier");
        // edit modes
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.MOVE), "/Move");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.RESIZE), "/Resize");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.COLOR), "/Color");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.EDIT), "/Edit");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.DUPLICATE), "/Duplicate");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.BACKGROUND), "/Background");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.FOREGROUND), "/Foreground");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.DELETE), "/Delete");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.UNGROUP), "/Ungroup");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.SELECT), "/Select");
        // grid modes
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.ZOOM), "/Zoom");
        // misc modes
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.ZIGZAG), "/Zigzag");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.BOX), "/Box");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.BLOB), "/Blob");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.VERTEX), VERTEX);
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.VERTEXT1), VERTEX);
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.VERTEXT2), VERTEX);
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.VERTEXT3), VERTEX);
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.VERTEXT4), VERTEX);
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.VERTEXT5), VERTEX);
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.VERTEXT6), VERTEX);
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.TEXT), "/Text");
        MODE_KEYS.put(Integer.valueOf(JaxoConstants.LATEX), "/LaTex");
    }

    private final JLabel controlFlag;
    private final JLabel coordFlag;
    private final JLabel fileFlag;
    private String currentFile = "";
    private String currentModeKey = "";

    /** Constructor: just calls this(null). */
    public JaxoStatusBar() {
        this(null);
    }

    /** Constructor: displays the panel containing the current mode and the panel
     * containing the coordinates.
     * @param tab A JaxoTab (may be null). If not null, the file flag text will
     * be initialized with the saveFileName of the tab, and this flag panel
     * is registered as a ChangeListener (for eventual tab changes).
     */
    public JaxoStatusBar(final JaxoTab tab) {
        super(null, false);

        setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));

        controlFlag = new JLabel(currentModeKey, JLabel.CENTER);

        final JPanel controlFlagPanel = new JPanel(new BorderLayout(), false);
        controlFlagPanel.add(controlFlag, BorderLayout.CENTER);
        controlFlagPanel.setBorder(JaxoButtonPanel.RAISED_ETCHED_BORDER);
        controlFlagPanel.setMinimumSize(new Dimension(270, 30));
        controlFlagPanel.setPreferredSize(new Dimension(270, 30));

        coordFlag = new JLabel("", JLabel.CENTER);

        final JPanel coordFlagPanel = new JPanel(new BorderLayout(), false);
        coordFlagPanel.add(coordFlag, BorderLayout.CENTER);
        coordFlagPanel.setBorder(JaxoButtonPanel.RAISED_ETCHED_BORDER);
        coordFlagPanel.setMinimumSize(new Dimension(170, 30));
        coordFlagPanel.setPreferredSize(new Dimension(170, 30));

        fileFlag = new JLabel(currentFile, JLabel.CENTER);

        final JPanel fileFlagPanel = new JPanel(new BorderLayout(), false);
        fileFlagPanel.add(fileFlag, BorderLayout.CENTER);
        fileFlagPanel.setBorder(JaxoButtonPanel.RAISED_ETCHED_BORDER);
        fileFlagPanel.setMinimumSize(new Dimension(390, 30));
        fileFlagPanel.setPreferredSize(new Dimension(490, 30));

        add(fileFlagPanel);
        add(controlFlagPanel);
        add(coordFlagPanel);

        if (tab != null) {
            // for SaveFileName
            tab.addChangeListener(this);
            currentFile = tab.getSaveFileName();
        }

        updateFileFlagText();
        updateCurrentModeText();
        updateMouseLocation(null);
    }

    /**
     * Applies a property change event.
     *
     * @param e the change event.
     */
    public void propertyChange(final PropertyChangeEvent e) {
        final String name = e.getPropertyName();

        if ("Jaxo.mouseLocation".equals(name)) {
            updateMouseLocation((Point) e.getNewValue());
        } else if ("Jaxo.mode".equals(name)) {
            currentModeKey = MODE_KEYS.get((Integer) e.getNewValue());
            updateCurrentModeText();
        } else if ("Jaxo.selectedTab".equals(name)) {
            final JaxoTab old = (JaxoTab) e.getOldValue();

            if (old != null) {
                old.removeChangeListener(this);
            }

            final JaxoTab t = (JaxoTab) e.getNewValue();

            if (t != null) {
                t.addChangeListener(this);
                currentFile = t.getSaveFileName();
            }

            updateFileFlagText();
        }
    }

    /**
     * Apply a change event.
     *
     * @param e The change event.
     */
    public void stateChanged(final ChangeEvent e) {
        if (e.getSource() instanceof JaxoTab) {
            currentFile = ((JaxoTab) e.getSource()).getSaveFileName();
            updateFileFlagText();
        }
    }

    /** Returns the text that is currently shown in the mode panel.
     * @return The current mode text.
     */
    public String getCurrentModeText() {
        return controlFlag.getText();
    }

    /** Returns the text that is currently shown in the file panel.
     * @return The current file text.
     */
    public String getCurrentFileText() {
        return fileFlag.getText();
    }

    /** Returns the text that is currently shown in the coordinates panel.
     * @return The current mouse location text.
     */
    public String getCurrentCoordinateText() {
        return coordFlag.getText();
    }

    /** {@inheritDoc} */
    public final void updateLanguage() {
        updateFileFlagText();
        updateCurrentModeText();
    }

    // private methods

    /** Sets the current mode in the flag panel. */
    private void updateCurrentModeText() {
        final String noControl = LANGUAGE.value("mode_none");
        final String currentModeText = LANGUAGE.value(currentModeKey);
        controlFlag.setText(("".equals(currentModeText)) ? noControl
                                                         : LANGUAGE
            .message("mode%0", currentModeText));
    }

    private void updateMouseLocation(final Point value) {
        final String noMouseCoordinates =
            LANGUAGE.value("mouseCoordinates_none");
        coordFlag.setText((value == null) ? noMouseCoordinates
                                          : LANGUAGE.message(
                "mouseCoordinates%0%1", Integer.valueOf(value.x),
                Integer.valueOf(value.y)));
    }

    private void updateFileFlagText() {
        String filename = currentFile;
        if (filename.length() == 0) {
            filename = JaxoIO.currentDirectoryString();
        } else {
            filename = JaxoIO.directoryString(filename);
        }

        if (filename.length() > MAX_NAME_LENGTH) {
            fileFlag.setText(LANGUAGE.message(
                    "directory%0ending",
                    filename.substring(filename.length() - MAX_NAME_LENGTH)));
        } else {
            fileFlag.setText(LANGUAGE.message("directory%0",
                    filename));
        }
    }
}
