package com.ozs.da.utils;

import com.ozs.da.utils.ftp.FtpClientPool;
import com.ozs.da.utils.ftp.FtpConfiguration;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.StringTokenizer;

/**
 * @author 宋显哲
 * @version 1.0.0 创建于 2018/8/16
 **/
public class FtpUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(FtpUtils.class);
    private volatile static FtpUtils instance = null;

    private FtpClientPool ftpClientPool = null;

    public FtpClientPool getFtpClientPool() {
        return ftpClientPool;
    }

    private FtpUtils() {
        FtpConfiguration configuration = new FtpConfiguration();
        configuration.setHost(CommonConfUtil.getConf("mcd.ftp.host"));
        configuration.setPort(CommonConfUtil.getInteger("mcd.ftp.port", 21));
        configuration.setUsername(CommonConfUtil.getConf("mcd.ftp.username"));
        configuration.setPassword(CommonConfUtil.getConf("mcd.ftp.password"));
        configuration.setConnectTimeOut(CommonConfUtil.getInteger("mcd.ftp.timeout", 600));
        configuration.setMaxTotal(CommonConfUtil.getInteger("mcd.ftp.maxTotal", 10));
        configuration.setMaxIdle(CommonConfUtil.getInteger("mcd.ftp.maxIdle", 10));
        configuration.setMinIdle(CommonConfUtil.getInteger("mcd.ftp.minIdle", 0));
        configuration.setMaxWaitMillis(CommonConfUtil.getLong("mcd.ftp.maxWaitMillis", 600000));
        configuration.setPassiveMode(CommonConfUtil.getBool("mcd.ftp.passiveMode", false));
        ftpClientPool = new FtpClientPool(configuration);
    }

    private static FtpUtils getInstance() {
        synchronized (FtpUtils.class) {
            if (instance == null) {
                instance = new FtpUtils();
            }
        }
        return instance;
    }

    /**
     * 判断 FTP 服务器上的文件是否存在
     *
     * @param filePath FTP服务器中的文件路径
     * @return 文件存在则返回true，否则返回false
     */
    public static boolean fileIsExist(String filePath) {
        FTPClient ftpClient = getInstance().getFtpClientPool().getFtpClient();
        try {
            if (filePath == null || "".equals(filePath)) {
                LOGGER.error("filePath = {}", filePath);
                return false;
            }
            String fileName = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length());
            FTPFile[] ftpFiles = ftpClient.listFiles(filePath, (ftpFile) -> fileName.equals(ftpFile.getName()));
            if (ftpFiles == null || ftpFiles.length == 0) {
                return false;
            }
            return ftpFiles[0].isFile();
        } catch (IOException e) {
            LOGGER.error("FTP操作异常,{}", e);
            return false;
        } finally {
            getInstance().getFtpClientPool().returnFtpClient(ftpClient);
        }
    }

    /**
     * 判断 FTP 服务器上的文件夹是否存在
     *
     * @param path FTP服务器中的文件夹路径
     * @return 文件存在则返回true，否则返回false
     */
    public static boolean dirIsExist(String path) {
        FTPClient ftpClient = getInstance().getFtpClientPool().getFtpClient();
        try {
            if (path == null || "".equals(path)) {
                LOGGER.error("path = {}", path);
                return false;
            }
            String currDirName = path.substring(path.lastIndexOf("/") + 1, path.length());
            String parentDir = path.substring(0, path.lastIndexOf("/"));
            FTPFile[] ftpFiles = ftpClient.listDirectories(parentDir);
            for (FTPFile ftpFile : ftpFiles) {
                if (currDirName.equals(ftpFile.getName()) && ftpFile.isDirectory()) {
                    return true;
                }
            }
            return false;
        } catch (Exception e) {
            LOGGER.error("FTP操作异常,{}", e);
            return false;
        } finally {
            getInstance().getFtpClientPool().returnFtpClient(ftpClient);
        }
    }

    /**
     * 创建在ftp服务器中创建文件夹
     *
     * @param path 文件夹路径，只支持创建以及目录
     * @return 文件创建成功返回true，否则返回false
     */
    public static boolean createDir(String path) {
        FTPClient ftpClient = getInstance().getFtpClientPool().getFtpClient();
        try {
            if (path == null || "".equals(path)) {
                LOGGER.error("path = {}", path);
                return false;
            }
            int i = ftpClient.mkd(path);
            return i == 257;
        } catch (Exception e) {
            LOGGER.error("FTP操作异常,{}", e);
            return false;
        } finally {
            getInstance().getFtpClientPool().returnFtpClient(ftpClient);
        }
    }

    /**
     * 创建在ftp服务器中创建多级文件夹
     *
     * @param path 文件夹路径，只支持创建以及目录
     * @return 文件创建成功返回true，否则返回false
     */
    public static boolean createDirs(String path) {
        try {
            if (path == null || "".equals(path)) {
                LOGGER.error("path = {}", path);
                return false;
            }
            StringTokenizer stringTokenizer = new StringTokenizer(path, "/");
            String createPath = "";
            boolean b = false;
            while (stringTokenizer.hasMoreElements()) {
                createPath = createPath + "/" + (String) stringTokenizer.nextElement();
                if (!dirIsExist(createPath)) {
                    b = createDir(createPath);
                }
            }
            return b;
        } catch (Exception e) {
            LOGGER.error("FTP操作异常,{}", e);
            return false;
        }
    }


    /**
     * 将文件上传至FTP 服务器
     *
     * @param localFile  本地文件
     * @param remotePath 文件上传至FTP服务器路径
     * @return 上传成功返回true，否则返回false
     */
    public static boolean upload(String localFile, String remotePath) {
        try {
            if (localFile == null || "".equals(localFile)
                    || remotePath == null || "".equals(remotePath)) {
                LOGGER.error("localFile = {},remotePath = {}", localFile, remotePath);
                return false;
            }
            return upload(localFile, remotePath, localFile.substring(localFile.lastIndexOf(File.separator) + 1, localFile.length()));
        } catch (Exception e) {
            LOGGER.error("FTP操作异常,{}", e);
            return false;
        }
    }

    /**
     * 将文件上传至FTP 服务器
     *
     * @param localFile     本地文件
     * @param remotePath    文件上传至FTP服务器路径
     * @param storeFileName 存储在FTP服务器上的文件名
     * @return 上传成功返回true，否则返回false
     */
    public static boolean upload(String localFile, String remotePath, String storeFileName) {
        FTPClient ftpClient = getInstance().getFtpClientPool().getFtpClient();
        try {
            if (localFile == null || "".equals(localFile)
                    || remotePath == null || "".equals(remotePath)) {
                LOGGER.error("localFile = {},remotePath = {}", localFile, remotePath);
                return false;
            }
            File file = new File(localFile);
            if (!file.exists() || !file.isFile()) {
                LOGGER.error("本地文件 {} 不存在！", localFile);
                return false;
            }
            ftpClient.changeWorkingDirectory(remotePath);
            return ftpClient.storeFile(storeFileName, new FileInputStream(file));
        } catch (Exception e) {
            LOGGER.error("FTP操作异常,{}", e);
            return false;
        } finally {
            getInstance().getFtpClientPool().returnFtpClient(ftpClient);
        }
    }


    /**
     * 从FTP服务器中下载文件
     *
     * @param remoteFile    FTP中的文件路径
     * @param localPath     下载到本地的文件路径
     * @param localFileName 下载到本地的文件名
     * @return 下载成功返回true，否则返回false
     */
    public static boolean load(String remoteFile, String localPath, String localFileName) {
        FTPClient ftpClient = getInstance().getFtpClientPool().getFtpClient();
        try {
            if (localPath == null || "".equals(localPath)
                    || remoteFile == null || "".equals(remoteFile)
                    || localFileName == null || "".equals(localFileName)) {
                LOGGER.error("remoteFile = {},localPath = {},localFileName={}", remoteFile, localPath, localFileName);
                return false;
            }

            File localDir = new File(localPath);
            if (!localDir.exists() || !localDir.isDirectory()) {
                localDir.mkdirs();
            }
            return ftpClient.retrieveFile(remoteFile, new FileOutputStream(localPath + File.separator + localFileName));
        } catch (Exception e) {
            return false;
        } finally {
            getInstance().getFtpClientPool().returnFtpClient(ftpClient);
        }
    }

    /**
     * 从FTP服务器中下载文件
     *
     * @param remoteFile FTP中的文件路径
     * @param localPath  下载到本地的文件路径
     * @return 下载成功返回true，否则返回false
     */
    public static boolean load(String remoteFile, String localPath) {
        FTPClient ftpClient = getInstance().getFtpClientPool().getFtpClient();
        try {
            if (localPath == null || "".equals(localPath)
                    || remoteFile == null || "".equals(remoteFile)) {
                LOGGER.error("remoteFile = {},localPath = {}", remoteFile, localPath);
                return false;
            }
            File localDir = new File(localPath);
            if (!localDir.exists() || !localDir.isDirectory()) {
                localDir.mkdirs();
            }
            return ftpClient.retrieveFile(remoteFile, new FileOutputStream(localPath + File.separator + remoteFile.substring(remoteFile.lastIndexOf("/") + 1, remoteFile.length())));
        } catch (Exception e) {
            return false;
        } finally {
            getInstance().getFtpClientPool().returnFtpClient(ftpClient);
        }
    }

    /**
     * 删除FTP服务器上的文件夹
     *
     * @param remotePath FTP中的文件夹路径
     * @return 删除成功返回true，否则返回false
     */
    public static boolean deleteDir(String remotePath) {
        FTPClient ftpClient = getInstance().getFtpClientPool().getFtpClient();
        try {
            if (remotePath == null || "".equals(remotePath)) {
                LOGGER.error("path = {}", remotePath);
                return false;
            }
            return ftpClient.removeDirectory(remotePath);
        } catch (Exception e) {
            LOGGER.error("FTP操作异常,{}", e);
            return false;
        } finally {
            getInstance().getFtpClientPool().returnFtpClient(ftpClient);
        }
    }

    /**
     * 删除FTP服务器上的文件
     *
     * @param remoteFile FTP中的文件路径
     * @return 删除成功返回true，否则返回false
     */
    public static boolean deleteFile(String remoteFile) {
        FTPClient ftpClient = getInstance().getFtpClientPool().getFtpClient();
        try {
            if (remoteFile == null || "".equals(remoteFile)) {
                LOGGER.error("path = {}", remoteFile);
                return false;
            }
            return ftpClient.deleteFile(remoteFile);
        } catch (Exception e) {
            LOGGER.error("FTP操作异常,{}", e);
            return false;
        } finally {
            getInstance().getFtpClientPool().returnFtpClient(ftpClient);
        }
    }

    /**
     * 对FTP服务器中的文件重命名
     *
     * @param orgFileName    FTP中的文件原始名称（文件全路径）
     * @param targetFileName FTP重命名后的文件名（文件全路径）
     * @return 重命名成功返回true，否则返回false
     */
    public static boolean renameFile(String orgFileName, String targetFileName) {
        FTPClient ftpClient = getInstance().getFtpClientPool().getFtpClient();
        try {
            if (orgFileName == null || "".equals(orgFileName)
                    || targetFileName == null || "".equals(targetFileName)) {
                LOGGER.error("orgFileName = {},localPath = {}", orgFileName, targetFileName);
                return false;
            }
            ftpClient.rename(orgFileName, targetFileName);
            return true;
        } catch (Exception e) {
            LOGGER.error("FTP操作异常,{}", e);
            return false;
        }finally {
            getInstance().getFtpClientPool().returnFtpClient(ftpClient);
        }
    }

    /**
     * 将文件上传至FTP 服务器
     *
     * @param localFile     本地文件
     * @param remotePath    文件上传至FTP服务器路径
     * @param storeFileName 存储在FTP服务器上的文件名
     * @return 上传成功返回true，否则返回false
     */
    public static boolean uploadAndDel(String localFile, String remotePath, String storeFileName) {
        FTPClient ftpClient = getInstance().getFtpClientPool().getFtpClient();
        FileInputStream in = null;
        File file = null;
        try {
            if (localFile == null || "".equals(localFile)
                    || remotePath == null || "".equals(remotePath)) {
                LOGGER.error("localFile = {},remotePath = {}", localFile, remotePath);
                return false;
            }
            file = new File(localFile);
            if (!file.exists() || !file.isFile()) {
                LOGGER.error("本地文件 {} 不存在！", localFile);
                return false;
            }
            in = new FileInputStream(file);
            ftpClient.changeWorkingDirectory(remotePath);
            boolean uploadResult = ftpClient.storeFile(storeFileName, in);

            return uploadResult;
        } catch (Exception e) {
            LOGGER.error("FTP操作异常,{}", e);
            return false;
        } finally {
            getInstance().getFtpClientPool().returnFtpClient(ftpClient);
            if(in != null){
                try {
                    in.close();
                    file.delete();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static InputStream readFtpFile(String remoteFile) throws Exception {
        FTPClient ftpClient = getInstance().getFtpClientPool().getFtpClient();
        return ftpClient.retrieveFileStream(remoteFile);
    }


}
