package common.utility;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
//import java.nio.file.Files;
//import java.nio.file.Path;
//import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Scanner;

import javax.imageio.ImageIO;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.apache.log4j.Logger;

public class FileUtilities {
	
	public static List<String> FilesInFolder (String path, String extension, boolean stripExtension) {
		List<String> res = new ArrayList<String>();
		File folder = new File(path);
		File[] listOfFiles = folder.listFiles();
		
		for (File file: listOfFiles) {
			if (file.isFile() && (extension==null || file.getName().toLowerCase().endsWith(extension.toLowerCase())))
				if (!stripExtension)
		    	  res.add(file.getName());
				else
					res.add(FilenameUtils.removeExtension(file.getName()));
		}
		return res;
	}
	
	public static List<String> FoldersInFolder (String path, String startingText) {
		
		final String startText = startingText;
		File file = new File(path);
		String[] directories = file.list(new FilenameFilter() {
			public boolean accept(File dir, String name) {
				return new File(dir, name).isDirectory() && name.startsWith(startText);
			}
		});
		
		return Arrays.asList(directories);
	}
	
	public static int countFilesInFolder(String path, String mask){
		File folder = new File(path);
		FileFilter fileFilter = new WildcardFileFilter(mask);
		File[] files = folder.listFiles(fileFilter);
		return files.length;
	}
	
	public static String FileToString(String fileName) throws IOException {
		
		return FileUtils.readFileToString(new File(fileName), (Charset)null);

	}
	
	public static List<String> FileToStringList(String fileName) {
		
		Scanner s;
		try {
			s = new Scanner(new File(fileName));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return new ArrayList<String>();
		}
		ArrayList<String> list = new ArrayList<String>();
		while (s.hasNextLine()){
		    list.add(s.nextLine());
		}
		s.close();
		
		return list;

	}
	
	public static boolean StringListToFile(List<String> lines, String fileName) {
		PrintWriter pw;
		try {
			pw = new PrintWriter(new FileOutputStream(fileName));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
		for(String line: lines)
			pw.println(line);
		
		pw.flush();
		pw.close();
		return true;
	}
	
	public static byte[] FileToBytes(String fileName) {
		
		try {
			return FileUtils.readFileToByteArray(new File(fileName));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}

	}

	public static String StringToFile(String fileName, String string) {
		try {
			FileUtils.writeStringToFile(new File(fileName), string, (Charset)null);
			return null;
		}  catch(Exception ex) {
			ex.printStackTrace();
			return ex.getLocalizedMessage();
		}	
	}

	public static boolean deleteFolder(String path) {
		List<String> files = FilesInFolder(path,null,false);
		boolean res = true;
		for(String file:files)
			res |= new File(file).delete();
		return res;
	}

	public static boolean deleteFile(String fileName) {
		File file = new File(fileName);
		return file.delete();
	}
	
	public static Object ObjectToFile(String fileName, Object obj) {
		try {
			ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(fileName));
			objectOutputStream.writeObject(obj);
			objectOutputStream.flush();
			objectOutputStream.close();
			return null;
		}  catch(Exception ex) {
			ex.printStackTrace();
			return ex.getLocalizedMessage();
		}	
	}

	public static Object FileToObject(String fileName) {
		try {
			ObjectInputStream objectInputStream = new ObjectInputStream(
			        new FileInputStream(fileName));
			Object res = objectInputStream.readObject();
			objectInputStream.close();
			return res;
		}  catch(Exception ex) {
			ex.printStackTrace();
			return ex.getLocalizedMessage();
		}	
	}
	
