/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package jblackout.util;

import java.io.File;
import java.io.FileFilter;
import java.util.Stack;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This Class walks the filesystem trying to find 
 * media that match the extensions provided to the constructor. The matched files
 * are return via the getFiles() method after the search completes.
 * @author Jason Ederle
 */
public class BreadthFirstSearcher implements FileFilter {

    
    //Starting folder
    public String root;
    
    //folders to process
    private Stack<File> stack;
    
    //media that has a supported extension
    private Vector<File> media;
    
    //number of folders processed from the stack
    private int numFoldersProcessed = 0;
    
    //The supported files to find ( set from constructor )
    String[] supportedExtensions;
    
    
    private static Logger logger = Logger.getLogger(BreadthFirstSearcher.class.getName());
    
    
    /**
     * Constructor that set's the starting search position and array of extensions to support.
     * @param searchRoot
     * @param extensionsToFind - array in form ".mp3", ".ogg", ".doc" etc.
     */
    public BreadthFirstSearcher(String searchRoot, String[] extensionsToFind){
        this.root = searchRoot;
        this.supportedExtensions = extensionsToFind;
        
        stack = new Stack<File>();
        media = new Vector<File>();
    }
    
    
    
    /**
     * Begin searching from the root down.
     * @return
     */
    public boolean search(){
        
        //jump start the recursion with the root
        File rootFolder = new File(root);
        if(rootFolder.exists()){
            logger.log(Level.INFO, "Root looks good..starting recursive search.");
            
            stack.push(rootFolder);
            
            //start the recursive search
            searchDeeper();
            
            return true;
        }else{
            logger.log(Level.SEVERE, "Root doesn't exist, can't search for any local files.");
            return false;
        }
        
    }
    
    
    /**
     * Get the media that was found during the search.
     * @return
     */
    public Vector<File> getFiles(){
        return media;
    }
    
    
    
    /**
     * Get the folder numFoldersProcessed that the search is at. This changes
     * if called during the search process.
     * @return
     */
    public int numberOfProcessedFolders(){
        return numFoldersProcessed;
    }
    
    
    
    /**
     * Performs a recursive search starting on the rootFolder until the stack is empty.
     */
    private void searchDeeper(){
        
        //start with exit condition
        if(stack.empty()){
            logger.log(Level.INFO, "Hit end of recursive search.");
            return;
        }
        
        //explore items in the folder, and push internal folders onto stack to be processed later
        File aFolder = stack.pop();
        File[] goodFiles = aFolder.listFiles(this);
        
        //keep the good files
        for(int i=0; i<goodFiles.length; i++){
            media.add( goodFiles[i] );
        }
        
        //free memory
        goodFiles = null;
        
        //track the numFoldersProcessed
        numFoldersProcessed++;
        
        //continue searching
        searchDeeper();
    }

    
    /**
     * Tests if the file should be allowed or not.
     * @param aFile - a File object to examine
     * @return
     */
    public boolean accept(File aFile) {
        if(aFile.isDirectory()){
            stack.push(aFile);
            return false;
        }
        
        for(int i=0; i< supportedExtensions.length; i++){
            //check each supported extension
            if(aFile.getName().endsWith( supportedExtensions[i] )){
                
                logger.log(Level.INFO, "Found -  " + aFile.getName() + " Depth: " + numFoldersProcessed);
                return true;
            }
        }
        
        
        //if no matches from loop it's not supported
        return false;
    }
    
    
    
    
    /**
     * Test the finder and print out results.
     * @param args
     */
    public static void main(String[] args){
 
        //the folder to start searching from 
        String startingFolder = "###### PUT YOUR START FOLDER HERE ########";
        
        //The supported files to find
        String[] extensionsToFind = {".mp3"};
        
        BreadthFirstSearcher finder = new BreadthFirstSearcher(startingFolder, extensionsToFind);
        finder.search();
        
        //Print status
        logger.log(Level.INFO, 
                "Completed Search: " + finder.getFiles().size() + " Files, " +
                "inside " + finder.numberOfProcessedFolders() + " folders.");
        
        
    }
    
    
    
}
