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

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;

import javax.naming.InitialContext;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.border.TitledBorder;

import lu.tudor.santec.gecamed.backup.ejb.session.interfaces.BackupManagerInterface;
import lu.tudor.santec.gecamed.backup.ejb.session.interfaces.FileInfo;
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.IconFetcher;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.utils.LineColorListRenderer;
import lu.tudor.santec.gecamed.core.gui.utils.LogFileViewer;
import lu.tudor.santec.gecamed.core.utils.FileUtils;
import lu.tudor.santec.i18n.Translatrix;

public class BackupDialog extends JDialog implements ActionListener, MouseListener {

    	public static final ImageIcon ICON_DB = IconFetcher.getMediumIcon(BackupDialog.class, "file_db.png");
    	public static final ImageIcon ICON_FILES = IconFetcher.getMediumIcon(BackupDialog.class, "file_files.png");
    	public static final ImageIcon ICON_DICOM = IconFetcher.getMediumIcon(BackupDialog.class, "file_dcm.png");
    	public static final ImageIcon ICON_LETTER_TEMPLATE = IconFetcher.getMediumIcon(BackupDialog.class, "file_letter.png");
    	public static final ImageIcon ICON_COMPLETE = IconFetcher.getMediumIcon(BackupDialog.class, "file_zip.png");
    
	private static final long serialVersionUID = 1L;
	
	private BackupManagerInterface backupManager;
	
	protected FileInfo lastBackup;

	private DateFormat fileDateFormat = new SimpleDateFormat("dd/MM/yyyy - HH:mm");
	
	private JFrame parent;
	private JPanel topPanel;
	private JScrollPane listPanel;
	private JPanel bottomPanel;
	private JProgressBar progressBar;
	private JButton closeButton;
	private JLabel infoLabel;
	private JButton runButton;
	private JButton downloadButton;
	private JList list;
	private DefaultListModel listModel;
	private JFileChooser jfc = new JFileChooser();

	private MouseEvent event;

	private JPopupMenu popup;
	private JCheckBox doDBBackup;
	private JCheckBox doFileBackup;
	private JCheckBox doDicomBackup;
	private BackupAdminSettingsPlugin backupSettings;
	private JCheckBox doLetterTemplateBackup;
	
