package tools;

import java.util.regex.*;
import java.io.*;
import java.nio.*;
import java.nio.charset.*;
import java.nio.channels.*;
import java.util.*;

import org.apache.log4j.*;

/**
* 
* This program is intended to help a person in finding out the list of 
* 'unused' files in a given project directory. 
*
* The input: A directory name with the complete path. For eg. D:\TJX\SupplyReq to
* supplied at the command line (or to the method load loadFileNames if being
* invoked programmatically).
* 
* The output: Printed out on the output configured with log4j.properties.
* 
 */
 
public class NewMatcher
{
	private ArrayList filePathsArrayList = new ArrayList();    
	private ArrayList projectFilesList = new ArrayList();
	private ArrayList junkFilesList = new ArrayList();

	private static Logger logger = Logger.getLogger("tools.NewMatcher");

	/**
	* This method checks whether the regex passed is matched
	* if the search pattern is found the method returns true
	* else it returns false.
	*
	* @return boolean
	* @exception IOException. 
	*/
	private boolean isFound(String regExpression, String filename) throws IOException
	{

		//logger.debug("isFound method - Start");
		//logger.debug("regEx is "+regExpression);
		//logger.debug("filename is "+filename);
		// Create matcher on file
		Pattern pattern = Pattern.compile(regExpression);
		Matcher matcher = pattern.matcher(fromFile(filename));
		return matcher.find();

	}

	/**
	* This method returns the charactersequence of the fileName.
	* 
	* @param filename as String.
	* @return CharSequence. 
	* @exception IOException.
	*/
	private CharSequence fromFile(String filename) throws IOException
	{
		FileInputStream fis = new FileInputStream(filename);

		//Returns the unique FileChannel object associated
		//with this file input stream.
		FileChannel fc = fis.getChannel();

		// Create a read-only CharBuffer on the file
		ByteBuffer bbuf = fc.map(FileChannel.MapMode.READ_ONLY, 0, (int)fc.size());

		CharBuffer cbuf = Charset.forName("8859_1").newDecoder().decode(bbuf);
		return cbuf;

	}

    
    public NewMatcher()
    {
        BasicConfigurator.configure();
    }
    
     /**
      * This method loads the file names into an ArrayList
      *
      * @param path as String.
      * @returns ArrayList of FileNames.
      * @exception IOException.
      */
     public void loadFileNames(String path)
     throws IOException
     {
        logger.debug("*****************************");
        logger.debug("Method loadFileNames -Start");
        logger.debug("path is ="+path);
        File file = new File(path);
        addFiles(file);
        
        
        Iterator arrayListIterator = filePathsArrayList.iterator();
        
        ArrayList clonedFilePathsArrayList = (ArrayList)filePathsArrayList.clone();
        
        
        boolean isReferenced ;
        while(arrayListIterator.hasNext())
        {
            isReferenced = false;
            String outerFileNameWithPath = ((File)arrayListIterator.next()).getPath();
            String fileName = new File(outerFileNameWithPath).getName();
            // check if this file is referenced by any other file in the array list
            
            Iterator jAIterator = clonedFilePathsArrayList.iterator();
            while(jAIterator.hasNext())
            {
                String fileWithPathName = ((File)jAIterator.next()).getPath();  
               //logger.debug("filewithPath = "+fileWithPathName);
                String fileToBeSearched = new File(fileWithPathName).getName();

                if(!fileToBeSearched.equals(fileName))
                {
                     if (isFound(fileName,fileWithPathName))
                     {
                          //logger.debug("Adding file to the ProjectFileList"+fileWithPathName);
                           projectFilesList.add(outerFileNameWithPath);
                           isReferenced = true;
                     }
                     
                }
                if(isReferenced)
                {
                    break;
                }
            }
            
            if(!isReferenced)
            {
                   //logger.debug("Adding file to the JUNK FileList"+fileName);
                 junkFilesList.add(outerFileNameWithPath);
            }
        }
        
        logger.debug("Total no of project files list ="+projectFilesList.size());            
        logger.debug("Total no of junk files list ="+junkFilesList.size());            
        logger.debug("Method loadFileNames -End");
        logger.debug("****************************");
        logger.debug("PROJECT FILES LIST IS");            
        
        Iterator projectFilesListIterator = projectFilesList.iterator();
        while(projectFilesListIterator.hasNext())
        {
           logger.debug((String)projectFilesListIterator.next());
        }
        
        logger.debug("****************************");
        logger.debug("JUNK FILES LIST IS");        

        Iterator junkFilesListIterator = junkFilesList.iterator();
        while(junkFilesListIterator.hasNext())
        {
          logger.debug((String)junkFilesListIterator.next());
        }
        
     }
     
     /**
      * This method adds the files fron the directory to the ArrayList
      * If there is a sub-directory with in a directory it will call
      * the function again(recursion).
      *
      * @param files as File[] array
      * @throws IOException.
      */
     public void addFiles(File file)  throws IOException
     {
        //retrieves the files length.
        File[] files = file.listFiles();
        int len = files.length;
       //logger.debug("Files Length is "+len);
        
        for(int i =0 ; i <len ; i ++ )
        {
            if(files[i].isDirectory())
            {
                //logger.debug("directory name is "+files[i]);
                addFiles(files[i]);
            }
            else if(files[i].isFile())
            {
               //logger.debug("file name is "+files[i]);
                 filePathsArrayList.add(files[i]);
            }
        }
     }
     
     public static void main(String[] args) throws Exception
     {
     	   if(args.length != 1) {
				NewMatcher.logger.info("Wrong Usage.");
				NewMatcher.logger.info("Correct Usage: java tools.NewMatcher <name_of_the_dir_to_be_searched>");
     	   }
     	   else {
			   try
			   {
				   NewMatcher.logger.info("Directory that will be searched:" + args[0]);
				   BufferedReader  in = new BufferedReader(new InputStreamReader(System.in));
				   new NewMatcher().loadFileNames(in.readLine());
				   Date endDate = new Date();

				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
		   }
     }
}