package cokr.xit.fims.cmmn.ftp;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

public class FTPUtil {
	public static boolean fileDown(RemoteSystemInfo rs, String remoteWorkPath, String downloadRoot) {

		File f = new File(downloadRoot + remoteWorkPath);
		f.mkdirs();

		FTPClient client = null;

		String thisSystemFileSeperator = File.separator;

		String remoteSystemFileSeparator = rs.getOsType().equals("linux") ? "/" : "\\";

		if(!thisSystemFileSeperator.equals(remoteSystemFileSeparator)) {
			remoteWorkPath = remoteWorkPath.replaceAll(
				Matcher.quoteReplacement(thisSystemFileSeperator),
   				Matcher.quoteReplacement(remoteSystemFileSeparator)
			);
		}

		client = new FTPClient();
		client.setControlEncoding("UTF-8");
		try {
			client.connect(rs.getIp(), Integer.parseInt(rs.getPort()));
		} catch (Exception e) {
			throw new RuntimeException("접속 오류.");
		}

		// 접속을 확인.
	    int resultCode = client.getReplyCode();
	    if (!FTPReply.isPositiveCompletion(resultCode)) {
	        throw new RuntimeException("접속 오류 : FTP server refused connection.");
	    }

	    try {
	    	client.setSoTimeout(1000);
	    } catch (Exception e) {
			throw new RuntimeException("접속 오류.");
		}

	    boolean loginResult = false;
	    try {
	    	// 로그인을 한다.
	    	loginResult = client.login(rs.getId(), rs.getPw());
	    } catch (Exception e) {
			throw new RuntimeException("로그인 오류 : Login Error");
		}

	    if (!loginResult) {
          throw new RuntimeException("로그인 오류 : Login Error");
        }

        List<String> remoteFiles = new ArrayList<>();
        List<String> remoteDirectories = new ArrayList<>();

        // FTP에서 파일 리스트와 디렉토리 정보를 취득한다.
        if (!FTPUtil.getFileList(client, remoteSystemFileSeparator, remoteWorkPath, remoteFiles, remoteDirectories)) {
        	// 리스트 취득 실패시 프로그램을 종료한다.
            throw new RuntimeException("파일 조회 오류 발생 : File search Error");
        }

        for (String remoteDirectory : remoteDirectories) {
        	  System.out.println("디렉토리-"+remoteDirectory);

        	  String newFolderPath = "";
        	  if(thisSystemFileSeperator.equals(remoteSystemFileSeparator)) {
        		  newFolderPath = downloadRoot + remoteDirectory;
        	  } else {
        		  newFolderPath = downloadRoot + remoteDirectory.replaceAll(
        				  Matcher.quoteReplacement(remoteSystemFileSeparator),
        				  Matcher.quoteReplacement(thisSystemFileSeperator)
        		  );
        	  }

              File folder = new File(newFolderPath);
              folder.mkdirs();
        }


        for (String remoteFile : remoteFiles) {
        	System.out.println("파일-"+remoteFile);

        	String tempFileOutputPath = "";

        	if(thisSystemFileSeperator.equals(remoteSystemFileSeparator)) {
        		tempFileOutputPath = downloadRoot + remoteFile;
        	} else {
        		tempFileOutputPath = downloadRoot + remoteFile.replaceAll(
        				  Matcher.quoteReplacement(remoteSystemFileSeparator),
        				  Matcher.quoteReplacement(thisSystemFileSeperator)
        		  );
        	}


            try (FileOutputStream fo = new FileOutputStream(tempFileOutputPath)){
              //FTPClient의 retrieveFile함수로 보내면 다운로드가 이루어 진다.
              if (client.retrieveFile(remoteFile, fo)) {
                System.out.println("Download - " + remoteFile);
              }
            } catch(Exception e) {
            	throw new RuntimeException("파일 다운로드 오류");
            }

        }

        try {
			client.disconnect();
        } catch(Exception e) {
        	throw new RuntimeException("파일 다운로드 오류");
        }
		return true;
	}

	// FTP의 파일 리스트와 디렉토리 정보를 취득하는 함수.
	public static boolean getFileList(FTPClient client, String fileSeparator, String work, List<String> files, List<String> directories) {

	    // FTP의 디렉토리 커서를 이동한다.
	    try {
			if (client.changeWorkingDirectory(work)) {

			  // 해당 디렉토리의 파일 리스트를 취득한다.
			  for (FTPFile file : client.listFiles()) {

			    if (!file.isFile()) {
			    	// 디렉토리리면 함수의 재귀적 방식으로 하위 탐색을 시작한다.
				    if(!getFileList(client, fileSeparator, work + file.getName() + fileSeparator, files, directories)) {
				    	return false;
				    }

				     // directories 리스트에 디렉토리 경로를 추가한다.
				     directories.add(work + file.getName() + fileSeparator);
			    } else {
			    	// files 리스트에 경로를 추가한다.
				    files.add(work + file.getName());
			    }

			  }
			  // FTP의 디렉토리 커서를 상위로 이동하는 함수
			  // client.changeToParentDirectory();

			  // FTP의 디렉토리 커서를 이동한다.
			  return client.changeWorkingDirectory(fileSeparator);

			}
		} catch (IOException e) {
			throw new RuntimeException("ftp오류."+e);
		}

	    // 커서 이동에 실패하면 false를 리턴한다.
	    return false;
	  }
}
