/*
 * 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.util.regex.PatternSyntaxException;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mucommander.commons.file.filter.AndFileFilter;
import com.mucommander.commons.file.filter.AttributeFileFilter;
import com.mucommander.commons.file.filter.AttributeFileFilter.FileAttribute;
import com.mucommander.commons.util.ui.dialog.DialogToolkit;
import com.mucommander.commons.util.ui.dialog.FocusDialog;
import com.mucommander.commons.util.ui.layout.YBoxPanel;
import com.mucommander.commons.file.filter.ContainsFilenameFilter;
import com.mucommander.commons.file.filter.EndsWithFilenameFilter;
import com.mucommander.commons.file.filter.EqualsFilenameFilter;
import com.mucommander.commons.file.filter.FileFilter;
import com.mucommander.commons.file.filter.PassThroughFileFilter;
import com.mucommander.commons.file.filter.RegexpFilenameFilter;
import com.mucommander.commons.file.filter.StartsWithFilenameFilter;
import com.mucommander.text.Translator;
import com.mucommander.ui.main.MainFrame;
import com.mucommander.ui.main.table.FileTable;

/**
 * This dialog allows the user to add (mark) or remove (unmark) files from the current selection,
 * based on a match criterium and string.
 *
 * @author Maxence Bernard
 */
public class FileSelectionDialog extends FocusDialog implements ActionListener {
	private static final Logger LOGGER = LoggerFactory.getLogger(FileSelectionDialog.class);
	
    /* Filename comparison criteria */		
    private final static int CONTAINS    = 0;
    private final static int STARTS_WITH = 1;
    private final static int ENDS_WIDTH  = 2;
    private final static int IS          = 3;
    private final static int REGEXP      = 4;

    /** Add to or remove from selection ? */	 
    private boolean addToSelection;

    private JComboBox<String> comparisonComboBox;
    private JTextField selectionField;

    private JCheckBox caseSensitiveCheckBox;
    private JCheckBox includeFoldersCheckBox;

    private JButton okButton;

    private MainFrame mainFrame;
	
    /** 
     * Is selection case sensitive? (initially false)
     * <br>Note: this field is static so the value is kept after the dialog is OKed.
     */ 
    private static boolean caseSensitive = false;

    /** 
     * Does the selection include folders? (initially false)
     * <br>Note: this field is static so the value is kept after the dialog is OKed.
     */ 
    private static boolean includeFolders = false;
	
    /** 
     * Filename comparison: contains, starts with, ends with, is ?
     * <br>Note: this field is static so the value is kept after the dialog is OKed.
     */ 
    private static int comparison = CONTAINS;

    /** 
     * Keyword which has last been typed to mark or unmark files.
     * <br>Note: this field is static so the value is kept after the dialog is OKed.
     */ 
    private static String keywordString = "*";
	

    private final static Dimension MINIMUM_DIALOG_DIMENSION = new Dimension(320,0);	
    private final static Dimension MAXIMUM_DIALOG_DIMENSION = new Dimension(400,10000);	