	public BackupDialog(JFrame parent, BackupAdminSettingsPlugin backupSettings) {
		super(parent);
		
		setModal(true);
		
		this.parent = parent;
		
        	// load translations
        	Translatrix.addBundle("lu.tudor.santec.gecamed.backup.gui.resources.Translatrix");
        	setTitle(Translatrix.getTranslationString("backup.dbBackup"));
		
        	this.backupSettings = backupSettings; 	
		
		this.getContentPane().setBackground(GECAMedColors.c_GECAMedBackground);
		this.setLayout(new BorderLayout());
		this.topPanel = new JPanel(new BorderLayout());
		this.topPanel.setBackground(Color.WHITE);
		this.topPanel.setBorder(BorderFactory.createEmptyBorder(3,3,3,3));
		this.infoLabel = new JLabel("");
		this.infoLabel.setIcon(GECAMedModule.getIcon(GECAMedIconNames.BACKUP_DB));
		this.infoLabel.setPreferredSize(new Dimension(60,60));
		this.topPanel.add(infoLabel, BorderLayout.NORTH);
		JPanel bPanel = new JPanel(new GridLayout(0,2,5,5));
		bPanel.setOpaque(false);
		this.runButton = new JButton(Translatrix.getTranslationString("backup.runBackup"));
		this.runButton.addActionListener(this);
		bPanel.add(runButton);
		this.downloadButton = new JButton(Translatrix.getTranslationString("backup.downloadBackup"));
		this.downloadButton.addActionListener(this);
		bPanel.add(downloadButton);
		this.topPanel.add(bPanel, BorderLayout.CENTER);
		
		JPanel optionPanel = new JPanel(new GridLayout(1,0));
		optionPanel.setOpaque(false);
		optionPanel.setBorder(new TitledBorder(Translatrix.getTranslationString("backup.backupOptions")));
        	this.doDBBackup = new JCheckBox(Translatrix.getTranslationString("backup.DBBackup"));
        	this.doDBBackup.setOpaque(false);
        	optionPanel.add(this.doDBBackup);
                this.doFileBackup = new JCheckBox(Translatrix.getTranslationString("backup.FileBackup"));
                this.doFileBackup.setOpaque(false);
                optionPanel.add(this.doFileBackup);
                this.doDicomBackup = new JCheckBox(Translatrix.getTranslationString("backup.DicomBackup"));
                this.doDicomBackup.setOpaque(false);
                optionPanel.add(this.doDicomBackup);
                this.doLetterTemplateBackup = new JCheckBox(Translatrix.getTranslationString("backup.LetterTemplateBackup"));
                this.doLetterTemplateBackup.setOpaque(false);
                optionPanel.add(this.doLetterTemplateBackup);
                
                topPanel.add(optionPanel, BorderLayout.SOUTH);

		this.add(topPanel, BorderLayout.NORTH);
		
		this.listModel = new DefaultListModel();
		this.list = new JList(listModel);
		this.list.setFixedCellHeight(30);
		this.list.setCellRenderer(new FileListCellRenderer());
		this.list.addMouseListener(this);
		this.listPanel = new JScrollPane(list);
		this.listPanel.setBackground(Color.WHITE);
		this.listPanel.getViewport().setOpaque(false);
		this.listPanel.setBorder(
				new TitledBorder(Translatrix.getTranslationString("backup.recentBackups")));
		this.add(listPanel, BorderLayout.CENTER);
		
		this.bottomPanel = new JPanel(new BorderLayout());
		this.bottomPanel.setOpaque(false);
		this.bottomPanel.setBorder(BorderFactory.createEmptyBorder(3,3,3,3));
		this.progressBar = new JProgressBar();
		this.progressBar.setStringPainted(true);
		this.progressBar.setString("");
		this.progressBar.setPreferredSize(new Dimension(300,20));
		this.bottomPanel.add(progressBar, BorderLayout.WEST);
		
		this.closeButton = new JButton(Translatrix.getTranslationString("core.close"));
		this.closeButton.addActionListener(this);
		this.bottomPanel.add(closeButton, BorderLayout.EAST);
		
		this.add(bottomPanel, BorderLayout.SOUTH);
		
		try {
			InitialContext ctx = new InitialContext();
 			backupManager  = (BackupManagerInterface) ctx.lookup("GECAMed/BackupManagerBean/remote");
		}	catch (Exception e) 
 		{
			e.printStackTrace();
 		}
		
	}
	
	public void showDialog() {
	    	try {
                    this.doDBBackup.setSelected((Boolean)backupSettings.getValue(BackupAdminSettingsPlugin.DO_DB_BACKUP));
                    this.doFileBackup.setSelected((Boolean)backupSettings.getValue(BackupAdminSettingsPlugin.DO_FILE_BACKUP));
                    this.doDicomBackup.setSelected((Boolean)backupSettings.getValue(BackupAdminSettingsPlugin.DO_DICOM_BACKUP));
                    this.doLetterTemplateBackup.setSelected((Boolean)backupSettings.getValue(BackupAdminSettingsPlugin.DO_LETTER_TEMPLATE_BACKUP));
		} catch (Exception e) {
		}
	    
		listBackups();
		this.setSize(600,400);
		this.setLocationRelativeTo(parent);
		this.setVisible(true);
	}
	
	
	public void actionPerformed(ActionEvent e) {
		if (e.getSource().equals(this.closeButton))  {
			this.setVisible(false);
		} else if (e.getSource().equals(this.runButton)){
			doBackup();
		} else if (e.getSource().equals(this.downloadButton)){
			FileInfo fi = (FileInfo) list.getSelectedValue();
			downloadBackup(fi.getFile());
		}
	}
	
	
	/**
	 * starts downloading the provided file
	 * @param backup
	 */
	private void downloadBackup(final File backup) {
		if (backup == null)
			return;
		
			jfc.setSelectedFile(new File(backup.getName()));
			if (jfc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
				new Thread() {
					public void run() {
						runButton.setEnabled(false);
						closeButton.setEnabled(false);
						progressBar.setIndeterminate(true);
						progressBar.setString(Translatrix.getTranslationString("backup.downloadingBackup"));
						byte[] fileData;
						try {
							fileData = backupManager.getBackupFile(backup.getName());
							FileUtils.writeFile(fileData, jfc.getSelectedFile());
						} catch (Exception e) {
							e.printStackTrace();
						}
						progressBar.setIndeterminate(false);
						progressBar.setString("");
						closeButton.setEnabled(true);
						runButton.setEnabled(true);
					}
				}.start();
			}
	}

