package com.eactive.eai.batch.common;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import com.eactive.eai.batch.doc.BatchDoc;
import com.eactive.eai.batch.logger.LogManager;
import com.eactive.eai.common.util.DatetimeUtil;
import com.eactive.eai.common.util.Logger;

/**
 * <pre>
 * 디렉토리 또는 파일을 생성/삭제/이동/이름변경 하는 유틸리티이다.
 * 참고) 윈도계열과 유닉스계열에 모두 적용된다.
 * </pre>
 */
public class FileUtil {

	//파일로거
	public static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);

	/**
	 * 디렉토리를 생성한다.<br>
	 * 참고) 상위디렉토리가 이미 생성되어 있어야 한다.
	 * @param	path		디렉토리 경로 문자열
	 * @return 	성공시 리턴 true, 실패시 리턴 false
	 */
	public static boolean mkdir(String path) {
		return mkdir(path, false);
	}

	/**
	 * 디렉토리를 생성한다.<br>
	 * 참고) 상위디렉토리가 미 존재시 상위디렉토리까지 생성할 수 있다.
	 * @param	path		디렉토리 경로 문자열
	 * @param	isRecursive	상위디렉토리 미 존재시 생성여부
	 * @return 	성공시 리턴 true, 실패시 리턴 false
	 */
	public static boolean mkdir(String path, boolean isRecursive) {
		if (path==null || (path=path.trim()).equals("")) return false;
		return mkdir(new File(path.replace('\\', '/')), isRecursive);
	}

	/**
	 * 디렉토리를 생성한다.<br>
	 * 참고) 상위디렉토리가 미 존재시 상위디렉토리까지 생성할 수 있다.
	 * @param	path		디렉토리 경로 File 객체
	 * @param	isRecursive	상위디렉토리 미 존재시 생성여부
	 * @return 	성공시 리턴 true, 실패시 리턴 false
	 */
	public static boolean mkdir(File f, boolean isRecursive) {
		if (f==null) return false;
		if (f.exists()) {
			logger.debug("   - 디렉토리 생성...["+ f.getAbsolutePath() +"] -> true (이미존재함)");
			setExecutable(f.getAbsolutePath());
			return true;
		}

		boolean isSuccess = (isRecursive)? f.mkdirs() : f.mkdir();
		logger.debug("   - 디렉토리 생성...["+ f.getAbsolutePath() +"] -> "+ isSuccess);
		setExecutable(f.getAbsolutePath());
		return isSuccess;
	}

	/**
	 * 디렉토리를 삭제한다.<br>
	 * 참고) 디렉토리 안에 내용이 없어야 한다.
	 * @param	path		디렉토리 경로 문자열
	 * @return 	성공시 리턴 true, 실패시 리턴 false
	 */
	public static boolean rmdir(String path) {
		return rmdir(path, false);
	}

	/**
	 * 디렉토리를 삭제한다.<br>
	 * 참고) 디렉토리 안의 내용 존재시 모든 내용을 삭제할 수 있다.
	 * @param	path		디렉토리 경로 문자열
	 * @param	isRecursive	내용 존재시 삭제여부
	 * @return 	성공시 리턴 true, 실패시 리턴 false
	 */
	public static boolean rmdir(String path, boolean isRecursive) {
		if (path==null || (path=path.trim()).equals("")) return false;
		return rmdir(new File(path.replace('\\', '/')), isRecursive);
	}

	/**
	 * 디렉토리를 삭제한다.<br>
	 * 참고) 디렉토리 안의 내용 존재시 모든 내용을 삭제할 수 있다.
	 * @param	path		디렉토리 경로 File 객체
	 * @param	isRecursive	내용 존재시 삭제여부
	 * @return 	성공시 리턴 true, 실패시 리턴 false
	 */
	public static boolean rmdir(File f, boolean isRecursive) {
		if (f==null) return false;
		if (!f.exists()) {
			logger.debug("   - 디렉토리 삭제...["+ f.getAbsolutePath() +"] -> true (존재안함)");
			return true;
		}
		if (f.isFile()) {
			logger.debug("   - 디렉토리 삭제...["+ f.getAbsolutePath() +"] -> false (파일임)");
			return false;
		}

		if (isRecursive) {	//디렉토리 내의 모든 내용도 삭제할때
			File[] fl = f.listFiles();

			for (int i=0; i<fl.length; i++) {
				boolean isSuccess;
				if (fl[i].isFile()) {
					isSuccess = fl[i].delete();
					logger.debug("     - 파일 삭제...["+ f.getAbsolutePath() +"] -> "+ isSuccess);
				} else {
					isSuccess = rmdir(fl[i], true);
				}
				if (!isSuccess) return false;
			}
			boolean isSuccess = f.delete();
			logger.debug("   - 디렉토리 삭제...["+ f.getAbsolutePath() +"] -> "+ isSuccess);
			return isSuccess;

		} else {
			boolean isSuccess = f.delete();
			logger.debug("   - 디렉토리 삭제...["+ f.getAbsolutePath() +"] -> "+ isSuccess);
			return isSuccess;
		}
	}

	/**
	 * 파일을 삭제한다.
	 * @param	path		파일 경로 문자열
	 * @return 	성공시 리턴 true, 실패시 리턴 false
	 */
	public static boolean delete(String path) {
		if (path==null || (path=path.trim()).equals("")) return false;
		return delete(new File(path.replace('\\', '/')));
	}

	/**
	 * 파일을 삭제한다.
	 * @param	path		파일 경로 File 객체
	 * @return 	성공시 리턴 true, 실패시 리턴 false
	 */
	public static boolean delete(File f) {
		if (f==null || !f.exists() || f.isDirectory()) return false;	//존재하지 않거나 디렉토리면 리턴 true
		return f.delete();
	}

	/**
	 * 파일 또는 디렉토리의 이름을 변경 또는 이동 시킨다.<br>
	 * 주의) 윈도계열에서 이동시 다른 드라이브로 이동할 수는 없다.
	 * @param	pathFrom	원본 디렉토리 또는 파일 경로 문자열
	 * @param	pathTo		목적 디렉토리 또는 파일 경로 문자열
	 * @return 	성공시 리턴 true, 실패시 리턴 false
	 */
	public static boolean move(String pathFrom, String pathTo) {
		return move(pathFrom, pathTo, false);
	}

	/**
	 * 파일 또는 디렉토리의 이름을 변경 또는 이동 시킨다.<br>
	 * 참고) 목적 경로의 상위디렉토리 미 존재시 상위디렉토리 생성 후 이름변경 또는 이동할 수 있다.
	 * 주의) 윈도계열에서 이동시 다른 드라이브로 이동할 수는 없다.
	 * @param	pathFrom	원본 디렉토리 또는 파일 경로 문자열
	 * @param	pathTo		목적 디렉토리 또는 파일 경로 문자열
	 * @param	isMkdir		목적경로의 상위디렉토리 미 존재시 생성여부
	 * @return 	성공시 리턴 true, 실패시 리턴 false
	 */
	public static boolean move(String pathFrom, String pathTo, boolean isMkdir) {
		if (pathFrom==null || (pathFrom=pathFrom.trim()).equals("")) return false;
		if (pathTo  ==null || (pathTo  =pathTo.trim()  ).equals("")) return false;
		return move(new File(pathFrom.replace('\\', '/')), pathTo.replace  ('\\', '/'), isMkdir);
	}

	/**
	 * 파일 또는 디렉토리의 이름을 변경 또는 이동 시킨다.<br>
	 * 참고) 목적 경로의 상위디렉토리 미 존재시 상위디렉토리 생성 후 이름변경 또는 이동할 수 있다.
	 * 주의) 윈도계열에서 이동시 다른 드라이브로 이동할 수는 없다.
	 * @param	pathFrom	원본 디렉토리 또는 파일 경로 File 객체
	 * @param	pathTo		목적 디렉토리 또는 파일 경로 문자열
	 * @param	isMkdir		목적경로의 상위디렉토리 미 존재시 생성여부
	 * @return 	성공시 리턴 true, 실패시 리턴 false
	 */
	public static boolean move(File f, String pathTo, boolean isMkdir) {
		if (f==null) return false;
		if (!f.exists()) {
			logger.debug("   - 디렉토리 이동...["+ f.getAbsolutePath() +"] to ["+ pathTo +"] -> false (존재안함)");
			return false;
		}

		//목적경로가 없을경우 강제로 만듬
		if (isMkdir) {
			if (pathTo.endsWith("/")) pathTo = pathTo.substring(0, pathTo.length()-1);	//맨끝 "/" 제거
			boolean isSuccess = mkdir(pathTo.substring(0, pathTo.lastIndexOf("/")), true);
			if (!isSuccess) {
				logger.debug("   - 디렉토리 이동...["+ f.getAbsolutePath() +"] to ["+ pathTo +"] -> false (미존재Path생성실패)");
				return false;
			}
		}
		File f1 = new File(pathTo);
		boolean isSuccess = f.renameTo(f1);
		logger.debug("   - 디렉토리 이동...["+ f.getAbsolutePath() +"] to ["+ f1.getAbsolutePath() +"] -> "+ isSuccess);
		setExecutable(pathTo);
		return isSuccess;
	}

    public static boolean copyTransferFile(File sourceFile, File targetFile) throws IOException {
    	return copyTransferFile(sourceFile, targetFile, false);
    }

    public static boolean copyTransferFile(File sourceFile, File targetFile, boolean flag) throws IOException {
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        boolean success = true;
        try {
            inChannel = new FileInputStream(sourceFile).getChannel();
            outChannel = new FileOutputStream(targetFile).getChannel();
            inChannel.transferTo(0, inChannel.size(), outChannel);
        } finally {
            try {
                if (inChannel != null) {
                    inChannel.close();
                }
                if (outChannel != null) {
                    outChannel.close();
                }
            } catch (IOException e) {
            	success = false;
            	logger.error( e.getMessage(), e);
            }
        }
        if ( success && flag ){
        	try {
        		sourceFile.delete();
			} catch (Exception e) {
				success = false;
				logger.error( e.getMessage(), e);
			}
        }
        return success;
    }
    
    public static byte[] readLine( FileInputStream fin ){
    	byte[] fileLine = new byte[1024];
    	byte[] newLine = null;
    	int len = 0;
    	int buf;
    	try {
        	while (( buf = fin.read()) != -1) {
    			if ( buf == '\n' )
    				break;
    			if ( len == fileLine.length ){
    				byte[] tmpLine = fileLine;
    				fileLine = new byte[len + 1024];
    				System.arraycopy( tmpLine, 0, fileLine, 0, len );
    			}
    			fileLine[len] = (byte)buf;
    			len++;
    		}
        	if ( ( len > 0 ) && ( fileLine[len-1] == '\r' ) )
        		len--;
        	if ( len == 0 )
        		return null;
        	newLine = new byte[len];
        	System.arraycopy( fileLine, 0, newLine, 0, len );
		} catch (Exception e) {
			return null;
		}
		return newLine;
    }
    private static void setExecutable ( String path ){
    	
    	String cmd1 = "chmod 775 " + path;
//    	String cmd2 = "chgrp ftp " + path;

//    	File dir = new File(path);
    	try {
    		Runtime.getRuntime().exec( cmd1 );
//    		Runtime.getRuntime().exec( cmd2 );
//        	dir.setExecutable(true, false);
//        	dir.setReadable(true, false);
//        	dir.setWritable(true, false);
		} catch (Exception e) {
			logger.error( e.getMessage(), e);
		}
    }
    
	static public List<File> getFileList(File dir){
		ArrayList<File> list = new ArrayList<File>(); 
		File[] flist = dir.listFiles();
		for (File file : flist) {
			if ( file.isFile() ){
				list.add(file);
			}else if ( file.isDirectory()){
				ArrayList<File> slist = (ArrayList<File>) getFileList(file);
				for (File file2 : slist) {
					list.add(file2);
				}
			}
		}
		return list;
		
	}

	static public List<File> getSendFileList(File dir){
//		ArrayList<File> list = new ArrayList<File>(); 
//		File[] deplist = dir.listFiles();
//		for (File deps : deplist) {
//			File sendDir = new File( deps.getAbsoluteFile()+ File.separator + "snd" ); 
//			if ( sendDir.exists() && sendDir.isDirectory()){
//				ArrayList<File> slist = (ArrayList<File>) getFileList(sendDir);
//				for (File file : slist) {
//					list.add(file);
//				}
//			}
//		}
//		return list;

		ArrayList<File> list = new ArrayList<File>(); 
		 
		if ( dir.exists() && dir.isDirectory()){
			ArrayList<File> slist = (ArrayList<File>) getFileList(dir);
			for (File file : slist) {
				list.add(file);
			}
		}

		return list;

		
	}
	
	static public String getRecvFileName(String fileName, String pattern, BatchDoc batchDoc){
		return getRecvFileName( fileName, pattern, batchDoc, true);
	}

	static public String getRecvFileName(String fileName, String pattern, BatchDoc batchDoc, boolean flag){
		
		String rFileName = fileName + "";
		String recvDate = null;
		boolean useSeq = false;
		if (pattern == null || pattern.trim().equals("")){
			return rFileName;
		}
		
		if ( pattern.endsWith("001") ){
			useSeq = true;
			pattern = pattern.substring(0, pattern.length()-3);
			if ( pattern.endsWith("_") ){
				pattern = pattern.substring(0, pattern.length()-1);
			}
		}
		String baseDate = batchDoc.getBatchMsg().getHeader().getBaseDate();
		if ( baseDate == null || baseDate.trim().equals("") || !DatetimeUtil.isRightDate(baseDate)){
	        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
	        baseDate = formatter.format(Calendar.getInstance().getTime());
		}
        Calendar calendar = Calendar.getInstance();
        calendar.set(Integer.parseInt(baseDate.substring(0,4)),Integer.parseInt(baseDate.substring(4,6))-1,Integer.parseInt(baseDate.substring(6)));

        SimpleDateFormat sdf = new SimpleDateFormat( pattern );
        recvDate = sdf.format(calendar.getTime());
        
        if ( recvDate != null && !recvDate.equals("") ){
        	rFileName = rFileName + "_" + recvDate;
        }
        
        if ( !useSeq )
        	return rFileName;
        
        String procCode = batchDoc.getBatchMsg().getHeader().getProcessCode();
        String instCode = batchDoc.getBatchMsg().getHeader().getInstitutionCode();
        String fileSeq = "001";
        
        try {
			fileSeq = LogManager.getInstance().getFileNameSeq(procCode, instCode, rFileName, flag);
		} catch (Exception e) {
			logger.error( e.getMessage(), e);
		}
		return rFileName + "_" + fileSeq;
	}

	
    public static byte[] readLine( BufferedInputStream bis ){
    	byte[] fileLine = new byte[1024];
    	byte[] newLine = null;
    	int len = 0;
    	int buf;
    	try {
        	while (( buf = bis.read()) != -1) {
    			if ( buf == '\n' )
    				break;
    			if ( len == fileLine.length ){
    				byte[] tmpLine = fileLine;
    				fileLine = new byte[len + 1024];
    				System.arraycopy( tmpLine, 0, fileLine, 0, len );
    			}
    			fileLine[len] = (byte)buf;
    			len++;
    		}
        	if ( ( len > 0 ) && ( fileLine[len-1] == '\r' ) )
        		len--;
        	if ( len == 0 )
        		return null;
        	newLine = new byte[len];
        	System.arraycopy( fileLine, 0, newLine, 0, len );
		} catch (Exception e) {
			return null;
		}
		return newLine;
    }

}