/*******************************************************************************
 * 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.labo.gui.download;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.TitledBorder;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

import lu.tudor.santec.gecamed.core.gui.GECAMedColors;
import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.IconFetcher;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.utils.SwingWorker;
import lu.tudor.santec.gecamed.core.gui.widgets.CheckBoxEditorField;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
import lu.tudor.santec.gecamed.core.gui.widgets.GenericListBox;
import lu.tudor.santec.gecamed.core.utils.Logger;
import lu.tudor.santec.gecamed.labo.ejb.entity.beans.Connection;
import lu.tudor.santec.gecamed.labo.ejb.session.interfaces.ImportInterface;
import lu.tudor.santec.gecamed.labo.gui.LaboModule;
import lu.tudor.santec.i18n.Relocalizable;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.log4j.Level;

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

public class DownloadDialog extends JDialog implements ActionListener,
													   Relocalizable
	{
	/**
	 * 
	 */
	private JPanel				m_ConnectionPanel;
	private TitledBorder		m_ConnectionBorder; 
	private GenericListBox		m_ConnectionsListBox;
	private ConnectionListModel	m_Connections;
	
	private JPanel				m_DownloadPanel;
	private TitledBorder		m_DownloadBorder;
	private JButton				m_DownloadButton;
	private JLabel				m_Task;
	private JProgressBar		m_Progress;
	
	private JButton				m_OkayButton;
	private JButton				m_CancelButton;
	private boolean				m_Canceled;

	private DownloadHandler		m_Downloader;
	private SwingWorker  		m_DownloadWorker;
	private boolean				m_Suspend;
	private static boolean		m_Aborted;
	
	private static ImageIcon m_DownloadIcon         = IconFetcher.getIcon (LaboModule.class,LaboModule.c_i32_DownloadResult);
	private static ImageIcon m_SuspendDownloadIcon  = IconFetcher.getIcon (LaboModule.class,LaboModule.c_i32_DownloadResult);
	private static ImageIcon m_ResumeDownloadIcon   = IconFetcher.getIcon (LaboModule.class,LaboModule.c_i32_DownloadResult);

	private static Logger	 m_Logger	     		= new Logger (DownloadDialog.class);
	
	private static DownloadDialog instance;

//---------------------------------------------------------------------------
//***************************************************************************
//* Constants	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------
	
	private static final long serialVersionUID = 1L;

	private final static int  c_IconTextGap   = 10;

	private static final  int c_ColumnWidths [] = {  10,10,80 };

	private final static String c_Columns			  	= "3dlu,fill:max(70dlu;pref):grow," +
														  "3dlu,fill:max(35dlu;pref)," +
														  "3dlu,fill:max(35dlu;pref),3dlu";
		
	private final static String c_Rows				  	= "3dlu,fill:pref," +
														  "3dlu,fill:pref," +
														  "3dlu,fill:pref,3dlu";

	private final static String c_ConnectionColumns		= "3dlu,fill:max(140dlu;pref),3dlu";
	
	private final static String c_ConnectionRows		= "3dlu,fill:140dlu:grow,3dlu";
	
	private final static String c_DownloadColumns		= "3dlu,fill:pref:grow,3dlu";

	private final static String c_DownloadRows			= "3dlu,fill:pref," +
	  											  		  "5dlu,fill:pref," +
	  											  		  "5dlu,fill:pref,3dlu";
	
	//=======================================================================
	//= I18N Strings
	//=======================================================================

	private final static String c_Title				= "DownloadDialog.Title";

	private final static String c_ConnectionBorder  = "DownloadDialog.ConnectionBorder";
	
	private final static String c_DownloadBorder    	= "DownloadDialog.DownloadBorder";
	private final static String c_DownloadButton		= "DownloadDialog.DownloadButton";
	private final static String c_SuspendDownloadButton	= "DownloadDialog.SuspendDownloadButton";
	private final static String c_ResumeDownloadButton	= "DownloadDialog.ResumeDownloadButton";

	private final static String c_IdleTask   					= "DownloadDialog.IdleTask";
	private final static String c_OpeningConnectionTask   		= "DownloadDialog.OpeningConnectionTask";
	private final static String c_SynchronizingCertificatesTask = "DownloadDialog.SynchronizingCertificatesTask";
	private final static String c_DownloadingResultsTask		= "DownloadDialog.DownloadingResultsTask";
	
	private final static String c_DownloadingResultProgress     = "DownloadDialog.DownloadingResultProgress";