	/**
	 * starts the backup script on the server
	 */
	private void doBackup() {
		new Thread() {
			public void run() {
				runButton.setEnabled(false);
				closeButton.setEnabled(false);
				downloadButton.setEnabled(false);
				progressBar.setIndeterminate(true);
				progressBar.setString(Translatrix.getTranslationString("backup.runningBackup"));
				infoLabel.setText(Translatrix.getTranslationString("backup.runningBackup"));
				try {
				    long timestamp = System.currentTimeMillis();
				    
				    	if (doDBBackup.isSelected()) {
				    	    infoLabel.setText(Translatrix.getTranslationString("backup.settings.doDBBackup") + "...");
				    	    backupManager.doBackup(timestamp);
				    	}
				    	if (doFileBackup.isSelected()) {
				    	    infoLabel.setText(Translatrix.getTranslationString("backup.settings.doFileBackup") + "...");
				    	    backupManager.doFileBackup(timestamp);
				    	}
				    	if (doDicomBackup.isSelected()) {
				    	    infoLabel.setText(Translatrix.getTranslationString("backup.settings.doDicomBackup") + "...");
				    	    backupManager.doDicomBackup(timestamp);
				    	}
				    	if (doLetterTemplateBackup.isSelected()) {
				    	    infoLabel.setText(Translatrix.getTranslationString("backup.settings.doLetterTemplateBackup") + "...");
				    	    backupManager.doLetterTemplateBackup(timestamp);
				    	}
					listBackups();
					infoLabel.setText("<html><span style=\"color:green\">" +
							Translatrix.getTranslationString("backup.backupDone") +
							"</span><br>"  + infoLabel.getText());
				} catch (Throwable e1) {
					infoLabel.setText("<html><span style=\"color:red\">" +
							Translatrix.getTranslationString("backup.backupFailed") +
							"</span><br>"  + e1.getLocalizedMessage());
//					e1.printStackTrace();
				} 
				
				try {
					LogFileViewer.showLogFile(BackupDialog.this, "Backup Output", backupManager.getOutput(), false);					
				} catch (Exception e) {
					e.printStackTrace();
				}
				
				progressBar.setIndeterminate(false);
				progressBar.setString("");
				downloadButton.setEnabled(true);
				closeButton.setEnabled(true);
				runButton.setEnabled(true);
			}
		}.start();
	}

