/*
 * This file is part of muCommander, http://www.mucommander.com
 *
 * muCommander is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * muCommander 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.mucommander.ui.dialog.file;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import com.mucommander.commons.file.AbstractFile;
import com.mucommander.commons.file.util.FileSet;
import com.mucommander.commons.util.ui.dialog.DialogToolkit;
import com.mucommander.commons.util.ui.layout.XAlignedComponentPanel;
import com.mucommander.commons.util.ui.layout.YBoxPanel;
import com.mucommander.conf.MuConfigurations;
import com.mucommander.conf.MuPreference;
import com.mucommander.job.impl.SendMailJob;
import com.mucommander.text.SizeFormat;
import com.mucommander.text.Translator;
import com.mucommander.ui.action.ActionProperties;
import com.mucommander.ui.action.impl.EmailAction;
import com.mucommander.ui.dialog.pref.general.GeneralPreferencesDialog;
import com.mucommander.ui.main.MainFrame;

/**
 * Dialog allowing the user to email files to someone.
 *
 * <p>One or several recipients, as well as a mail subject and body can be input.
 * The dialog also allows the user to review the files that have been marked,
 * select/unselect some, and displays the total file size.</p>
 *
 * @author Maxence Bernard
 */
public class EmailFilesDialog extends JobDialog implements ActionListener, ItemListener {

    private FileSet flattenedFiles;
	
    private JTextField toField;
    private JTextField subjectField;
    private JTextArea bodyArea;
    private JLabel infoLabel;
    private JCheckBox fileCheckboxes[];

    private static String lastTo = "";
    private static String lastSubject = "";
    private static String lastBody = "";

    private JButton okButton;
    private JButton cancelButton;