//	private final static String c_DownloadDone                  = "DownloadDialog.DownloadDone";

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

public DownloadDialog ()
	{
	super (MainFrame.getInstance(),Translatrix.getTranslationString(c_Title),true);
	instance = this;
	
	CellConstraints	l_Constraints;
	FormLayout		l_Layout;	
	Color			l_DefaultColor;
	
	this.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
	this.getContentPane().setBackground (GECAMedColors.c_GECAMedBackground);
	this.setResizable(false);
	
	l_Constraints  = new CellConstraints();
	
	l_DefaultColor = (Color) UIManager.getDefaults().get("TextField.inactiveBackground");   
	UIManager.getDefaults().put("TextField.inactiveBackground", Color.WHITE);

	this.buildConnectionPanel();
	this.buildDownloadPanel();
	
	m_OkayButton    = new JButton ();
	m_OkayButton.setIcon(IconFetcher.getScaledIcon(IconFetcher.class,GECAMedIconNames.OK,16));
	m_OkayButton.addActionListener(this);
	
	m_CancelButton    = new JButton ();
	m_CancelButton.setIcon(IconFetcher.getScaledIcon(IconFetcher.class,GECAMedIconNames.CANCEL,16));
	m_CancelButton.addActionListener(this);

	this.relocalize();
	
	l_Layout = new FormLayout(c_Columns, c_Rows);
    this.setLayout (l_Layout);

	this.add (m_ConnectionPanel,  	l_Constraints.xywh(2, 2, 5, 1));
	this.add (m_DownloadPanel,  	l_Constraints.xywh(2, 4, 5, 1));
	this.add (m_OkayButton,			l_Constraints.xywh(4, 6, 1, 1));
	this.add (m_CancelButton,		l_Constraints.xywh(6, 6, 1, 1));
	
	UIManager.getDefaults().put("TextField.inactiveBackground", l_DefaultColor );	
	}
	
//---------------------------------------------------------------------------
//***************************************************************************
//* Primitives	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

private void buildConnectionPanel ()
	{
	CellConstraints		l_Constraints;
	FormLayout			l_Layout;	
	TableColumn			l_Column;
	TableColumnModel	l_ColumnModel;

	l_Layout = new FormLayout(c_ConnectionColumns, c_ConnectionRows);
	l_Constraints = new CellConstraints();
	
	m_ConnectionBorder = new TitledBorder ("");
	
	m_ConnectionPanel = new JPanel ();
	m_ConnectionPanel.setBorder (m_ConnectionBorder);
	m_ConnectionPanel.setLayout(l_Layout);
	m_ConnectionPanel.setOpaque (false);
	
	m_Connections = new ConnectionListModel ();
	
	m_ConnectionsListBox = new GenericListBox (m_Connections);
	m_ConnectionsListBox.setRenderer (new ConnectionRenderer());
	m_ConnectionsListBox.setColumnWidths(c_ColumnWidths);
	
	l_ColumnModel = m_ConnectionsListBox.getTable().getColumnModel(); 	
	l_Column = l_ColumnModel.getColumn (ConnectionListModel.c_EnabledColumn);
	l_Column.setCellEditor (new CheckBoxEditorField());
	
	this.relocalize();
	
	m_ConnectionPanel.add(m_ConnectionsListBox, l_Constraints.xywh(2, 2, 1, 1));
	}

//---------------------------------------------------------------------------

