// CommonBoard.java
//
// Created: October 2005
//
// This file is a component of the BioMoby project.
// Copyright Martin Senger (martin.senger@gmail.com).
//

package org.biomoby.service.dashboard;

import org.tulsoft.tools.gui.SwingUtils;
import org.biomoby.shared.event.NotificationEvent;
import org.biomoby.shared.event.NotificationListener;

import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JProgressBar;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;

/**
 * This is a simple graphical widget combining together a tree (a
 * subclass of {@link org.biomoby.service.dashboard.CommonTree}) and a
 * progress bar showing how the tree is being loaded. The progress bar
 * has a cancel button that allows to terminate loading
 * prematurely. The tree represents a part of a Biomoby registry. <p>
 *
 * It is also a listener of events notifying about the loading
 * process.  It reflects this events appropriately in the progress
 * bar, and in some cases it propagates these events to the property
 * channel (usually they are caught and displayed in Dashboard's
 * status bar). <p>
 *
 * @author <A HREF="mailto:martin.senger@gmail.com">Martin Senger</A>
 * @version $Id: CommonBoard.java,v 1.9 2005/11/22 18:03:28 senger Exp $
 */

abstract public class CommonBoard
    extends JPanel
    implements DashboardProperties, NotificationListener {

    protected RegistryModel model;
    protected PropertyChannel channel;

    // each board has its identity (it helps in logs)
    private static int allBoardCounter = 0;
    protected int boardId;

    // components
    protected JLabel treeTitle;
    protected JProgressBarWithCancel pBar;
    protected CommonTree tree;
    protected GridBagConstraints gbc;

    /*********************************************************************
     * Constructor. <p>
     *
     * @param model gives access to a Biomoby registry
     * @param channel is used to fire property-change events
     ********************************************************************/
    protected CommonBoard (RegistryModel model,
			   PropertyChannel channel) {
	this.model = model;
	this.channel = channel;
	treeTitle = new JLabel ("");
	boardId = ++allBoardCounter;
    }

    /*********************************************************************
     * Update the underlying tree.
     ********************************************************************/
    public void updateTree (int howSorted) {
	tree.update (howSorted, null);
    }

    /*********************************************************************
     * An empty mplementation of a NotificationListener intereface.
     ********************************************************************/
    abstract public void notified (NotificationEvent event);

    /*********************************************************************
     * Put together all components (they should be created by now).
     ********************************************************************/
    protected void createItself() {
	setLayout (new GridBagLayout());
 	SwingUtils.addComponent (this, treeTitle,         0, 0, 1, 1, AbstractPanel.HORI, AbstractPanel.WEST, 1.0, 0.0);
 	SwingUtils.addComponent (this, tree.scrollable(), 0, 1, 1, 1, AbstractPanel.BOTH, AbstractPanel.WEST, 1.0, 1.0);
	gbc = ((GridBagLayout)getLayout()).getConstraints (treeTitle);
    }

    /*********************************************************************
     * Create a progress bar in its initial stage (when we do not know
     * yet how many items will be loaded). Add there an action
     * listener that will callback the underlying registry model using
     * given 'callbackSignal'.
     ********************************************************************/
    protected synchronized void createProgressBar (int callbackSignal) {
	pBar = new JProgressBarWithCancel();
	JProgressBar pB = pBar.get();
	pB.setStringPainted (true);
	pB.setString ("");
	pB.setIndeterminate (true);
	final int signal = callbackSignal;
	pBar.addActionListener (new ActionListener() {
		public void actionPerformed (ActionEvent e) {
		    model.callback (signal);
		    removeProgressBar();
		}
	    });
    }

    /*********************************************************************
     * Replace the first component by the current progress bar.
     ********************************************************************/
    protected synchronized void insertProgressBar() {
	if (pBar != null) {
	    this.remove (0);
	    this.addImpl (pBar, gbc, 0);
	    this.validate();
	}
    }

    /*********************************************************************
     * Set the maximum value into the current progress bar, change it
     * to a mode when it shows percentage of the progress.
     ********************************************************************/
    protected synchronized void calibrateProgressBar (int maximum) {
	if (pBar != null) {
	    if (maximum > 0) {
		JProgressBar pB = pBar.get();
		pB.setMinimum (0);
		pB.setMaximum (maximum);
		pB.setValue (0);
		pB.setIndeterminate (false);
		pB.setString (null);
	    }
	}
    }

    /*********************************************************************
     * Increase value of the current progress bar.
     ********************************************************************/
    protected synchronized void addToProgressBar() {
	if (pBar != null) {
	    JProgressBar pB = pBar.get();
	    pB.setValue (pB.getValue() + 1);
	}
    }

    /*********************************************************************
     * Replace the progress bar with a tree label.
     ********************************************************************/
    protected synchronized void removeProgressBar() {
	if (pBar != null) {
	    this.remove (0);
	    this.addImpl (treeTitle, gbc, 0);
	    this.validate();
	    pBar = null;
	}
    }

}