    /**
     * Creates a new 'mark' or 'unmark' dialog.
     *
     * @param addToSelection if <true>, files matching
     */
    public FileSelectionDialog(MainFrame mainFrame, boolean addToSelection) {

        super(mainFrame, Translator.get(addToSelection?"file_selection_dialog.mark":"file_selection_dialog.unmark"), mainFrame);
	
        this.mainFrame = mainFrame;
        this.addToSelection = addToSelection;

        Container contentPane = getContentPane();
        contentPane.setLayout(new BorderLayout());

        YBoxPanel northPanel = new YBoxPanel(5);
        JLabel label = new JLabel(Translator.get(addToSelection?"file_selection_dialog.mark_description":"file_selection_dialog.unmark_description")+" :");
        northPanel.add(label);

        JPanel tempPanel = new JPanel();
        tempPanel.setLayout(new BoxLayout(tempPanel, BoxLayout.X_AXIS));
        comparisonComboBox = new JComboBox<>();
        comparisonComboBox.addItem(Translator.get("file_selection_dialog.contains"));
        comparisonComboBox.addItem(Translator.get("file_selection_dialog.starts_with"));
        comparisonComboBox.addItem(Translator.get("file_selection_dialog.ends_with"));
        comparisonComboBox.addItem(Translator.get("file_selection_dialog.is"));
        comparisonComboBox.addItem(Translator.get("file_selection_dialog.matches_regexp"));
        comparisonComboBox.setSelectedIndex(comparison);
        tempPanel.add(comparisonComboBox);
				
        // selectionField is initialized with last textfield's value (if any)
        selectionField = new JTextField(keywordString);
        selectionField.addActionListener(this);
        selectionField.setSelectionStart(0);
        selectionField.setSelectionEnd(keywordString.length());
        tempPanel.add(selectionField);
        northPanel.add(tempPanel);

        // Add some vertical space
        northPanel.addSpace(10);
		
        caseSensitiveCheckBox = new JCheckBox(Translator.get("file_selection_dialog.case_sensitive"), caseSensitive);
        northPanel.add(caseSensitiveCheckBox);

        includeFoldersCheckBox = new JCheckBox(Translator.get("file_selection_dialog.include_folders"), includeFolders);
        northPanel.add(includeFoldersCheckBox);
		
        northPanel.addSpace(10);
        northPanel.add(Box.createVerticalGlue());

        contentPane.add(northPanel, BorderLayout.NORTH);

        okButton = new JButton(Translator.get(addToSelection?"file_selection_dialog.mark":"file_selection_dialog.unmark"));
        contentPane.add(DialogToolkit.createOKCancelPanel(okButton, new JButton(Translator.get("cancel")), getRootPane(), this), BorderLayout.SOUTH);

        // Selection field receives initial keyboard focus
        setInitialFocusComponent(selectionField);

        setMinimumSize(MINIMUM_DIALOG_DIMENSION);
        setMaximumSize(MAXIMUM_DIALOG_DIMENSION);
    }


    ////////////////////////////
    // ActionListener methods //
    ////////////////////////////
	
    public void actionPerformed(ActionEvent e) {
        Object source = e.getSource();

        FileTable activeTable = mainFrame.getActiveTable();

        // Action coming from the selection dialog
        if ((source==okButton || source==selectionField)) {
            // Save values for next time this dialog is invoked
            caseSensitive = caseSensitiveCheckBox.isSelected();
            includeFolders = includeFoldersCheckBox.isSelected();
            comparison = comparisonComboBox.getSelectedIndex();


            String testString;
            keywordString = selectionField.getText();
            if(comparison!=REGEXP) {
                // Remove '*' characters
                testString = keywordString.replace("*", "");
            }
            else {
                testString = keywordString;
            }

            // Instantiate the main file filter
            FileFilter filter;
            switch (comparison) {
                case CONTAINS:
                    filter = new ContainsFilenameFilter(testString, caseSensitive);
                    break;
                case STARTS_WITH:
                    filter = new StartsWithFilenameFilter(testString, caseSensitive);
                    break;
                case ENDS_WIDTH:
                    filter = new EndsWithFilenameFilter(testString, caseSensitive);
                    break;
                case IS:
                    filter = new EqualsFilenameFilter(testString, caseSensitive);
                    break;
                case REGEXP:
                default:
                    try {
                        filter = new RegexpFilenameFilter(testString, caseSensitive);
                    }
                    catch(PatternSyntaxException ex) {
                        // Todo: let the user know the regexp is invalid
                        LOGGER.debug("Invalid regexp", ex);

                        // This filter does match any file
                        filter = new PassThroughFileFilter(false);
                    }
                    break;
            }

            // If folders are excluded, add a regular file filter and chain it with an AndFileFilter
            if(!includeFolders) {
                filter = new AndFileFilter(
                    new AttributeFileFilter(FileAttribute.FILE),
                    filter
                );
            }

            // Mark/unmark the files using the filter
            activeTable.getFileTableModel().setFilesMarked(filter, addToSelection);

            // Notify registered listeners that currently marked files have changed on this FileTable
            activeTable.fireMarkedFilesChangedEvent();

            activeTable.repaint();
        }
		
        dispose();
    }

}