	/**
	 * fetches the list of available backup files from teh server
	 */
	private void listBackups() {

		try {
			this.listModel.removeAllElements();
			Collection<FileInfo> files = backupManager.listBackups();
			if (files == null)
				return;
			try {
			    this.lastBackup = files.iterator().next();			    
			} catch (Exception e) {
				this.infoLabel.setText("<html>" + Translatrix.getTranslationString("backup.lastBackup") + ": " +
					" - "  + "<br>" +
					Translatrix.getTranslationString("backup.nextBackup") + ": " + getNextBackupDate());
			    return;
			    
			}
			for (Iterator<FileInfo> iter = files.iterator(); iter.hasNext();) {
				FileInfo file = (FileInfo) iter.next();
				this.listModel.addElement(file);				
			}
			this.infoLabel.setText("<html>" + Translatrix.getTranslationString("backup.lastBackup") + ": " +
					fileDateFormat.format(new Date(lastBackup.lastModified())) + "<br>" +
					Translatrix.getTranslationString("backup.nextBackup") + ": " + getNextBackupDate());
				
			try {
				this.list.setSelectedIndex(0);				
			} catch (Exception e) {}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	private String getNextBackupDate() {
		String weekdays = (String) MainFrame.getInstance().adminSettingsPanel.getValue("BACKUP_ADMIN_SETTINGS", "BACKUP_WEEKDAYS");
		if (weekdays == null || weekdays.length()<=1) {
			return "-";
		}
		
		String time = (String)  MainFrame.getInstance().adminSettingsPanel.getValue("BACKUP_ADMIN_SETTINGS", "BACKUP_TIME");
		int hour = Integer.parseInt(time.split(":")[0]);
		int minute = Integer.parseInt(time.split(":")[1]);

		Calendar nextDate = new GregorianCalendar();
		nextDate.set(Calendar.HOUR_OF_DAY, hour);
		nextDate.set(Calendar.MINUTE, minute);
		
		while(! (weekdays.indexOf(nextDate.get(Calendar.DAY_OF_WEEK)+"") >= 0 && nextDate.after(new GregorianCalendar()))) {
			nextDate.roll(Calendar.DAY_OF_YEAR, true);
		}
		return fileDateFormat.format(nextDate.getTime());
	}

	/**
	 * show a menu on right click
	* @param c
	 * @param x
	 * @param y
	 */
	private void showMenu(MouseEvent e) {
		this.event = e;
		if (popup == null) {
			popup = new JPopupMenu();
			popup.add(new AbstractAction(
					Translatrix.getTranslationString("backup.downloadBackup"),
				IconFetcher.getSmallIcon(GECAMedModule.class, GECAMedIconNames.BACKUP_DB)) {
				private static final long serialVersionUID = 1L;
				public void actionPerformed(ActionEvent ae) {
					//	get the current row
					int row = list.locationToIndex(event.getPoint());
					list.setSelectedIndex(row);
					FileInfo fi = (FileInfo) list.getModel().getElementAt(row);
					try {
						downloadBackup(fi.getFile());
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			});
			popup.add(new AbstractAction(
					Translatrix.getTranslationString("backup.deleteBackupFile"),
				IconFetcher.getSmallIcon(GECAMedModule.class, GECAMedIconNames.REMOVE_LINE)) {
				private static final long serialVersionUID = 1L;
				public void actionPerformed(ActionEvent ae) {
					//	get the current row
					int row = list.locationToIndex(event.getPoint());
					list.setSelectedIndex(row);
					FileInfo fi = (FileInfo) list.getModel().getElementAt(row);
					try {
						backupManager.deleteFile(fi.getName());
					} catch (Exception e) {
						e.printStackTrace();
					}
					listBackups();
				}
			});
		}
		int row = list.locationToIndex(event.getPoint());
		if (row < 0) 
			return;
		list.setSelectedIndex(row);
		popup.show(e.getComponent(), e.getX(), e.getY());
	}
	
	
	public void mousePressed(MouseEvent e) {
		if (e.isPopupTrigger()) {
			showMenu(e);
		}
	}

	public void mouseReleased(MouseEvent e) {
		if (e.isPopupTrigger()) {
			showMenu(e);
		}
	}

	public void mouseClicked(MouseEvent e) {}
	public void mouseEntered(MouseEvent e) {}
	public void mouseExited(MouseEvent e) {}
	
	/**
	 * renderer for the list of backup files
	 * 
	 *
	 * @author Johannes Hermen johannes.hermen(at)tudor.lu
	 *
	 * @version
	 * <br>$Log: BackupDialog.java,v $
	 * <br>Revision 1.13  2010-10-13 06:52:28  hermen
	 * <br>added backup of Letter Templates
	 * <br>
	 * <br>Revision 1.12  2009-12-14 15:33:53  hermen
	 * <br>fixed translation
	 * <br>
	 * <br>Revision 1.11  2009-10-30 09:58:55  hermen
	 * <br>added departed status to patient
	 * <br>
	 * <br>Revision 1.10  2009-05-12 09:21:17  hermen
	 * <br>enable Backup by default
	 * <br>
	 * <br>Revision 1.9  2008-09-25 09:42:42  heinemann
	 * <br>fixed copyrights
	 * <br>
	 * <br>Revision 1.8  2008-05-28 12:02:48  hermen
	 * <br>removed stacktrace on parsing empty settings, added enable/disable backup module
	 * <br>
	 * <br>Revision 1.7  2008-04-15 09:59:36  hermen
	 * <br>added backup options
	 * <br>
	 * <br>Revision 1.6  2008-04-14 12:39:17  hermen
	 * <br>extended backup to external files
	 * <br>
	 * <br>Revision 1.5  2008-04-04 13:22:10  hermen
	 * <br>updated backup stuff
	 * <br>
	 * <br>Revision 1.4  2008-04-01 08:17:28  hermen
	 * <br>updated backup stuff
	 * <br>
	 * <br>Revision 1.3  2008-03-28 14:12:20  hermen
	 * <br>changed file path handling to new ServerConfiguration and FileUtils classes
	 * <br>
	 * <br>Revision 1.2  2008-03-27 14:15:24  hermen
	 * <br>added fileinfo obj.
	 * <br>
	 * <br>Revision 1.1  2008-03-27 13:41:53  hermen
	 * <br>added database backup dialog
	 * <br>
	 *
	 */
	class FileListCellRenderer extends LineColorListRenderer {
		private static final long serialVersionUID = 1L;

//		ImageIcon icon = GECAMedModule.getMediumIcon(GECAMedIconNames.OK);
		Font font = new Font("Arial",Font.PLAIN, 12);
		String date = Translatrix.getTranslationString("backup.date");
		String size = Translatrix.getTranslationString("backup.size");
		NumberFormat formatter = new DecimalFormat("#.##");
		
		/* (non-Javadoc)
		 * @see javax.swing.DefaultListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean)
		 */
		@Override
		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
			FileInfo f = (FileInfo) value;
			value = "<html><b>" + date + ":  " + fileDateFormat.format(new Date(f.lastModified())) + "   " + size + ":  " + formatter.format(f.length()/1024/1024.0) + "MB" + "</b><br>"
			+ "&nbsp;&nbsp;&nbsp;" + f.getName();
			JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected,
					cellHasFocus);
			label.setIconTextGap(8);
			label.setFont(font);
			if (f.getName().endsWith(BackupManagerInterface.BACKUP_DB_EXTENSION)) {
			    label.setIcon(ICON_DB);			    
			} else if (f.getName().endsWith(BackupManagerInterface.BACKUP_FILE_EXTENSION)) {
			    label.setIcon(ICON_FILES);			    
			} else if (f.getName().endsWith(BackupManagerInterface.BACKUP_DICOM_EXTENSION)) {
			    label.setIcon(ICON_DICOM);			    
			} else if (f.getName().endsWith(BackupManagerInterface.BACKUP_COMPLETE_EXTENSION)) {
			    label.setIcon(ICON_COMPLETE);			    
			} else if (f.getName().endsWith(BackupManagerInterface.BACKUP_LETTERTEMPLATE_EXTENSION)) {
			    label.setIcon(ICON_LETTER_TEMPLATE);			    
			}
			
			return label;
		}
		
		
		
	}	
}
