package kr.co.swh.lecture.opensource.util; 

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.HashMap;

/**
 * <pre>
 * kr.co.swh.lecture.opensource.util 
 * Nio2FilesUtil.java
 *
 * 설명 :	파일 유틸 정보
 * </pre>
 * 
 * @since : 2018. 2. 4.
 * @author : tobby48
 * @version : v1.0
 */
public class Nio2FilesUtil {

	public static boolean existFile(File fileName) {
		if(fileName == null) return false;
		return fileName.exists();
	}
	
	public static boolean existFile(String dirName) throws IOException {
		if(dirName == null) return false;
		return newFile(dirName).exists();
	}
	
	public static File getDirectory(File parent, String child){
		if (!parent.exists())
		{
			return null;
		}
		File childDir = new File(parent, child);
		return childDir;
	}
	
	public static File newFile(String fileName) throws IOException{
		return new File(fileName).getCanonicalFile();
	}
	
	public static File newFile(String parent, String child) throws IOException {
		File parentFile = newFile(parent);
		if (!parentFile.exists())
		{
			newDirectory(parentFile.getPath());
		}
		return new File(parentFile, child).getCanonicalFile();
	}
	
	public static File newFile(File parent, String child) throws IOException {
		if (!parent.exists())
		{
			newDirectory(parent.getPath());
		}
		return new File(parent, child).getCanonicalFile();
	}
	
	public static File newFile(File parent, String subParent, String child) throws IOException {
		return newFile(newDirectory(parent, subParent), child);
	}
	
	public static File newDirectory(String dirName) throws IOException {
		File dir = newFile(dirName);
        dir.mkdirs();
		return dir;
	}
	
	public static File newDirectory(String parent, String child) throws IOException {
		File parentF = newFile(parent);
		if (!parentF.exists())
		{
			newDirectory(parentF.getPath());
		}
		File childDir = newFile(parentF, child);
		childDir.mkdirs();
		return childDir;
	}
	
	public static File newDirectory(File parent, String child) throws IOException { 
		if (!parent.exists())
		{
			newDirectory(parent.getPath());
		}
		File childDir = newFile(parent, child);
		childDir.mkdirs();
		return childDir;
	}
	
	public static File newDirectory(File parent, String subParent, String child) throws IOException {
		return newDirectory(newDirectory(parent, subParent), child);
	}
	
	public static boolean isDirectory(String parent) throws IOException { 
		File parentFile = newFile(parent);
		if (parentFile == null || !parentFile.exists())
			new Exception("file not exist.");
		if(parentFile.isDirectory())
			return true;
		return false;
	}
	
	public static File isDirectory(String parent, String child) throws IOException { 
		File parentFile = newFile(parent);
		if (parentFile == null || !parentFile.exists())
			return null;
		File childDir = getDirectory(parentFile, child);
		return childDir;
	}
	
	public static File isDirectory(File parent, String child) throws IOException { 
		if (parent == null || !parent.exists())
			return null;
		File childDir = getDirectory(parent, child);
		return childDir;
	}
	
	public static boolean isDirectory(File parent, String subParent, String child) throws IOException {
		File childFile = isDirectory(isDirectory(parent, subParent), child);
		if (childFile == null || !childFile.exists())
			throw new IOException();
		return true;
	}
	
	
	public static File createFile(String fileName) throws IOException {
        File file = newFile(fileName);
        if (!file.canWrite())
        {
            String dirName = file.getPath();
            int i = dirName.lastIndexOf(File.separator);
            if (i > -1)
            {
                dirName = dirName.substring(0, i);
                File dir = newFile(dirName);
                dir.mkdirs();
            }
            file.createNewFile();
        }
        return file;
    }
	
	public static void fileNioCopy(String source, File target) throws IOException {
		Files.write(target.toPath(), source.getBytes(Charset.forName("euc-kr")));
	}
	
	public static void fileNioCopy(File source, File target) throws IOException{
		boolean success = true;
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try
		{
			fis = new FileInputStream(source);
			if (!target.exists())
			{
				createFile(target.getPath());
			}
			fos = new FileOutputStream(target);
			FileChannel srcChannel = fis.getChannel();
			FileChannel dstChannel = fos.getChannel();
			dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
			srcChannel.close();
			dstChannel.close();
		}
		catch (Exception ioex)
		{
			// grr!
			success = false;
		}
		finally
		{
			if(fis != null)
				fis.close();
			if(fos != null)
				fos.close();
		}
		if(!success){
			safeCopyFile(source, target);
		}
    }
	