private void buildDownloadPanel ()
	{
	CellConstraints		l_Constraints;
	FormLayout			l_Layout;	
	Font				l_ProgressFont;	
	
	l_Layout = new FormLayout(c_DownloadColumns, c_DownloadRows);
	l_Constraints = new CellConstraints();
	
	m_DownloadBorder = new TitledBorder ("");
	
	m_DownloadPanel = new JPanel ();
	m_DownloadPanel.setBorder (m_DownloadBorder);
	m_DownloadPanel.setLayout(l_Layout);
	m_DownloadPanel.setOpaque (false);
	
	m_DownloadButton = new JButton ();
	m_DownloadButton.setIcon(m_DownloadIcon);
	m_DownloadButton.setText(Translatrix.getTranslationString(c_DownloadButton));
	m_DownloadButton.setIconTextGap(c_IconTextGap);
	m_DownloadButton.addActionListener(this);
	
	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_Task.setText(Translatrix.getTranslationString(c_IdleTask));
	
	m_Progress = new JProgressBar ();
	m_Progress.setStringPainted(true);
	m_Progress.setString("");
	
	m_DownloadPanel.add (m_DownloadButton,  l_Constraints.xywh(2, 2, 1, 1));
	m_DownloadPanel.add (m_Task,     		l_Constraints.xywh(2, 4, 1, 1));
	m_DownloadPanel.add (m_Progress,		l_Constraints.xywh(2, 6, 1, 1));
	}

//---------------------------------------------------------------------------

//private void toggleSuspendButton (boolean p_SuspendButton)
//	{
//	if (p_SuspendButton)
//		{
//		m_DownloadButton.setIcon(m_SuspendDownloadIcon);
//		m_DownloadButton.setText(Translatrix.getTranslationString(c_SuspendDownloadButton));	
//		}
//	else
//		{
//		m_DownloadButton.setIcon(m_DownloadIcon);
//		m_DownloadButton.setText(Translatrix.getTranslationString(c_DownloadButton));	
//		}
//	}

//---------------------------------------------------------------------------

private void toggleResumeButton (boolean p_ResumeButton)
	{
	if (p_ResumeButton)
		{
		m_DownloadButton.setIcon(m_ResumeDownloadIcon);
		m_DownloadButton.setText(Translatrix.getTranslationString(c_ResumeDownloadButton));	
		}
	else
		{
		m_DownloadButton.setIcon(m_SuspendDownloadIcon);
		m_DownloadButton.setText(Translatrix.getTranslationString(c_SuspendDownloadButton));	
		}
	}

//---------------------------------------------------------------------------
//***************************************************************************
//* Swing Worker Thread                                                     *
//***************************************************************************
//---------------------------------------------------------------------------

