package com.pictc.utils;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;


public class IoUtils {
	
	private final static Charset charset=Charset.forName("UTF-8");

	private final static ForkJoinPool forkJoinPool = new ForkJoinPool();

	public static void closeQuietly(Closeable... closeables) {
		if (closeables == null)
			return;

		for (Closeable closeable : closeables) {
			if (closeable == null)
				return;

			try {
				closeable.close();
			} catch (IOException ignored) {
			}
		}
	}

	// In JDK 1.6, java.net.Socket doesn't implement Closeable, so we have this
	// overload.
	public static void closeQuietly(final Socket... sockets) {
		if (sockets == null)
			return;

		for (Socket socket : sockets) {
			if (socket == null)
				return;

			try {
				socket.close();
			} catch (IOException ignored) {
			}
		}
	}
	
	

	/**
	 * Returns the text read from the given reader as a String. Closes the given
	 * reader upon return.
	 */
	public static String getText(Reader reader) throws IOException {
		try {
			StringBuilder source = new StringBuilder();
			BufferedReader buffered = new BufferedReader(reader);
			String line = buffered.readLine();

			while (line != null) {
				source.append(line);
				source.append('\n');
				line = buffered.readLine();
			}

			return source.toString();
		} finally {
			closeQuietly(reader);
		}
	}

	/**
	 * Returns the text read from the given file as a String.
	 */
	public static String getText(File path) throws IOException {
		return getText(new FileReader(path));
	}


	public static String getText(InputStream stream) throws IOException {
		return getText(new InputStreamReader(stream,charset));
	}
	
	public static String getText(InputStream stream,Charset charset) throws IOException {
		return getText(new InputStreamReader(stream,charset));
	}

	public static void createDirectory(File dir) throws IOException {
		if (!dir.exists()) {
			dir.mkdirs();
		}
	}

	public static void copyStream(InputStream in, OutputStream out) throws IOException {
		byte[] buffer = new byte[8192];

		try {
			int read = in.read(buffer);
			while (read > 0) {
				out.write(buffer, 0, read);
				read = in.read(buffer);
			}
		} finally {
			closeQuietly(in, out);
		}
	}

	public static void copyFile(File source, File target) throws FileNotFoundException, IOException {
		if (!source.isFile())
			throw new IOException(
					String.format("Error copying file %s to %s; source file does not exist", source, target));

		createDirectory(target.getParentFile());
		doCopyFile(source, target);
		checkSameSize(source, target);
	}

	public static List<File> listFilesRecursively(File baseDir) throws IOException {
		if (!baseDir.exists())
			return Collections.emptyList();

		List<File> result = new ArrayList<File>();
		doListFilesRecursively(baseDir, result);
		return result;
	}

	public static String getFileExtension(String filename) {
		int index = filename.lastIndexOf('.');
		return index == -1 ? null : filename.substring(index + 1, filename.length());
	}
	
	public static void createFile(File file) throws IOException {
		if(!file.exists()) {
			if(file.isDirectory()) {
				file.mkdirs();
			}else {
				file.getParentFile().mkdirs();
				file.createNewFile();
			}
		}
	}

	private static void doListFilesRecursively(File baseDir, List<File> result) throws IOException {
		List<File> dirs = new ArrayList<File>();
		File[] files = baseDir.listFiles();
		if (files == null) {
			throw new IOException("Failed to list files of directory '" + baseDir + "'");
		}
		for (File file : files) {
			if (file.isFile()) {
				result.add(file);
			} else {
				dirs.add(file);
			}
		}
		for (File dir : dirs) {
			doListFilesRecursively(dir, result);
		}
	}

	private static void doCopyFile(File source, File target) throws IOException {
		FileInputStream in = null;
		FileOutputStream out = null;

		try {
			in = new FileInputStream(source);
			out = new FileOutputStream(target);
			// instead of checking transferred size, we'll compare file sizes in
			// checkSameSize()
			in.getChannel().transferTo(0, Long.MAX_VALUE, out.getChannel());
		} finally {
			closeQuietly(in, out);
		}
	}