	public static void directoryRenameTo(File source, File target) throws IOException {
		if (source.isDirectory()) {                
			if (!target.exists()) { 
				newDirectory(target.getPath());
			} 
			
			String[] children = source.list(); 
			for (int i=0; i<children.length; i++) { 
				directoryRenameTo(new File(source, children[i]), new File(target, children[i]));
			} 
		} else { 
			fileRenameTo(source, target);
		} 
	}
	
	public static void fileRenameTo(File source, File target) throws IOException {
        boolean success = source.renameTo(target);
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try
		{
			fis = new FileInputStream(source);
			if (!target.exists())
			{
				createFile(target.getPath());
			}
			fos = new FileOutputStream(target);
			FileChannel srcChannel = fis.getChannel();
			FileChannel dstChannel = fos.getChannel();
			dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
			srcChannel.close();
			dstChannel.close();
			success = source.delete();
		}
		catch (Exception ioex)
		{
			success = false;
		}
		finally
		{
			 if (fis != null) fis.close();
             if (fos != null) fos.close();
		}
		if(!success){
			safeCopyFile(source, target);
		}
    }
	
	private static void safeCopyFile(File source, File target) throws IOException {
        try
        {
            FileInputStream fis = new FileInputStream(source);
            FileOutputStream fos = new FileOutputStream(target);
            try
            {
                byte[] buf = new byte[1024];
                int i = 0;
                while ((i = fis.read(buf)) != -1)
                {
                    fos.write(buf, 0, i);
                }
            }
            catch (IOException e)
            {
                throw e;
            }
            finally
            {
                try
                {
                    if (fis != null) fis.close();
                    if (fos != null) fos.close();
                }
                catch (IOException e)
                {
                    throw e;
                }

            }
        }
        catch (FileNotFoundException e)
        {
            throw e;
        }
    }
	
	public static void copyDirectory(File source, File target) throws IOException { 
		if (source.isDirectory()) {                
			if (!target.exists()) { 
				target.mkdir(); 
			} 
			
			String[] children = source.list(); 
			for (int i=0; i<children.length; i++) { 
				copyDirectory(new File(source, children[i]), new File(target, children[i]));
			} 
		} else { 
			fileNioCopy(source, target);
		} 
	} 
	
	public static boolean deleteFile(File file) throws IOException {
		boolean result = true;
		if(file.exists()) {
			if(file.isDirectory()) {
				File[] files = file.listFiles();
				if(files != null && files.length > 0) {
					for(int i=0;i<files.length;i++)
						deleteFile(files[i]);
				}
			}
		}
		Files.delete(file.toPath());
//		deleteFile(file);
		return result;
	}
	
	public static void writeToFile(InputStream uploadedInputStream, String uploadedFileLocation) {
		try {
			OutputStream out = new FileOutputStream(new File(uploadedFileLocation));
			int read = 0;
			byte[] bytes = new byte[1024];

			out = new FileOutputStream(new File(uploadedFileLocation));
			while ((read = uploadedInputStream.read(bytes)) != -1) {
				out.write(bytes, 0, read);
			}
			out.flush();
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void fileContentReplace(File source, HashMap<String, String> keys) throws IOException {
		
		StringBuffer targetContents = new StringBuffer();
		for(String line : Files.readAllLines(source.toPath(), Charset.forName("euc-kr"))){
			for(Object key : keys.keySet().toArray()){
				line = line.replace(key.toString(), keys.get(key.toString()));
			}
			targetContents.append(line);
			targetContents.append("\n");
		}
		String sourcePath = source.getPath();
		deleteFile(source);
		File target = newFile(sourcePath);
		fileNioCopy(targetContents.toString(), target);
	}
	
	public static void fileContentLineReplace(File source, HashMap<String, String> keys) throws IOException {
		
		StringBuffer targetContents = new StringBuffer();
		for(String line : Files.readAllLines(source.toPath(), Charset.forName("euc-kr"))){
			for(Object key : keys.keySet().toArray()){
				if(line.contains(key.toString()))
					line = keys.get(key.toString());
			}
			targetContents.append(line);
			targetContents.append("\n");
		}
		String sourcePath = source.getPath();
		deleteFile(source);
		File target = newFile(sourcePath);
		fileNioCopy(targetContents.toString(), target);
	}
}
