package com.steerinfo.ftp.uploadfile.utils;

import com.steerinfo.framework.utils.io.IOUtils;
import com.steerinfo.framework.utils.text.Charsets;
import org.apache.commons.net.ftp.*;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Base64;

/**
 * POIExcelToHtml 文件转换：
 *
 * @author generator
 * @version 1.0-SNAPSHOT 2021-08-09 18:06
 * 类描述
 * 修订历史：
 * 日期：2021-08-09
 * 作者：shadow
 * 参考：
 * 描述：
 * @Copyright 湖南视拓信息技术股份有限公司. All rights reserved.
 * @see null
 */
@Component
public class FtpFileUtil {
    /**
     *   ftp服务器ip地址
     *   相关配置放在application.properties 中
     */
    //@Value("${custom.config.file-server.ip}")
    // String FTP_ADDRESS;
    private String FTP_ADDRESS="172.16.90.238";

    /**
     *  端口号
     */
    //@Value("${custom.config.file-server.port}")
    //Integer FTP_PORT;
    private Integer FTP_PORT=21;
    /**
     * 用户名
     */
    //@Value("${custom.config.file-ftp-user}")
    private String FTP_USERNAME="ftptest";
    /**
     * 密码
     */
    //@Value("${custom.config.file-ftp-password}")
    private String FTP_PASSWORD="at286315";

    private FTPClient ftpClient = new FTPClient();
    private static final String SPOT = ".";