	private static void checkSameSize(File source, File target) throws IOException {
		long fromSize = source.length();
		long toSize = target.length();

		if (fromSize != toSize)
			throw new IOException(
					String.format("Error copying file %s to %s; source file size is %d, but target file size is %d",
							source, target, fromSize, toSize));
	}

	public static byte[] getBytes(InputStream in) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		copyStream(in, out);
		return out.toByteArray();
	}
	
	public static byte[] getBytes(File in) throws IOException {
		return getBytes(new FileInputStream(in));
	}

	public static void streamToFile(InputStream in, File file) throws IOException {
		if (!file.exists()) {
			//createDirectory(file.getParentFile());
			file.createNewFile();// 将压缩文件内容写入到这个文件中
		}
		FileOutputStream fos = new FileOutputStream(file);
		int count;
		byte[] buf = new byte[8192];
		while ((count = in.read(buf)) != -1) {
			fos.write(buf, 0, count);
		}
		fos.flush();
		closeQuietly(in, fos);
	}
	
	public static void byteToFile(byte[] bytes, File file) throws IOException {
		if (!file.exists()) {
			//createDirectory(file.getParentFile());
			file.createNewFile();// 将压缩文件内容写入到这个文件中
		}
		FileOutputStream fos = new FileOutputStream(file);
		fos.write(bytes);
		fos.flush();
		closeQuietly(fos);
	}

	public static void writeFile(File file, OutputStream out, boolean close) throws IOException {
		FileInputStream in = null;
		try {
			in = new FileInputStream(file);
			int count;
			byte[] buf = new byte[8192];
			while ((count = in.read(buf)) != -1) {
				out.write(buf, 0, count);
			}
			out.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} finally {
			closeQuietly(in);
			if (close) {
				closeQuietly(out);
			}
		}
	}
	
	
	private static class FileSizeFinder extends RecursiveTask<Long> {
        /**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		final File file;
        public FileSizeFinder(final File theFile) {
            file = theFile;
        }
        @Override
        public Long compute() {
            long size = 0;
            if (file.isFile()) {
                size = file.length();
            } else {
                final File[] children = file.listFiles();
                if (children != null) {
                    List<ForkJoinTask<Long>> tasks = new ArrayList<ForkJoinTask<Long>>();
                    for (final File child : children) {
                        if (child.isFile()) {
                            size += child.length();
                        } else {
                            tasks.add(new FileSizeFinder(child));
                        }
                    }
                    for (final ForkJoinTask<Long> task : invokeAll(tasks)) {
                        size += task.join();
                    }
                }
            }
            return size;
        }
    }

	public static long getFileSize(File file) {
		return forkJoinPool.invoke(new FileSizeFinder(file));
	}
	
	public static String getProjectPath() {
		String url=Thread.currentThread().getContextClassLoader().getResource("").getPath();
		try {
			url=url.substring(1, url.length()-15);
			if(url.contains("/targe")) {
				url = url.replace("/targe","");
			}
			return URLDecoder.decode(url,"utf-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return url;
	}
	
	public static void delFile(File file) {
		if(file.isDirectory()) {
			File[] childs = file.listFiles();
			if(childs!=null) {
				for (int i = 0; i < childs.length; i++) {
					if(childs[i].isDirectory()) {
						delFile(childs[i]);
					}else {
						childs[i].delete();
					}
				}
			}
		}
		file.delete();
	}
	
	public static List<File> findFile(File file,FilenameFilter filter) {
		List<File> res = new ArrayList<File>();
		findChilds(res, file, filter);
		return res;
	}
	
	private static void findChilds(List<File> res,File file,FilenameFilter filter) {
		if(file.isDirectory()) {
			File[] delFiles=file.listFiles(filter);
			for (int i = 0; i < delFiles.length; i++) {
				res.add(delFiles[i]);
			}
			File[] childs= file.listFiles();
			for (int i = 0; i < childs.length; i++) {
				findChilds(res,childs[i],filter);
			}
		}
	}
}

