/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/

package lu.tudor.santec.gecamed.core.gui.widgets.progress;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingConstants;

import lu.tudor.santec.gecamed.core.gui.GECAMedColors;
import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.i18n.Relocalizable;
import lu.tudor.santec.i18n.Translatrix;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

//***************************************************************************
//* Class Definition and Members                                            *
//***************************************************************************

/**
 * The ProgressDialog is a generic Dialog to show progress about lengthy tasks.
 * The dialog can be used both for tasks where length of execution is unknown,
 * i.e. Indetermined mode or for those where moment of completion is known,
 * i.e. Determined mode. The ProgressDialog allows to specify the title and the
 * message for the overall dialog. Furthermore, its possible to specify the
 * current task
 * @author nico.mack@tudor.lu
 */

public class ProgressDialog extends JDialog implements ActionListener,
													   Relocalizable
	{
	private static final long serialVersionUID = 1L;

	private	String			 m_TitleKey;
	
	private JLabel			 m_Message;
	private String			 m_MessageKey;
	private String[] 		 m_MessageFiller;
	
	private JLabel			 m_Task;
	private JProgressBar	 m_ProgressBar;
	private ProgressExecutor m_ProgressExecutor;
	
	private JButton			 m_CloseButton;
	private JButton			 m_CancelButton;
	
	private boolean			 m_Cancelable;
	private boolean			 m_WasCanceled;
	
	private boolean			 m_Closeable;
	
//***************************************************************************
//* Class Constants                                                         *
//***************************************************************************

	public final static boolean c_Indetermined = true;
	public final static boolean c_Determined   = false;
	
	private final static Dimension c_PreferredSize = new Dimension (330,200);

	private final static String c_Columns		= "3dlu,fill:max(50dlu;pref)," +
	  											  "3dlu,fill:max(50dlu;pref)," +
	  											  "3dlu,fill:max(50dlu;pref),3dlu";

	private final static String c_Rows			= "3dlu,fill:pref:grow," +
	  											  "5dlu,fill:pref," +
	  											  "5dlu,fill:pref," +
	  											  "10dlu,fill:pref,3dlu";

	//=======================================================================
	//= I18N Strings
	//=======================================================================

	private final static String c_Title				= "ProgressDialog.Title";
	private final static String c_Message			= "ProgressDialog.Message";

//---------------------------------------------------------------------------
//***************************************************************************
//* Constructor		                                                        *
//***************************************************************************
//---------------------------------------------------------------------------

public 	ProgressDialog ()
	{
	super (MainFrame.getInstance(),Translatrix.getTranslationString(c_Title),false);
	
	CellConstraints	l_Constraints;
	FormLayout		l_Layout;	
	Font        	l_ProgressFont;
	
	m_TitleKey 		= c_Title;
	m_MessageKey	= c_Message;
	m_MessageFiller = null;
		
	m_Cancelable    = true;
	m_Closeable     = false;
	
	this.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
	this.getContentPane().setBackground(GECAMedColors.c_GECAMedBackground);

	l_Constraints  = new CellConstraints();

	l_Layout = new FormLayout(c_Columns, c_Rows);
	this.setLayout (l_Layout);
	
	m_Message 		  = new JLabel ();
	m_Message.setVerticalTextPosition(SwingConstants.TOP);
	m_Message.setHorizontalTextPosition(SwingConstants.RIGHT);
	m_Message.setIcon (GECAMedModule.getIcon(GECAMedIconNames.CLOCK));
	
	m_Task = new JLabel ();   
	l_ProgressFont    = m_Task.getFont();
	m_Task.setFont (l_ProgressFont.deriveFont((float)(l_ProgressFont.getSize() * 0.75)));
	m_Task.setHorizontalAlignment(SwingConstants.CENTER);
	
	m_ProgressBar 	  = new JProgressBar ();
	m_ProgressBar.setStringPainted(true);
	m_ProgressBar.setString("0");
//	l_ProgressFont    = m_ProgressBar.getFont();
//	m_ProgressBar.setFont (l_ProgressFont.deriveFont((float)(l_ProgressFont.getSize() * 0.75)));
	
	m_CloseButton = new JButton ();
	m_CloseButton.addActionListener(this);
	
	m_CancelButton = new JButton ();
	m_CancelButton.addActionListener(this);
	
	m_Cancelable = false;
	m_CancelButton.setEnabled(m_Cancelable);
	
	this.relocalize();
	
//	this.add (m_Icon,  	  		l_Constraints.xywh(2, 2, 1, 1));
	this.add (m_Message,  		l_Constraints.xywh(2, 2, 5, 1));
	this.add (m_Task,     		l_Constraints.xywh(2, 4, 5, 1));
	this.add (m_ProgressBar,	l_Constraints.xywh(2, 6, 5, 1));
	this.add (m_CloseButton,	l_Constraints.xywh(4, 8, 1, 1));
	this.add (m_CancelButton,	l_Constraints.xywh(6, 8, 1, 1));
	
	this.setPreferredSize (c_PreferredSize);
	this.setResizable(false);
	}

//---------------------------------------------------------------------------	
//***************************************************************************
//* Primitives		                                                        *
//***************************************************************************
//---------------------------------------------------------------------------	

//---------------------------------------------------------------------------	
/**
 * returns the translation string for the specified key. If filler array
 * was specified and translation string contained placeholders, then returned
 * transaltion string will already have the placeholders replaced with values
 * specified in filler.
 * @param p_Key specifies the key of the translation string to retrieve.
 * @param p_Filler specifies the values to substitue placeholders in translation
 * string.
 * @return The translation string matchin p_Key where placeholders (if any) have
 * been replaced by values specified in p_Filler.
 */
//---------------------------------------------------------------------------	

private String getTranslationString (String p_Key, String[] p_Filler)
	{
	if (p_Filler == null)
		 return Translatrix.getTranslationString(p_Key);
	else return Translatrix.getTranslationString(p_Key,p_Filler);
	}

//---------------------------------------------------------------------------	
//***************************************************************************
//* Class Body		                                                        *
//***************************************************************************
//---------------------------------------------------------------------------	
/**
 * Associates the specified progress executor with this progress dialog. If
 * this dialog is cancelable, then canceling will abort the specified executor
 * @param p_Executor specifies the executor to be associated with this
 * instance of progress dialog
 */
//---------------------------------------------------------------------------	

public void setProgressExecutor (ProgressExecutor p_Executor)
	{
	m_ProgressExecutor = p_Executor;
	}

//---------------------------------------------------------------------------	
/**
 * Resets the Progress dialog.
 */
//---------------------------------------------------------------------------	

public void reset ()
	{
	m_WasCanceled = false;
	m_Task.setText ("");
	m_ProgressBar.setIndeterminate(true);
	m_ProgressBar.setValue(0);
	m_ProgressBar.setStringPainted(false);
	}

//---------------------------------------------------------------------------	
/**
 * The setCancelable method allows to specify whether the progress dialog
 * can be canceled or not. Setting dialog to be cancelable will enable the
 * Cancel button.
 * @param  p_Cancelable specifies whether the progress dialog can be canceled
 * or not. Specify <code>true</code> to make dialog cancelable, <code>false</code>
 * if dialog should not be cancelable (default).
 */
//---------------------------------------------------------------------------	

public void setCancelable (boolean p_Cancelable)
	{
	m_Cancelable = p_Cancelable;
	m_CancelButton.setEnabled(m_Cancelable);
	}

//---------------------------------------------------------------------------	
/**
 * The setClosable method allows to specify whether the progress dialog
 * can be closed or not. Setting dialog to be closable will enable the
 * Close button.
 * @param  p_Closeable specifies whether the progress dialog can be closed
 * or not. Specify <code>true</code> to make dialog closable, <code>false</code>
 * if dialog should not be cancelable (default).
 */
//---------------------------------------------------------------------------	

public void setClosable (boolean p_Closeable)
	{
	m_Closeable = p_Closeable;
	m_CloseButton.setEnabled(p_Closeable);
	}

//---------------------------------------------------------------------------	
/**
 * sets the title of this progress dialog.
 * @param p_TitleKey specifies the key of the translation string to be used
 * as dialog title.
 */
//---------------------------------------------------------------------------	

public void setTitle (String p_TitleKey)
	{
	m_TitleKey = p_TitleKey;
	super.setTitle(Translatrix.getTranslationString(m_TitleKey));
	}

//---------------------------------------------------------------------------	
/**
 * sets the message of this progress dialog.
 * @param p_MessageKey specifies the key of the translation string to be used
 * as dialog message.
 * @param p_Filler specifies the values to be used to substitue placeholders
 * in message string . Specify <code>null</code> if message translation string does
 * not contain any placeholders.
 */
//---------------------------------------------------------------------------	

public void setMessage (String p_MessageKey, String[] p_Filler)
	{
	m_MessageKey 	= p_MessageKey;
	m_MessageFiller = p_Filler;
	
	m_Message.setText(this.getTranslationString (m_MessageKey,m_MessageFiller));
	}

//---------------------------------------------------------------------------	
/**
 * sets the current task of this progress dialog.
 * @param p_TaskKey specifies the key of the translation string to be used
 * as task message.
 * @param p_Filler specifies the values to be used to substitue placeholders
 * in task string. Specify <code>null</code> if message translation string does
 * not contain any placeholders.
 */
//---------------------------------------------------------------------------	

public void setTask (String p_TaskKey, String[] p_Filler)
	{
	String	l_TaskMessage;
	
	l_TaskMessage = this.getTranslationString (p_TaskKey,p_Filler);
	
	m_Task.setText(l_TaskMessage);
	}

//---------------------------------------------------------------------------	
/**
 * Sets the progress bar mode for this dialog. Progress bar can be either
 * indetermined or determined. In Indetermined mode, progress bar turns into
 * a knight rider kind of scanner showing that something is happening but not
 * allowing any judgement about how long it will take to complete. Determined
 * mode however allows the user to estimated how long the task or tasks will take
 * to complete.
 * @param p_Indeterminate specifies whether or not progress bar ought to be
 * in indetermined mode or determined mode. When specifying determined mode,
 * please remember to set progress bar span and to update progress by calling
 * seProgress method.
 * @see setProgressBarSpan (int,int)
 * @see setProgress
 */
//---------------------------------------------------------------------------	

public void setProgressBarMode (boolean p_Indeterminate)
	{
	m_ProgressBar.setIndeterminate(p_Indeterminate);
	}

//---------------------------------------------------------------------------	
/**
 * The setProgressBarSpan sets the range of values that the progress bar
 * has to expect as progress values. The lower limit is the value that will
 * be considered as 0% progress whereas the upper limit is the value that
 * will be interpreted as 100% progress, i.e. completion.
 * @param p_LowerLimit specifies the lowest value, i.e 0%
 * @param p_UpperLimit specifies the highest possible value i.e 100% 
 */
//---------------------------------------------------------------------------	

public void setProgressBarSpan (int p_LowerLimit, int p_UpperLimit)
	{
	m_ProgressBar.setIndeterminate(false);
	m_ProgressBar.setMinimum(p_LowerLimit);
	m_ProgressBar.setMaximum(p_UpperLimit);
	}

//---------------------------------------------------------------------------	
/**
 * The setProgress method sets progress bar to value specified by p_Value.
 * Specified value must be inside range specified by progress bar span. Please
 * not that calling setProgress is only effective when progress bar is in
 * determined mode.
 * @param p_Value specifies the current progress to be shown by progress bar.
 * @see setProgressBarSpan (int,int)
 */
//---------------------------------------------------------------------------	

public void setProgress (int p_Value)
	{
	m_ProgressBar.setValue(p_Value);
	m_ProgressBar.setStringPainted(false);
	}
	
//---------------------------------------------------------------------------	
/**
 * The setProgress method sets progress bar to value specified by p_Value.
 * Specified value must be inside range specified by progress bar span. This
 * implementation of the method furthermore allows to specify a
 * progress message that will be displayed inside the progress bar.Please
 * not that calling setProgress is only effective when progress bar is in
 * determined mode.
 * @param p_Value specifies the current progress to be shown by progress bar.
 * @param p_TaskKey specifies the key of the translation string to be used
 * as progress message.
 * @param p_Filler specifies the values to be used to substitue placeholders
 * in progress string. Specify <code>null</code> if message translation string does
 * not contain any placeholders.
 * @see setProgressBarSpan (int,int)
 */
//---------------------------------------------------------------------------	

public void setProgress (int p_Value, String p_MessageKey, String[] p_Filler)
	{
	m_ProgressBar.setValue(p_Value);
	
	if ((p_MessageKey != null) && (p_MessageKey.length() > 0))
		{
		m_ProgressBar.setStringPainted(true);
		m_ProgressBar.setString(this.getTranslationString(p_MessageKey, p_Filler));
		}
	}
	
//---------------------------------------------------------------------------	
/**
 * The setProgress method sets progress bar to value specified by p_Value.
 * Specified value must be inside range specified by progress bar span. This
 * implementation of the method furthermore allows to specify a 
 * progress message that will be displayed inside the progress bar.Please
 * not that calling setProgress is only effective when progress bar is in
 * determined mode.
 * @param p_Value specifies the current progress to be shown by progress bar.
 * @param p_Message specifies the key of the translation string to be used
 * as progress message.
 * @see setProgressBarSpan (int,int)
 */
//---------------------------------------------------------------------------	

public void setProgress (int p_Value, String p_Message)
	{
	m_ProgressBar.setValue(p_Value);

	if (p_Message != null) 
		{
		m_ProgressBar.setStringPainted(true);
		m_ProgressBar.setString(p_Message);
		}
	}

//---------------------------------------------------------------------------	
/**
 * Allows to determine whether or not this progress dialog was canceled.
 * @return <code>true</code> if dialog was canceled, i.e. cancel button was
 * pressed, <code>false</code> otherwise.
 */
//---------------------------------------------------------------------------	

public boolean wasCanceled ()
	{
	return m_WasCanceled;
	}

//---------------------------------------------------------------------------
/** 
 * overwrites ActionListener's actionPerformed method. Method responds to Buttons
 * in dialog.
 * @param p_ActionEvent the action event triggering method invocation
 */
//---------------------------------------------------------------------------

public void actionPerformed(ActionEvent p_ActionEvent) 
	{
	if (p_ActionEvent.getSource().equals (m_CloseButton))
		{
		m_WasCanceled = false;
		this.setVisible(false);
		}
	else if (p_ActionEvent.getSource().equals (m_CancelButton))
		{
		m_WasCanceled = true;
		if (m_ProgressExecutor != null) m_ProgressExecutor.abortExecution();
		this.setVisible(false);
		}	
	}

//---------------------------------------------------------------------------
/**
 * Method is part of the Relocalizable interface. The method does everything
 * required to reflect changes of active Locale
 */
//---------------------------------------------------------------------------

public void relocalize() 
	{
	this.setTitle(Translatrix.getTranslationString(m_TitleKey));
	
	if (m_Message != null)
		m_Message.setText(this.getTranslationString (m_MessageKey,m_MessageFiller));

	if (m_CloseButton != null)
		m_CloseButton.setText(Translatrix.getTranslationString("core.close"));
	
	if (m_CancelButton != null) 
		m_CancelButton.setText(Translatrix.getTranslationString("core.cancel"));
	}

//---------------------------------------------------------------------------	
//***************************************************************************
//* End of Class				                            				*
//***************************************************************************
//---------------------------------------------------------------------------	
}