    // Dialog size constraints
    private final static Dimension MINIMUM_DIALOG_DIMENSION = new Dimension(400,0);	
    private final static Dimension MAXIMUM_DIALOG_DIMENSION = new Dimension(550,400);	
	
	
    public EmailFilesDialog(MainFrame mainFrame, FileSet files) {
        super(mainFrame, ActionProperties.getActionLabel(EmailAction.Descriptor.ACTION_ID), files);

        // Notifies the user that mail preferences are not set and brings the preferences dialog 
        if(!SendMailJob.mailPreferencesSet()) {
            showErrorDialog(Translator.get("email_dialog.prefs_not_set"), Translator.get("email_dialog.prefs_not_set_title"));
	
            GeneralPreferencesDialog preferencesDialog = GeneralPreferencesDialog.getDialog();
            preferencesDialog.setActiveTab(GeneralPreferencesDialog.MAIL_TAB);
            preferencesDialog.showDialog();
			
            return;
        }
		
		
        try {
            // Figures out which files to send and calculates the number of files and the number of bytes
            this.flattenedFiles = getFlattenedFiles(files);
			
            Container contentPane = getContentPane();
			
            YBoxPanel mainPanel = new YBoxPanel(5);
	
            // Text fields panel
            XAlignedComponentPanel compPanel = new XAlignedComponentPanel();

            // From (sender) field, non editable
            JLabel fromLabel = new JLabel(MuConfigurations.getPreferences().getVariable(MuPreference.MAIL_SENDER_NAME)
                                          +" <"+MuConfigurations.getPreferences().getVariable(MuPreference.MAIL_SENDER_ADDRESS)+">");
            //			fromField.setEditable(false);
            compPanel.addRow(Translator.get("email_dialog.from")+":", fromLabel, 10);
			
            // To (recipients) field
            toField = new JTextField(lastTo);
            compPanel.addRow(Translator.get("email_dialog.to")+":", toField, 10);
			
            // Subject field
            subjectField = new JTextField(lastSubject);
            compPanel.addRow(Translator.get("email_dialog.subject")+":", subjectField, 15);

            mainPanel.add(compPanel);		
	
            // Body area
            bodyArea = new JTextArea(lastBody);
            bodyArea.setRows(6);
            bodyArea.setLineWrap(true);
            JScrollPane scrollPane = new JScrollPane(bodyArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
            mainPanel.add(scrollPane);
			
            mainPanel.addSpace(15);
			
            // Label showing the number of files and total size
            infoLabel = new JLabel();
            mainPanel.add(infoLabel);			

            contentPane.add(mainPanel, BorderLayout.NORTH);
			
            // checkbox showing all files that are to be sent, allowing them to be unselected
            int nbFiles = flattenedFiles.size();
            fileCheckboxes = new JCheckBox[nbFiles];
            if(nbFiles>0) {
                YBoxPanel tempPanel2 = new YBoxPanel();
                AbstractFile file;
                for(int i=0; i<nbFiles; i++) {
                    file = flattenedFiles.elementAt(i);
                    fileCheckboxes[i] = new JCheckBox(file.getName()
                                                      +" ("+ SizeFormat.format(file.getSize(), SizeFormat.DIGITS_MEDIUM| SizeFormat.UNIT_SHORT| SizeFormat.INCLUDE_SPACE| SizeFormat.ROUND_TO_KB)+")", true);
                    fileCheckboxes[i].addItemListener(this);
                    tempPanel2.add(fileCheckboxes[i]);
                }
                scrollPane = new JScrollPane(tempPanel2, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
                contentPane.add(scrollPane, BorderLayout.CENTER);
            }
            updateInfoLabel();
				
            // OK / Cancel buttons panel
            okButton = new JButton(Translator.get("email_dialog.send"));
            cancelButton = new JButton(Translator.get("cancel"));
            contentPane.add(DialogToolkit.createOKCancelPanel(okButton, cancelButton, getRootPane(), this), BorderLayout.SOUTH);
	
            // 'To' field will receive initial focus
            setInitialFocusComponent(toField);		
			
            // Packs dialog
            setMinimumSize(MINIMUM_DIALOG_DIMENSION);
            setMaximumSize(MAXIMUM_DIALOG_DIMENSION);
        }
        catch(IOException e) {
            showErrorDialog(Translator.get("email_dialog.read_error"), Translator.get("email_dialog.error_title"));
        }
    }


    /**
     * Updates the number of selected files and their total size.
     */
    private void updateInfoLabel() {
        int nbFiles = fileCheckboxes.length;
        int nbSelected = 0;
        int bytesTotal = 0;
        long fileSize;
        for(int i=0; i<nbFiles; i++) {
            if(fileCheckboxes[i].isSelected()) {
                fileSize = flattenedFiles.elementAt(i).getSize();
                if(fileSize>0)
                    bytesTotal += fileSize;
                nbSelected++;
            }
        }
        String text = 
            Translator.get("nb_files", ""+nbSelected)
            +(nbSelected==0?"":" ("+ SizeFormat.format(bytesTotal, SizeFormat.DIGITS_MEDIUM| SizeFormat.UNIT_LONG| SizeFormat.ROUND_TO_KB)+")");
        infoLabel.setText(text);
        infoLabel.repaint(100);
    }


    /**
     * Returns a FileSet of *files* (as opposed to folders) that have been found either in the given 
     * FileSet or in one of the subfolders. 
     *
     * @param originalFiles files as selected by the user which may contain folders
     */
    private FileSet getFlattenedFiles(FileSet originalFiles) throws IOException {
        int nbFiles = originalFiles.size();
        FileSet flattenedFiles = new FileSet(originalFiles.getBaseFolder());
        for(int i=0; i<nbFiles; i++)
            recurseOnFolder(originalFiles.elementAt(i), flattenedFiles);

        return flattenedFiles;
    }

    /**
     * Adds the given file to the FileSet if it's not a folder, recurses otherwise.
     */
    private void recurseOnFolder(AbstractFile file, FileSet flattenedFiles) throws IOException {
        if(file.isDirectory() && !file.isSymlink()) {
            AbstractFile children[] = file.ls();
            for (AbstractFile child : children)
                recurseOnFolder(child, flattenedFiles);
        }
        else {
            flattenedFiles.add(file);
        }
    }
	
	
    ////////////////////////////
    // ActionListener methods //
    ////////////////////////////
	
    public void actionPerformed(ActionEvent e) {
        Object source = e.getSource();
		
        // OK Button
        if (source==okButton)  {
            String to = toField.getText().trim();
            String subject = subjectField.getText();
            String body = bodyArea.getText();
            if(!to.equals("")) {
                lastTo = to;
                lastSubject = subject;
                lastBody = body;
				
                // Starts by disposing the dialog
                dispose();

                // Creates new FileSet with files that have been selected
                FileSet filesToSend = new FileSet(flattenedFiles.getBaseFolder());
                int nbFiles = fileCheckboxes.length;
                for(int i=0; i<nbFiles; i++)
                    if(fileCheckboxes[i].isSelected())
                        filesToSend.add(flattenedFiles.elementAt(i));

                // Starts sending files
                ProgressDialog progressDialog = new ProgressDialog(mainFrame, Translator.get("email_dialog.sending"));
                SendMailJob mailJob = new SendMailJob(progressDialog, mainFrame, filesToSend, to, subject, body);
                progressDialog.start(mailJob);
            }
        }
        // Cancel button
        else if (source==cancelButton)  {
            dispose();			
        }
    }
	
    //////////////////////////
    // ItemListener methods //
    //////////////////////////
		
    /**
     * Updates label text whenever a checkbox has been checked or unchecked.
     */
    public void itemStateChanged(ItemEvent e) {	
        updateInfoLabel();
    }


}