	public static byte[] fromFileToByte(String pathFile) throws IOException 
    {
		File file = new File(pathFile);
		InputStream is = new FileInputStream(file);
		byte[] bytes =  null;
		try {
			long length = file.length();
			bytes = new byte[(int)length];
			// Read in the bytes
			int offset = 0;
			int numRead = 0;
			while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
				offset += numRead;
			}
			// Ensure all the bytes have been read in
			if (offset < bytes.length) {
				throw new IOException("Impossibile leggere il file " + file.getName());
			}
		} finally {
			// Close the input stream and return bytes
			is.close();
		}
		return bytes;
	}
    
	public static void fromByteToFile(byte[] bytes,
	                                  File file)
	{
		BufferedOutputStream bos = null;

		try
		{
			//create an object of FileOutputStream
			FileOutputStream fos = new FileOutputStream(file);
			//create an object of BufferedOutputStream
			bos = new BufferedOutputStream(fos);

			/*
			 * To write byte array to file use,
			 * public void write(byte[] b) method of BufferedOutputStream
			 * class.
			 */
			bos.write(bytes);
		}
		catch (FileNotFoundException fnfe)
		{
			fnfe.printStackTrace();
		}
		catch (IOException ioe)
		{
			ioe.printStackTrace();
		}
		finally
		{
			if (bos != null)
			{
				try
				{
					//flush the BufferedOutputStream
					bos.flush();
					//close the BufferedOutputStream
					bos.close();
				}
				catch (Exception e)
				{
				}
			}
		}
	}

    //Elimina una cartella e le sue sottocartelle compresi i file
    public static boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (int i=0; i<children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }

        // The directory is now empty so delete it
        return dir.delete();
    }

    //Elimina file e sottocartelle da una cartella
    public static boolean clearDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (int i=0; i<children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }

        return true;
        
    }

    
    //Copia file
    public static void copy(File source, File dest) throws IOException {
        FileChannel in = null, out = null;
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
        	fis = new FileInputStream(source); 
             in = fis.getChannel();
             fos = new FileOutputStream(dest);
             out = fos.getChannel();

             in.transferTo( 0, in.size(), out);
        } finally {
             if (in != null)
                 in.close();
             if (out != null)
                 out.close();
         	if (fis!=null)
        		fis.close();
        	if (fos != null)
        		fos.close();

        }
   }
    
    public static String getFileNameFromPath(String path)
    {
 	   File file = new File(path);
 	   return file.getName();
    }
    
    public static String getExtension(String fileName)
    {
 	   String ext = "";
 	   if(!StringUtilities.empty(fileName, true))
 		   ext = fileName.substring(fileName.lastIndexOf(".") + 1);
 	   return ext;
    }
    
    public static String getContentType(String tipoFile)
  	{
  		if(tipoFile.equals("pdf"))
  			return "application/pdf";
  		else if(tipoFile.equals("zip"))
  			return "application/zip";
  		else if(tipoFile.equals("rar"))
  			return "application/rar";
  		else if(tipoFile.equals("doc"))
  			return "application/msword";
  		else if(tipoFile.equals("jpg"))
  			return "image/jpg";
  		else if(tipoFile.equals("jpeg"))
  			return "image/jpeg";
  		else if(tipoFile.equals("bmp"))
  			return "imgae/bmp";
  		else if(tipoFile.equals("tif"))
  			return "image/tif";
  		else if(tipoFile.equals("tiff"))
  			return "imgae/tiff";
  		else if(tipoFile.equals("gif"))
  			return "image/gif";
  		else if(tipoFile.equals("png"))
  			return "image/png";
  		else
  			return "application/octet-stream";
  	}
    
    public static byte[] resizeImage(File fileUploaded) throws IOException
    {
    	final int IMG_WIDTH = 130;
    	final int IMG_HEIGHT = 130;
    	BufferedImage originalImage = ImageIO.read(fileUploaded);
		int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
    	
		BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
    	Graphics2D g = resizedImage.createGraphics();
    	g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
    	g.dispose();
     
    	File file = new File(new Date().getTime() + "");
    	ImageIO.write(resizedImage, "jpg", file); 
    	
    	return fromFileToByte(file.getAbsolutePath());
    }
    
    public static List<String> listFilesOnly(String directoryName) {
    	Logger logger = Logger.getLogger(FileUtilities.class);
        if (logger.isDebugEnabled())
        	logger.debug(String.format("reading folder: %s", directoryName));
        
    	File directory = new File(directoryName);
        List<String> res = new ArrayList<String>();

        
        // get all the files from a directory
        File[] fList = directory.listFiles();
        
        if (logger.isDebugEnabled())
        	logger.debug(String.format("		...found %d files", fList.length));
        
        for (File file : fList) {
            if (file.isFile()) {
                res.add(file.getName());
                
                if (logger.isDebugEnabled())
                	logger.debug(String.format("		...adding file %s", file.getName()));
                
            } else if (file.isDirectory()) {
            	if (logger.isDebugEnabled())
                	logger.debug(String.format("		...adding folder %s", file.getName()));
                res.addAll(listFilesOnly(file.getAbsolutePath()));
            }
        }
        
        
        if (logger.isDebugEnabled())
        	logger.debug("done reading files");
        
        return res;
    }

    public static List<String> listFilesWithPath(String directoryName) {
    	File directory = new File(directoryName);
        List<String> res = new ArrayList<String>();

        
        // get all the files from a directory
        File[] fList = directory.listFiles();
        
        for (File file : fList) {
            if (file.isFile()) {
                res.add(file.getAbsolutePath());
            } else if (file.isDirectory()) {
                res.addAll(listFilesWithPath(file.getAbsolutePath()));
            }
        }
        
        return res;
    }
 
    public static List<String> bytesToStringList(byte[] bytes) {
	      List<String> lines = new ArrayList<String>();

	      if (bytes == null) {
	        return lines;
	      }

	      BufferedReader r = null;

	      try {
	        r = new BufferedReader(
	                new InputStreamReader(
	                    new ByteArrayInputStream(bytes)));
	      } catch (Exception e) {
	        // If UTF-8 is not supported we are in big trouble.
	        e.printStackTrace();
	        return null;
	      }

	      try {
	        try {
	          for (String line = r.readLine(); line != null; line = r.readLine()) {
	            lines.add(line);
	          }
	        } finally {
	          r.close();
	        }
	      } catch (IOException e) {
	        // I can't think of a reason we'd get here.
	        throw new RuntimeException(e);
	      }

	      return lines;
	    }	

}
