/*******************************************************************************
 * Copyright (c) 2010 Robert "Unlogic" Olofsson (unlogic@unlogic.se).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v3
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-3.0-standalone.html
 ******************************************************************************/
package se.unlogic.standardutils.io;

import se.unlogic.standardutils.callback.Callback;
import se.unlogic.standardutils.streams.StreamUtils;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Utility class for handling files and folders
 * 
 * @author Robert "Unlogic" Olofsson (unlogic@unlogic.se)
 * 
 */
public class FileUtils {

   public static String toAsciiFilename(String string) {

      return string.replaceAll("[^0-9a-zA-Z-.]", "_");
   }

   public static String toValidHttpFilename(String string) {

      return string.replaceAll("[^0-9a-�A-�-+. ()-+!@�&%$�=�]", "_");
   }

   public final static byte[] getRawBytes(File f) throws IOException {
      FileInputStream fin = new FileInputStream(f);
      byte[] buffer = new byte[(int) f.length()];
      fin.read(buffer);
      fin.close();
      return buffer;
   }

   public static String getFileExtension(File file) {
      return getFileExtension(file.getName());
   }

   public static String getFileExtension(String filename) {

      int dotIndex = filename.lastIndexOf(".");

      if (dotIndex == -1 || (dotIndex + 1) == filename.length()) {
         return null;
      } else {
         return filename.substring(dotIndex + 1);
      }
   }

   public static boolean fileExists(String path) {

      File file = new File(path);

      return file.exists();
   }

   /**
    * Removes all files in the given directory matching the given filter
    *
    * @param directory
    *            the directory to be cleared
    * @param filter
    *            {@link FileFilter} used to filter files
    * @param recursive
    *            controls weather files should be deleted from sub directories too
    */
   public static int deleteFiles(String directory, FileFilter filter, boolean recursive) {

      return deleteFiles(new File(directory), filter, recursive);
   }

   public static int deleteFiles(File dir, FileFilter filter, boolean recursive) {

      if (dir.exists() && dir.isDirectory()) {

         int deletedFiles = 0;

         File[] files = dir.listFiles(filter);

         for (File file : files) {

            if (file.isDirectory()) {

               if (recursive) {

                  deletedFiles += deleteFiles(file, filter, recursive);
               }

            } else {

               if(file.delete()){

                  deletedFiles++;
               }
            }
         }

         return deletedFiles;
      }

      return 0;
   }

   public static int replace(File dir, String filename, File replacementFile, boolean recursive, boolean caseSensitive, Callback<File> callback) {

      if (dir.exists() && dir.isDirectory()) {

         int replacedFiles = 0;

         File[] files = dir.listFiles();

         for (File file : files) {

            if (file.isDirectory()) {

               if (recursive) {

                  replacedFiles += replace(file, filename,replacementFile, recursive, caseSensitive, callback);
               }

            } else {

               if(caseSensitive){

                  if(!file.getName().equals(filename)){

                     continue;
                  }

               }else if(!file.getName().equalsIgnoreCase(filename)){

                  continue;
               }

               if(file.canWrite()){

                  try {
                     if(callback != null){
                        callback.callback(file);
                     }

                     replaceFile(file,replacementFile);

                     replacedFiles++;

                  } catch (IOException e) {}
               }
            }
         }

         return replacedFiles;
      }

      return 0;
   }

   public static void replaceFile(File target, File replacement) throws IOException {

      FileInputStream inputStream = null;
      FileOutputStream outputStream = null;

      try{
         inputStream = new FileInputStream(replacement);
         outputStream = new FileOutputStream(target);

         inputStream.getChannel().transferTo(0, replacement.length(), outputStream.getChannel());

         StreamUtils.transfer(inputStream, outputStream);

      }finally{
         StreamUtils.closeStream(inputStream);
         StreamUtils.closeStream(outputStream);
      }
   }

   public static boolean deleteDirectory(String directoryPath) {

      return deleteDirectory(new File(directoryPath));
   }

   public static boolean deleteDirectory(File directory) {

      if (directory.exists()) {

         File[] files = directory.listFiles();

         for (File file : files) {

            if (file.isDirectory()) {
               deleteDirectory(file);
            } else {
               file.delete();
            }
         }
      }
      return directory.delete();
   }

   public static void deleteFile(String path) {

      File file = new File(path);

      if(file.exists()){
         file.delete();
      }
   }
}