    /**
     * 上传文件
     * @param filePath 文件路径
     * @param filename 文件名称
     * @param basePath 上级目录
     * @param inputStream 文件输入流
     * @return 是否成功
     */
    public boolean uploadFile(String filePath, String filename,String basePath, InputStream inputStream) {
        boolean result = false;
        try {
            // 连接FTP服务器
            ftpClient.connect(FTP_ADDRESS, FTP_PORT);
            ftpClient.login(FTP_USERNAME, FTP_PASSWORD);
            int reply;
            ftpClient.enterLocalPassiveMode();
            reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                return false;
            }
            //切换到上传目录
            boolean changed = ftpClient.changeWorkingDirectory(filePath);
            if (!changed) {
                //如果目录不存在创建目录
                String[] dirs = filePath.split("/");
                String tempPath = basePath;
                for (String dir : dirs) {
                    if (null == dir || "".equals(dir)){
                        continue;
                    }
                    tempPath += "/" + dir;
                        if (!ftpClient.makeDirectory(tempPath)) {
                            return false;
                        } else {
                            ftpClient.changeWorkingDirectory(tempPath);
                        }
                }
            }
            System.out.println("当前目录" + ftpClient.printWorkingDirectory());
            //设置为被动模式

            //设置上传文件的类型为二进制类型
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            //上传文件
            if (!ftpClient.storeFile(filename, inputStream)) {
                System.out.println("上传文件失败");
                return false;
            }
            ftpClient.logout();
            result = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    inputStream.close();
                    ftpClient.disconnect();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
            }
        }
        return result;
    }

    /***
     * 上传
     * @param buffIn 文件流
     * @param filePath 文件路径
     * @param fileName 文件名称
     * @param needDelete 是否删除
     * @return 是否成功
     * @throws FTPConnectionClosedException ftp错误
     * @throws IOException io流错误
     * @throws Exception 普通错误
     */
    public boolean uploadToFtp(InputStream buffIn,String filePath, String fileName, boolean needDelete)
            throws FTPConnectionClosedException, IOException, Exception{
        boolean result;
        try {
            //建立连接
            connectToServer();
            ftpClient.changeWorkingDirectory("/");
            setFileType(FTP.BINARY_FILE_TYPE);
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                throw new IOException("failed to connect to the FTP Server:" + FTP_ADDRESS);
            }
            //进入文件目录
            boolean changeWork = ftpClient.changeWorkingDirectory(filePath);
            if(!changeWork){
                if(!createDirectory(filePath)){
                    return false;
                }
            }
            result = ftpClient.storeFile(fileName,buffIn);
            if(needDelete){
                ftpClient.deleteFile(fileName);
            }
            // 输出操作结果信息
            if (result) {
                System.out.println("uploadToFtp INFO: upload file  to ftp : succeed!");
            } else {
                System.out.println("uploadToFtp INFO: upload file  to ftp : failed!");
            }
        } catch (FTPConnectionClosedException e) {
            System.out.println("ftp连接被关闭！");
            throw e;
        }catch (Exception e){
            System.out.println("ERR : upload file  to ftp : failed! ");
            throw  e;
        } finally {
            try {
                if(buffIn != null){
                    buffIn.close();
                }
            } catch (Exception e){
                System.out.println("ftp关闭输入流时失败！");
            }
            if(ftpClient.isConnected()){
              closeConnect();
            }
        }
        return  result;
    }

    /***
     * 预览
     * @param fileName 文件名
     * @param filePath 文件路径
     * @return 返回HTML
     * @throws IOException io流错误
     */
    public String downloadFile(String fileName, String filePath) throws IOException {
        InputStream inputStream;
        String data = fileName + "预览失败";
        try {
            connectToServer();
            // 设置传输二进制文件
            setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.enterLocalPassiveMode();
            int reply = ftpClient.getReplyCode();
            if(!FTPReply.isPositiveCompletion(reply)){
                ftpClient.disconnect();
                throw new IOException("failed to connect to the FTP Server:" + FTP_ADDRESS);
            }

            String directory = filePath.substring(0,filePath.lastIndexOf("/")+1);
            // 进入文件所在目录，注意编码格式，以能够正确识别中文目录
            boolean cdStatus = ftpClient.changeWorkingDirectory(directory);
            if (!cdStatus) {
                return data;
            }
            String file = filePath.substring(filePath.lastIndexOf("/")+1);
            // 检验文件是否存在
            inputStream =ftpClient.retrieveFileStream(file);
            String suffixName;
            if(inputStream != null){
                if (fileName != null && fileName.contains(SPOT)) {
                    POIWordToHtml poiWordToHtml = new POIWordToHtml();
                    suffixName = fileName.substring(fileName.indexOf(".")+1);
                    switch (suffixName) {
                        case "docx": data = poiWordToHtml.docxToHtml(inputStream);break;
                        case "doc" : data = poiWordToHtml.docToHtml(inputStream); break;
                        case "xlsx":
                        case "xls" :
                            data = POIExcelToHtml.excelToHtml(inputStream);break;
                        case "pptx":
                        case "ppt" :
                            data = POIPptToHtml.pptToHtml(inputStream,suffixName);break;
                        case "jpg" :
                        case "gif" :
                        case "png" :
                        case "jpeg":
                        case "jpe" :
                            ByteArrayOutputStream stream = new ByteArrayOutputStream();
                            IOUtils.copy(inputStream,stream);
                            String imgStr = Base64.getEncoder().encodeToString(stream.toByteArray());
                            data = "<img src=" + "\"data:image/"+suffixName+";base64," + imgStr + "\"" + "/>";
                            stream.close();break;
                        case "txt" :
                            ByteArrayOutputStream txtStream = new ByteArrayOutputStream();
                            IOUtils.copy(inputStream,txtStream);
                            data = txtStream.toString();break;
                        default : data = fileName + "文件暂时不支持预览。"; break;
                    }
                }
                inputStream.close();
                ftpClient.completePendingCommand();
            }
        } catch (FTPConnectionClosedException e){
            System.out.println("ftp连接被关闭！");
            throw e;
        } catch (Exception e) {
            System.out.println("ERR : upload file " + fileName + " from ftp : failed!"+e.getMessage());
        } finally {
            if(ftpClient.isConnected()){
                closeConnect();
            }
        }
        return data;
    }

    /**
     * 下载
     * @param response 响应头
     * @param fileName 文件名
     * @param filePath 文件路径
     * @return 返回下载是否成功
     */
    public boolean download(HttpServletResponse response, String fileName, String filePath) {
        boolean flag = false;
        try{
            connectToServer();
            // 设置传输二进制文件
            setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.enterLocalPassiveMode();
            int reply = ftpClient.getReplyCode();
            if(!FTPReply.isPositiveCompletion(reply)){
                ftpClient.disconnect();
                throw new IOException("failed to connect to the FTP Server:" + FTP_ADDRESS);
            }
            String transferName = new String(fileName.getBytes(Charsets.UTF_8),Charsets.ISO_8859_1);
            String directory = filePath.substring(0,filePath.lastIndexOf("/")+1);
            String file = filePath.substring(filePath.lastIndexOf("/")+1);
            // 进入文件所在目录，注意编码格式，以能够正确识别中文目录
            ftpClient.changeWorkingDirectory(directory);
            response.setCharacterEncoding("UTF-8");
            response.setContentType("multipart/form-data;charset=UTF-8");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + transferName + "\"");
            FTPFile[] fs = ftpClient.listFiles();
            for (FTPFile ff : fs) {
                if (ff.getName().equals(file)) {
                    OutputStream os = response.getOutputStream();
                    flag = ftpClient.retrieveFile(ff.getName(), os);
                    os.flush();
                    os.close();
                    break;
                }
            }
            closeConnect();

        }catch (FTPConnectionClosedException ignored){

        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 下载返回流
     * @param fileName 文件名称
     * @param filePath 文件路径
     * @return 返回是否成功
     */
    public ByteArrayOutputStream download(String fileName, String filePath) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try{
            connectToServer();
            // 设置传输二进制文件
            setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.enterLocalPassiveMode();
            int reply = ftpClient.getReplyCode();
            if(!FTPReply.isPositiveCompletion(reply)){
                ftpClient.disconnect();
                throw new IOException("failed to connect to the FTP Server:" + FTP_ADDRESS);
            }
            String directory = filePath.substring(0,filePath.lastIndexOf("/")+1);
            String file = filePath.substring(filePath.lastIndexOf("/")+1);
            // 进入文件所在目录，注意编码格式，以能够正确识别中文目录
            ftpClient.changeWorkingDirectory(directory);
            FTPFile[] fs = ftpClient.listFiles();
            for (FTPFile ff : fs) {
                if (ff.getName().equals(file)) {
                    os.close();
                    break;
                }
            }
            closeConnect();
        }catch (FTPConnectionClosedException ignored){
        } catch (Exception e) {
            e.printStackTrace();
        }

        return os;
    }

    public boolean deleteFile(String filePath) throws Exception {
        boolean result;
        try {
            //建立连接
            connectToServer();
            ftpClient.changeWorkingDirectory("/");
            setFileType(FTP.BINARY_FILE_TYPE);
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                throw new IOException("failed to connect to the FTP Server:" + FTP_ADDRESS);
            }
            String directory = filePath.substring(0,filePath.lastIndexOf("/")+1);
            String fileName = filePath.substring(filePath.lastIndexOf("/")+1);
            //进入文件目录
            boolean changeWork = ftpClient.changeWorkingDirectory(directory);
            if(!changeWork){
                return false;
            }
             result = ftpClient.deleteFile(fileName);
        } catch (FTPConnectionClosedException e) {
            System.out.println("ftp连接被关闭！");
            throw e;
        }catch (Exception e){
            System.out.println("ERR : delete file  to ftp : failed! ");
            throw  e;
        } finally {
            if(ftpClient.isConnected()){
                closeConnect();
            }
        }
        return result;
    }

    /***
     * 建立连接
     * @throws FTPConnectionClosedException ftp错误
     * @throws Exception 普通错误
     */
    private void connectToServer() throws FTPConnectionClosedException, Exception {
         if(!ftpClient.isConnected()){
             int reply;
             try {
                //建立连接
                 ftpClient = new FTPClient();
                 //ftpClient.setControlEncoding("GBK");//windows default服务器gbk
                 ftpClient.setControlEncoding("UTF-8");//linux default UTF-8
                 ftpClient.connect(FTP_ADDRESS, FTP_PORT);
                 ftpClient.login(FTP_USERNAME, FTP_PASSWORD);
                 ftpClient.enterLocalPassiveMode();
                 reply = ftpClient.getReplyCode();
                 if(!FTPReply.isPositiveCompletion(reply)){
                     ftpClient.disconnect();
                     System.out.println("connectToServer FTP server refused connection.");
                 }
             } catch (FTPConnectionClosedException ex) {
                 System.out.println("没有连接数！there are too many connected users,please try later");
                 throw  ex;
             } catch (Exception e) {
                 System.out.println("登录ftp服务器失败");
                 throw e;
             }
         }
    }

    /**
     * 设置传输文件类型
     * @param fileType 文件类型
     */
    private void setFileType(int fileType) {
        try {
            ftpClient.setFileType(fileType);
        } catch (Exception e) {
            System.out.println("ftp设置传输文件的类型时失败！");

        }
    }

    /**
     *  关闭连接
     */
    public void closeConnect() {
        try {
            if (ftpClient != null) {
                ftpClient.logout();
                ftpClient.disconnect();
            }
        } catch (Exception e) {
            System.out.println("ftp连接关闭失败！");
        }
    }

    /**
     * 创建文件夹
     */
   public boolean createDirectory(String directory) {
       try {
           ftpClient.changeWorkingDirectory("/");
               String[] dirs = directory.split("/");
               String tempPath = "";
               for (String dir : dirs) {
                   if(null == dir || "".equals(dir)){
                       continue;
                   }
                   tempPath += "/" + dir;
                   if (!ftpClient.makeDirectory(tempPath)) {
                       if(!ftpClient.changeWorkingDirectory(tempPath)){
                           return false;
                       }
                   } else {
                       ftpClient.changeWorkingDirectory(tempPath);
                   }
               }
       } catch (Exception e) {
           e.printStackTrace();
       }
           return true;
   }
}