private boolean downloadResultsFormConnection (Connection p_Connection)
	{
	String[]			l_Filler;
	Collection <String>	l_AvailableResults;
	Iterator <String>	l_ResultIterator;
	String				l_Result;
	int					l_ImportState 			= ImportInterface.IMPORT_SUCCESSFUL;
//	boolean				l_Success				= true;
	int					l_Count   				= 0;
	Collection<String>	l_ImportedResults 		= new LinkedList<String>();
	Collection<String>	l_NotImportedResults 	= new LinkedList<String>();
	String				l_MasterPassword 		= LaboModule.getMasterPassword();
	
	if (l_MasterPassword == null)
		return false;
	
	m_Progress.setIndeterminate (true);
	
	if (m_Downloader == null)
		m_Downloader = new DownloadHandler ();
	else
		m_Downloader.resetApplyAllForExistingResults();
	
	m_Downloader.setMasterPassword(l_MasterPassword);
	
	l_Filler = new String [1];
	l_Filler[0] = p_Connection.getServer();
	
	if (p_Connection.getSynchronize())
		{
		m_Task.setText(Translatrix.getTranslationString(c_SynchronizingCertificatesTask, l_Filler));	
		try
			{
			m_Downloader.synchronizeCertifificates(p_Connection);
			} 
		catch (Exception p_Exception)
			{
			GECAMedBaseDialogImpl.showMessageDialog(this, 
					Translatrix.getTranslationString("FileImportHandler.ErrorWhileTryingToConnect"), 
					p_Exception.getMessage(), 
					GECAMedBaseDialog.OK_BUTTON_MODE);
			return false;
			}
		}

	l_Filler = new String [1];
	l_Filler[0] = p_Connection.getServer();

	m_Task.setText(Translatrix.getTranslationString(c_OpeningConnectionTask, l_Filler));
	
	if (m_Downloader.openConnection (p_Connection) && !m_Aborted)
		{
		m_Task.setText(Translatrix.getTranslationString(c_DownloadingResultsTask, l_Filler));
			
		l_AvailableResults = m_Downloader.getAvailableResults();
		if ((l_AvailableResults != null) && (l_AvailableResults.size() > 0) && !m_Aborted)
			{
			m_Progress.setIndeterminate(false);
			m_Progress.setMinimum (0);
			m_Progress.setMaximum (l_AvailableResults.size());
			
			l_ResultIterator = l_AvailableResults.iterator();
			while (l_ResultIterator.hasNext())
				{
				l_Result = l_ResultIterator.next();
				
				if (l_ImportState == ImportInterface.CANCEL_IMPORTING || m_Aborted)
					{
					if (m_Aborted)
						l_ImportState = ImportInterface.CANCEL_IMPORTING;
					l_NotImportedResults.add(l_Result);
					continue;
					}
				
				l_Filler[0] = l_Result;
				
				m_Progress.setString (Translatrix.getTranslationString(c_DownloadingResultProgress, l_Filler));
				m_Progress.setValue (++l_Count);
				
				l_ImportState = m_Downloader.importResult(l_Result);
				if (l_ImportState != ImportInterface.IMPORT_SUCCESSFUL)
					{
					if (l_ImportState != ImportInterface.CANCEL_IMPORTING
							&& l_ImportState != ImportInterface.RESULT_ALREADY_EXISTS
							&& l_ImportState != ImportInterface.SKIP_THIS_RESULT)
						m_Downloader.openConnection(p_Connection);
//					l_Success = false;
					l_NotImportedResults.add(l_Result);
					}
				else 
					{
					l_ImportedResults.add(l_Result);
					}
				}
			
			if (!l_NotImportedResults.isEmpty())
				{
				// one or more results have not been imported.
				DownloadInfoDialog dialog = new DownloadInfoDialog(l_ImportedResults, l_NotImportedResults);
				dialog.pack();
				MainFrame.showDialogCentered(dialog);
				}
			}
		else if ((l_AvailableResults != null) && (l_AvailableResults.size() == 0))
			{
			l_ImportState = ImportInterface.CANCEL_IMPORTING;	
			}
		m_Downloader.closeConnection();
		}
	
	return l_NotImportedResults.isEmpty();
	}

//---------------------------------------------------------------------------

public void downloadResults ()
	{
	Connection			  l_Connection;
	int					  l_Row = 0;
	
	m_Aborted = false;
	while (l_Row < m_Connections.getRowCount())
		{
		l_Connection = m_Connections.getConnectionAt(l_Row);	
		if (l_Connection.getEnabled())
			{
			l_Connection.setStatus(Connection.c_Downloading);
			m_Connections.setConnectionAt(l_Connection, l_Row);
			m_ConnectionsListBox.validate();
			
			if (this.downloadResultsFormConnection(l_Connection))
				{
				l_Connection.setStatus(Connection.c_Done);
				m_Connections.setConnectionAt(l_Connection, l_Row);
				m_ConnectionsListBox.validate();
				}
			else
				{
				l_Connection.setStatus(Connection.c_Failed);
				m_Connections.setConnectionAt(l_Connection, l_Row);
				m_ConnectionsListBox.validate();
				}
			}
		l_Row++;
		}
	
	m_Task.setText("");
	m_Task.setText(Translatrix.getTranslationString(c_IdleTask));
	
	m_Progress.setString("");
	m_Progress.setIndeterminate(false);
	m_Progress.setValue (0);
	}

