/*
 * $Id$
 *
 * Copyright 1996-2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */
package com.sun.javatest.exec;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.ResourceBundle;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.Timer;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import javax.swing.text.JTextComponent;

import com.sun.javatest.Harness;
import com.sun.javatest.Parameters;
import com.sun.javatest.TestResult;
import com.sun.javatest.tool.Preferences;
import com.sun.javatest.tool.UIFactory;

/**
 * The panel at the bottom of exec tool.
 * This class manages the insertion, deletion, and rearrangement of any small
 * monitors.  It also forwards informational text messages to the user.
 */

class MessageStrip extends JSplitPane 
    implements Harness.Observer, ComponentListener 
{
    MessageStrip(UIFactory uif, Monitor[] monitors, MonitorState state,
		 ActionListener zoomListener) {
	this.uif = uif;
	this.monitors = monitors;
	this.state = state;
	this.zoomListener = zoomListener;

	setOrientation(JSplitPane.HORIZONTAL_SPLIT);

	// left side is a simple text field
	leftField = uif.createOutputField("strip.msg");
	leftField.setOpaque(false);

	setLeftComponent(leftField);
	setRightComponent(createRightPanel());

	setDividerSize(5);
	setEnabled(true);
	addComponentListener(this);
	uif.setAccessibleInfo(this, "strip");
	setDividerLocation(0.60d);
    }

    // which to display while running tests
    void setRunningMonitor(Monitor m) {
	for (int i = 0; i < monitors.length; i++)
	    if (monitors[i] == m) {
		runningMonitor = i;
		break;
	    }
    }

    // which to display while not running tests
    // these are not currently intended to be called after initialization
    void setIdleMonitor(Monitor m) {
	for (int i = 0; i < monitors.length; i++)
	    if (monitors[i] == m) {
		idleMonitor = i;
		break;
	    }
	
	setMonitor(idleMonitor);
    }

    void setMonitor(final int index) {
	if (index < 0)
	    return;

	if (!EventQueue.isDispatchThread()) {
	    EventQueue.invokeLater(new Runnable() {
		public void run() {
		    setMonitor(index);
		}
	    });
	    return;
	}

	if (index < monitors.length) {
	    currMonitor = index;
	    monitorCards.show(rightPanel, monitors[index].getSmallMonitorName());
	    selector.setSelectedItem(monitors[index]);
	    validate();	    // required for correct repaint

	    // write to preferences
	    Preferences p = Preferences.access();
	    p.setPreference(MINI_PREF, monitors[index].getClass().getName());
	}
    }

    // Harness.Observer ...
    // anything that happens here must be switched on to the event thread

    public void startingTestRun(Parameters params) {
	setText(leftField, uif.getI18NString("strip.start"));
	setMonitor(runningMonitor);

	if (clearTimer == null)
	    clearTimer = new Timer(CLEAR_TIMEOUT, new ActionListener() {
		public void actionPerformed(ActionEvent evt) {
		    setText(leftField, "");
		}
	    });
	clearTimer.start();
    }

    public void startingTest(TestResult tr) {
	setText(leftField, uif.getI18NString("strip.running", tr.getTestName()));
    }

    public void finishedTest(TestResult tr) {
    }

    public void stoppingTestRun() {
	setText(leftField, uif.getI18NString("strip.stop"));
    }

    public void finishedTesting() {
	setText(leftField, uif.getI18NString("strip.cleanup"));
	setMonitor(idleMonitor);
    }

    public void finishedTestRun(boolean allOk) {
	setText(leftField, uif.getI18NString("strip.finish"));
	if (clearTimer != null)
            clearTimer.stop();
    }

    public void error(String msg) {
    }

    void showMessage(ResourceBundle msgs, String key) {
	setText(leftField, msgs.getString(key));
    }

    private void setText(JTextComponent comp, String text) {
	if (EventQueue.isDispatchThread())
	    comp.setText(text);
	else
	    EventQueue.invokeLater(new BranchPanel.TextUpdater(comp, text, uif));
    }

    private JPopupMenu createMenu() {
	JPopupMenu menu = uif.createPopupMenu("strip.menu");
	for (int i = 0; i < monitors.length; i++) {
	    JMenuItem mi = uif.createLiteralMenuItem(
		monitors[i].getSmallMonitorName(), actionListener);
	    mi.setActionCommand(Integer.toString(i));
	    menu.add(mi);
	}   // for


	return menu;
    }

    private JComponent createRightPanel() {
	JPanel right = uif.createPanel("strip.right", new GridBagLayout(), false);

	selector = uif.createLiteralChoice("strip.sel", monitors);
        uif.setAccessibleName(selector, "strip.sel");
	selector.addActionListener(actionListener);
	selector.setRenderer(new BasicComboBoxRenderer() {
		public Component getListCellRendererComponent(JList list, Object value,
			    int index, boolean isSelected, boolean cellHasFocus) {
		    Component c = super.getListCellRendererComponent(list, value,
						index, isSelected, cellHasFocus);
		    try {
			JLabel lab = (JLabel)c;
			if (value instanceof Monitor)
			    lab.setText(((Monitor)value).getSmallMonitorName());
		    }
		    catch (ClassCastException e) {
		    }
		    
		    return c;
		}
	    });

	GridBagConstraints gbc = new GridBagConstraints();
	gbc.weightx = 2.0d;
	gbc.gridx = 0;
	gbc.gridy = 0;
	gbc.fill = GridBagConstraints.HORIZONTAL;
	gbc.anchor = GridBagConstraints.WEST;

	monitorCards = new CardLayout();
	rightPanel = uif.createPanel("strip.", monitorCards, false);
	for (int i = 0; i < monitors.length; i++)
	    rightPanel.add(monitors[i].getSmallMonitorName(), monitors[i].getSmallMonitor());
	currMonitor = getDefaultSmallMonitor();
	monitorCards.show(rightPanel, monitors[currMonitor].getSmallMonitorName());

	JPanel tmpPanel = uif.createPanel("monitor container", new BorderLayout(), false);
	tmpPanel.add(selector, BorderLayout.WEST);
	tmpPanel.add(rightPanel, BorderLayout.CENTER);

	right.add(tmpPanel, gbc);

	gbc.gridx = 1;
	gbc.weightx = 0.0d;
	/*
	gbc.anchor = GridBagConstraints.EAST;
	selectButt = uif.createIconButton("strip.drop");
	selectButt.addMouseListener(popupListener);
	selectButt.addActionListener(popupListener);
	uif.setAccessibleName(selectButt, "strip.drop");

	gbc.gridx = 2;
	*/
	magButt = uif.createIconButton("strip.magnify");
	magButt.addActionListener(actionListener);
	uif.setAccessibleName(magButt, "strip.magnify");

	JToolBar tb = uif.createToolBar("strip.tb",
			    new JButton[] {magButt});
	tb.setFloatable(false);
	tb.setBorderPainted(true);

	right.add(tb, gbc);

	right.setEnabled(true);
	right.setVisible(true);
	rightPanel.setEnabled(true);
	rightPanel.setVisible(true);

	return right;
    }

    // --------------- private --------------------

    /** 
     * Determine by whatever means, which monitor should be shown.
     */
    private int getDefaultSmallMonitor() {
	if (idleMonitor != -1)
	    return idleMonitor;
	else {
	    Preferences p = Preferences.access();
	    String prefSetting = p.getPreference(MINI_PREF, null);

	    int index = 0;

	    // don't do anything if there's no monitors or no pref.
	    if (prefSetting != null && monitors != null) {
		try {
		    for (int i = 0; i < monitors.length; i++) {
			if (monitors[i].getClass().getName().equals(prefSetting)) {
			    index = i;
			    break;
			}
		    }	// for
		}   // try
		catch (NumberFormatException excep) {
		    // ok, whatever...
		    index = 0;
		}
	    }   // outer if
	    // whatever happens, zero is the default

	    return index;
	}
    }

    private int getMonitorIndex(Monitor m) {
	if (monitors == null || monitors.length == 0)
	    return -1;
	
	for (int i = 0; i < monitors.length; i++)
	    if (monitors[i] == m)
		return i;

	return -1;
    }

    // ---------- ComponentListener ----------
    public void componentHidden(ComponentEvent e) { }
    public void componentMoved(ComponentEvent e) { }
    public void componentResized(ComponentEvent e) {
	setDividerLocation(0.70d);
    }
    public void componentShown(ComponentEvent e) { }

    private JTextField leftField;
    private JPanel rightPanel;
    private JButton selectButt;
    private JButton magButt;

    private JComboBox selector;
    private JPopupMenu popMenu;
    private ActionListener actionListener = new SelectionListener();
    private ActionListener zoomListener;
    private Monitor[] monitors;
    private MonitorState state;
    private int currMonitor;
    private CardLayout monitorCards;
    private int runningMonitor = -1;
    private int idleMonitor = -1;
    private Timer clearTimer;
    private static final int CLEAR_TIMEOUT = 5000;  // time before msg is cleared

    private UIFactory uif;

    private static final String MINI_PREF = "exec.monitorstrip.mini";

    class SelectionListener implements ActionListener {
	public void actionPerformed(ActionEvent e) {
	    Object source = e.getSource();

	    if (source == magButt) {
		zoomListener.actionPerformed(e);
	    }
	    else if (source == selector) {
		Object item = selector.getSelectedItem();
		setMonitor(getMonitorIndex((Monitor)item));
	    }
	    else if (source instanceof JMenuItem) {
		try {
		    int index = Integer.parseInt(e.getActionCommand());

		    // no change, or index is out of valid range for some reason
		    if (currMonitor == index || index >= monitors.length)
			return;

		    setMonitor(index);
		}   // try
		catch (NumberFormatException excep) {
		    // ignore event
		}	// catch
	    }
	}   // actionPerformed()
    }

}

