/*
 * @(#)FileExtensionFilter.java    2.4.0   24 August 2005
 *
 * Copyright 2005
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.util;

import edu.neu.ccs.*;

import java.io.*;
import java.util.*;
import javax.swing.*;

/**
 * <p>Class <code>FileExtensionFilter</code> is a file filter that
 * both extends <code>javax.swing.filechooser.FileFilter</code>
 * and implements <code>java.io.FileFilter</code>; the filter uses
 * 0 or more file extensions to determine whether or not to accept
 * a file; the user can decide whether the matching should ignore
 * case or be case sensitive; the default is to ignore case in the
 * matching.</p>
 *
 * <p>Because a filter of this class extends an abstract class and
 * implements a related interface, such a filter may be passed to:</p>
 *
 * <ul>
 *   <li>The <code>setFileFilter</code> method of <code>JFileChooser</code>.</li>
 *   <li>The <code>listFiles</code> method of <code>File</code>.</li>
 * </ul>
 *
 * <p>A filter of this class returns true for directories.</p>
 *
 * <p>This class generalizes and supercedes the inner class
 * <code>ExtensionFileFilter</code> of <code>FileView</code>
 * but that class has been left in place for backward
 * compatibility.</p>
 */
public class FileExtensionFilter
    extends    javax.swing.filechooser.FileFilter
    implements java.io.FileFilter
{
    /** The filter as a comma separated String.*/
    private String commaList = "";
    
    /** The filter as an array of extensions.*/
    private String[] arrayList = new String[0];
    
    /** The length of extArray. */
    private int N = 0;
    
    /**
     * <p>Whether or not to ignore case in the match.</p>
     *
     * <p>The default is true.</p>
     */
    private boolean ignoreCase = true;
    
    /** The description for file dialog boxes. */
    private String dialogDescription = "All Files";
    
    
    /** The default constructor that filters nothing. */
    public FileExtensionFilter() { }
    
    
    /**
     * <p>The constructor that filters files whose extensions are found
     * in the given comma separated list.</p>
     *
     * <p>By default, case is ignored in matching.</p>
     *
     * @param commaList the comma separated list of extensions
     */
    public FileExtensionFilter(String commaList) {
        setExtensions(commaList);
    }
    
    
    /**
     * <p>The constructor that filters files whose extensions are found
     * in the given String array.</p>
     *
     * <p>By default, case is ignored in matching.</p>
     *
     * @param arrayList the array list of extensions
     */
    public FileExtensionFilter(String[] arrayList) {
        setExtensions(arrayList);
    }
    
    
    /**
     * <p>The constructor that filters files whose extensions are found
     * in the given comma separated list
     * and sets whether to ignore case in matching.</p>
     *
     * @param commaList the comma separated list of extensions
     * @param ignoreCase whether to ignore case in matching
     */
    public FileExtensionFilter(String commaList, boolean ignoreCase) {
        setExtensions(commaList);
        setIgnoreCase(ignoreCase);
    }
    
    
    /**
     * <p>The constructor that filters files whose extensions are found
     * in the given String array
     * and sets whether to ignore case in matching.</p>
     *
     * @param arrayList the array list of extensions
     * @param ignoreCase whether to ignore case in matching
     */
    public FileExtensionFilter(String[] arrayList, boolean ignoreCase) {
        setExtensions(arrayList);
        setIgnoreCase(ignoreCase);
    }
    
    
    /**
     * <p>Sets the extensions to filter using the given comma separated list.</p>
     *
     * @param commaList the comma separated list of extensions
     */
    public final void setExtensions(String commaList) {
        if (commaList == null)
            commaList = "";
        
        this.commaList = commaList;
        this.arrayList = Strings.splitCommaList(commaList);
        this.N = this.arrayList.length;
        this.dialogDescription = makeStandardDescription();
    }
    
    
    /**
     * <p>Sets the extensions to filter using the given String array list.</p>
     *
     * @param arrayList the array list of extensions
     */
    public final void setExtensions(String[] arrayList) {
        if (arrayList == null)
            arrayList = new String[0];
        
        this.commaList = Strings.makeCommaList(arrayList);
        this.arrayList = arrayList;
        this.N = this.arrayList.length;
        this.dialogDescription = makeStandardDescription();
    }
    
    
    /** Returns the extensions for this filter as a comma separated list. */ 
    public final String getExtensionsAsCommaList() {
        return commaList;
    }
    
    
    /**
     * <p>Sets whether to ignore case when matching a file name to an
     * extension.</p>
     *
     * @param ignoreCase whether to ignore case in matching
     */
    public final void setIgnoreCase(boolean ignoreCase) {
        this.ignoreCase = ignoreCase;
    }
    
    
    /** Returns the current ignore case setting. */
    public final boolean getIgnoreCase() {
        return ignoreCase;
    }
    
    
    /**
     * <p>Whether the given file is accepted by this filter.</p>
     *
     * @param f the file to test
     */
    public final boolean accept(File f) {
        // false since there is no file object
	    if (f == null)
		    return false;
	
        // true since there are no extensions
	    if (N == 0)
		    return true;
	
        // true to allow directory navigation
	    if (f.isDirectory())
		    return true;
	    
	    // prepare to examine file name
	    String name = f.getName();
	    int S = name.length();
	    
	    // loop over extensions and return true if the file matches the extension
	    for (int i = 0; i < N; i++) {
	        String ext = arrayList[i];
	        int E = ext.length();
	        
	        // cannot match since name is too short
	        if (S <= E)
	            continue;
	        
	        // test is true if
	        //   the character in name at position (S - E - 1) is a period
	        //   and the last E characters in name match via regionMatches
	        
	        boolean test = (name.charAt(S - E - 1) == '.')
	            && name.regionMatches(true, S - E, ext, 0, E);
	        
	        if (test)
	            return true;
	    }
	    
	    // return false if no match was found
	    return false;
    }
    
    
    /**
     * Returns the text description of the filtered files for a
     * <code>JFileChooser</code> dialog box.
     */
    public String getDescription() {
        return dialogDescription;
    }
    
    
    /** Create the standard dialog box description. */
    protected String makeStandardDescription() {
        if (N == 0)
            return "All Files";
        else
        if (N == 1)
            return "*." + commaList;
        else
            return "*.? for ? = " + commaList;
        
    }
    
}