//---------------------------------------------------------------------------

Object DownloadWorker ()
	{
	this.downloadResults();
	return "";
	}

//---------------------------------------------------------------------------

public void startDownload ()
	{
	m_DownloadWorker = new SwingWorker() 
	{
	public Object construct() 
		{
		return DownloadWorker ();
		}
	public void start ()
		{
		m_Aborted = false;
		super.start();
		}
	public void finished ()
		{
		}
	public void interrupt ()
		{
		m_Aborted = true;
		super.interrupt();
		}
	};

	m_DownloadWorker.start ();  	
	}

//---------------------------------------------------------------------------

public void abortDownload ()
	{
	m_Aborted = true;
	if (m_DownloadWorker != null) m_DownloadWorker.interrupt();
	}

//---------------------------------------------------------------------------

private synchronized void suspendDownload ()
	{
	m_Suspend = true;
	this.toggleResumeButton(true);
	while (m_Suspend) 
		try {wait(500);} 
		catch (Exception p_Exception) 
			{
			m_Logger.log(Level.ERROR, "Exception while suspended!", p_Exception);
			m_Suspend = false;
			};
			
	this.toggleResumeButton(false);
	}

//---------------------------------------------------------------------------

private void resumeDownload ()
	{
	m_Suspend = false;
	}

//---------------------------------------------------------------------------
//***************************************************************************
//* Class Body	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

public void setConnections (Collection <Connection> p_Connections)
	{
	if ((p_Connections != null) && (m_Connections != null))
		{
		m_Connections.setConnections(p_Connections);
		m_ConnectionsListBox.packColumns();
		m_ConnectionsListBox.packRows();
		m_ConnectionsListBox.validate();
		}
	}

//---------------------------------------------------------------------------

public boolean wasCanceled ()
	{
	return m_Canceled;	
	}

//---------------------------------------------------------------------------

public void relocalize()
	{
	this.setTitle(Translatrix.getTranslationString(c_Title));
		
	if (m_ConnectionBorder != null) 
		m_ConnectionBorder.setTitle(Translatrix.getTranslationString (c_ConnectionBorder));
	
	if (m_ConnectionsListBox != null) 
		m_ConnectionsListBox.relocalize();
	
	if (m_DownloadBorder != null) 
		m_DownloadBorder.setTitle(Translatrix.getTranslationString (c_DownloadBorder));
	
	if (m_DownloadButton != null)
		m_DownloadButton.setText(Translatrix.getTranslationString (c_DownloadButton));
	
	if (m_OkayButton != null)
		m_OkayButton.setText (Translatrix.getTranslationString("core.ok"));
	
	if (m_CancelButton != null)
		m_CancelButton.setText(Translatrix.getTranslationString("core.cancel"));
	}

//---------------------------------------------------------------------------

public void actionPerformed (ActionEvent p_ActionEvent)
	{
	if (p_ActionEvent.getSource().equals(m_CancelButton))
		{
		this.setVisible (false);
		this.abortDownload();
		m_Canceled = true;
		}
	else if (p_ActionEvent.getSource().equals(m_OkayButton))
		{				
		m_Canceled = false;
		this.setVisible (false);
		}
	else if (p_ActionEvent.getSource().equals(m_DownloadButton))
		{		
		if (m_DownloadButton.getText().equals(Translatrix.getTranslationString(c_DownloadButton)))
			{
			this.startDownload();
			}
		else if (m_DownloadButton.getText().equals(Translatrix.getTranslationString(c_SuspendDownloadButton)))
			{
			this.suspendDownload ();
			}
		else if (m_DownloadButton.getText().equals(Translatrix.getTranslationString(c_ResumeDownloadButton)))
			{
			this.resumeDownload();
			}
		}
	}

public static boolean isDownloadAborted ()
	{
	return m_Aborted;
	}

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