/*
 * Copyright 2000-2020 YGSoft.Inc All Rights Reserved.
 */
package com.ygsoft.ecp.app.mappcore.impl.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.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

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

import com.ygsoft.ecp.service.log.EcpLogFactory;
import com.ygsoft.ecp.service.log.IEcpLog;
import com.ygsoft.ecp.service.tool.StringUtil;

/**
 * Ftp工具类.<br>
 *
 * @author mapengfei <br>
 * @version 1.0.0 2016年4月9日<br>
 * @see
 * @since JDK 1.5.0
 */
public class FtpUtil {

    // private static Logger logger = Logger.getLogger(FtpUtil.class);

    private static final IEcpLog LOG = EcpLogFactory.getLog(FtpUtil.class);

    private static FTPClient ftp = new FTPClient();
    /**
     * 获取当前服务的编码
     */
    private static String encoding = System.getProperty("file.encoding");
    //private static String encoding="iso-8859-1";

    /**
     * 获取ftp连接
     *
     * @param f
     * @return
     * @throws Exception
     */
    public static boolean connectFtp(final FtpVO f) throws Exception {
        ftp = new FTPClient();
        boolean flag = false;
        int reply;
        ftp.setControlEncoding(encoding);
        if (f.getPort() == null) {
            // 链接ftp
            ftp.connect(f.getIpAddr(), 21);
        } else {
            ftp.connect(f.getIpAddr(), f.getPort());
        }
        // 登录ftp
        ftp.login(f.getUserName(), f.getPwd());
        // 设置读取方式
        ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
        // 获取ftp登录应答代码
        reply = ftp.getReplyCode();
        if (!FTPReply.isPositiveCompletion(reply)) {
            ftp.disconnect();
            if(LOG.isInfoEnabled()){
                LOG.info("FTP 服务拒绝访问.");
            }
            return flag;
        }
        String path = f.getPath();
        flag = ftp.changeWorkingDirectory(new String(f.getPath().getBytes(encoding), "iso-8859-1"));
        if (flag && StringUtil.isNotEmptyString(f.getFolderName())) {
            flag = createFolderToFtp(f, flag, path);
        }
        return flag;
    }

    /**
     * 创建文件夹到ftp
     * @param f ftpmodel
     * @param flag 创建标识
     * @param path 基础路径(ftp用户权限根路径)
     * @return
     * @throws IOException
     * @throws UnsupportedEncodingException
     */
    private static boolean createFolderToFtp(final FtpVO f, boolean flag, String path)
            throws IOException, UnsupportedEncodingException {
        String[] folders = f.getFolderName().split("/");
        for (String s : folders) {
            if (StringUtil.isNotEmptyString(s)) {
                ftp.makeDirectory(s);
                path += s + "/";
                flag = ftp.changeWorkingDirectory(new String(path.getBytes(encoding), "iso-8859-1"));
            }
        }
        return flag;
    }

    /**
     * 关闭ftp连接
     */
    public static void closeFtp() {
        if (ftp != null && ftp.isConnected()) {
            try {
                ftp.logout();
                ftp.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 根据inputStream 分析出zip压缩文件里的文件名称
     * @param stream
     * @param fileSourceName 文件源名称
     * @return
     */
    public static List<String> getFileName(final String fileName,final InputStream stream,final String fileSourceName){
        List<String> jarpath =new ArrayList<String>();
        FileOutputStream outPutStream=null;
        try {
            byte[] buf = new byte[4096];
            outPutStream = new FileOutputStream(SystemConfigUtil.get("SERVER_BASE_HOME","FTP")+"/mapp/"+"\\"+fileName);
            int readLength;
            while (((readLength = stream.read(buf)) != -1)) {
                outPutStream.write(buf, 0, readLength);
            }
//            if(fileSourceName!=null && fileSourceName.indexOf(".zip")>0){ // 针对ftp做的逻辑处理
//                ZipMultiFile.unzip(SystemConfigUtil.get("SERVER_BASE_HOME","FTP")+"/mapp/"+"\\"+fileName, SystemConfigUtil.get("SERVER_BASE_HOME","FTP")+"/mapp/"+"\\");
//                String fileSource =  fileSourceName.substring(0, fileSourceName.lastIndexOf("."));
//                File srcDir = new File(SystemConfigUtil.get("SERVER_BASE_HOME","FTP")+"/mapp/"+"\\"+fileSource+"\\"+fileSource);
//                if (srcDir.exists()) {
//                    //String MESSAGE = "复制目录失败:源目录" + srcDirName + "不存在!";
//                    File[] files = srcDir.listFiles();
//                    for (int i = 0; i < files.length; i++) {
//                        // 复制文件
//                        if (files[i].isFile()) {
//                            if(LOG.isInfoEnabled()){
//                                LOG.info("文件名是"+files[i].getName());
//                            }
//                            jarpath.add(files[i].getName());
//                        } else if (files[i].isDirectory()) {
//                            if(LOG.isInfoEnabled()){
//                                LOG.info("是文件目录"+files[i].getName());
//                            }
//                        }
//                    }
//                }
//            }
            //
        } catch (FileNotFoundException e) {
            if(LOG.isInfoEnabled()){
                LOG.info("没有找到相应的文件夹");
            }
            e.printStackTrace();
        } catch (IOException e) {
            if(LOG.isInfoEnabled()){
                LOG.info("文件写入异常");
            }
            e.printStackTrace();
        }finally{
            try {
                outPutStream.flush();
                outPutStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return jarpath;
        
    }

    /**
     * ftp上传文件
     *
     * @param f
     * @throws IOException
     * @throws Exception
     */
    public static void upload(final File f) throws IOException {
        ftp.setControlEncoding(encoding);
        if (f.isDirectory()) {
            ftp.makeDirectory(f.getName());
            ftp.changeWorkingDirectory(f.getName());
            String[] files = f.list();
            for (String fstr : files) {
                File file1 = new File(f.getPath() + "/" + fstr);
                if (file1.isDirectory()) {
                    upload(file1);
                    ftp.changeToParentDirectory();
                } else {
                    File file2 = new File(f.getPath() + "/" + fstr);
                    FileInputStream input = new FileInputStream(file2);
                    ftp.storeFile(new String(file2.getName().getBytes(encoding), "iso-8859-1"), input);
                    input.close();
                }
            }
        } else {
            File file2 = new File(f.getPath());
            FileInputStream input = new FileInputStream(file2);
            // 实现上传
            int bufferSize = Integer.valueOf(SystemConfigUtil.get("FTPPUFFERSIZE","FTP"));
            if(LOG.isInfoEnabled()){
                LOG.info("bufferSize 配置获取成功");
            }
            ftp.setBufferSize(bufferSize);
            ftp.storeFile(new String(file2.getName().getBytes(encoding), "iso-8859-1"), input);
            input.close();
        }
    }

    /**
     * 上传(mappstore定制)
     * @param input 输入流
     * @param folderName 目录文件夹(用于业务层的分层管理)
     * @param fileName ftp服务器上的文件名
     * @param fileSourceName 附件源名称
     * @throws IOException
     */
    public static List<String> uploadByInputStream(final InputStream input, final String folderName, final String fileName,final String fileSourceName,final String type)
            throws IOException {
        List<String> zipuploadName =null;
        ftp.setControlEncoding(encoding);
        if (StringUtil.isNotEmptyString(fileName)) {
            try {
                FtpVO f = new FtpVO();
                f.setIpAddr(SystemConfigUtil.get("FTPIPADDR","FTP"));
                f.setUserName(SystemConfigUtil.get("FTPUSERNAME","FTP"));
                f.setPwd(SystemConfigUtil.get("FTPPWD","FTP"));
                f.setPath(SystemConfigUtil.get("FTPPATH","FTP")); //根目录
                f.setFolderName(type+"/"+folderName); //业务子目录(支持无限层)
                FtpUtil.connectFtp(f); // 链接
                int bufferSize = Integer.valueOf(SystemConfigUtil.get("FTPPUFFERSIZE","FTP"));
                if(LOG.isInfoEnabled()){
                    LOG.info("bufferSize 配置获取成功");
                }
                ftp.setBufferSize(bufferSize);
                zipuploadName= getFileName(new String(fileName.getBytes(encoding), encoding),input,fileSourceName);
                FileInputStream inputStreams = new FileInputStream(new File(SystemConfigUtil.get("SERVER_BASE_HOME","FTP")+"/mapp/"+"\\"+fileName));
                ftp.storeFile(new String(fileName.getBytes(encoding), "iso-8859-1"), inputStreams);
                input.close();
                inputStreams.close();
                if(LOG.isInfoEnabled()){
                    LOG.info("多个jar 打包成zip格式包上传成功,开始启动删除缓存操作");
                }
                Thread.sleep(3000); // 等待5s
                ForderUtil.deleteFolder(SystemConfigUtil.get("SERVER_BASE_HOME","FTP")+"/mapp/"+"\\"+fileName);
                if(LOG.isInfoEnabled()){
                    LOG.info("多个jar 打包成zip格式包上传成功,删除成功");
                }
            } catch (Exception e) {
                if (LOG.isInfoEnabled()) {
                    LOG.info("ftp链接失败");
                }
                LOG.error(e);
            }
        }
        return zipuploadName;
    }

    /**
     * 下载链接配置
     *
     * @param f
     *            FTP 数据模型
     * @param localBaseDir
     *            本地目录
     * @param remoteBaseDir
     *            远程目录
     * @throws Exception
     */
    public static void startDown(final FtpVO f, final String localBaseDir, final String remoteBaseDir)
            throws Exception {
        if (FtpUtil.connectFtp(f)) {
            try {
                FTPFile[] files = null;
                ftp.setControlEncoding(encoding);
                files = ftp.listFiles();
                for (int i = 0; i < files.length; i++) {
                    if(remoteBaseDir.equals(files[i].getName())){
                        try {
                            downloadFile(files[i], localBaseDir, remoteBaseDir);
                        } catch (Exception e) {
                            if (LOG.isInfoEnabled()) {
                                LOG.info("<" + files[i].getName() + ">下载失败");
                            }
                            LOG.error(e);
                        }
                    }
                }
            } catch (Exception e) {
                if (LOG.isInfoEnabled()) {
                    LOG.info("下载过程中出现异常");
                }
                LOG.error(e);
            }
        } else {
            if (LOG.isInfoEnabled()) {
                LOG.info("链接FTP服务失败!");
            }
        }

    }
    /**
     * 下载链接配置(mapp定制版本)
     * @param folderName 文件夹目录
     * @param localBaseDir 本地目录
     * @param remoteBaseDir ftp目录
     */
    public static void download(final String folderName, final String localBaseDir, final String remoteBaseDir){
        FtpVO f = new FtpVO();
        f.setIpAddr(SystemConfigUtil.get("FTPIPADDR","FTP"));
        f.setUserName(SystemConfigUtil.get("FTPUSERNAME","FTP"));
        f.setPwd(SystemConfigUtil.get("FTPPWD","FTP"));
        f.setPath(SystemConfigUtil.get("FTPPATH","FTP")); //根目录
        f.setFolderName("server/"+folderName); //业务子目录(支持无限层)
        try {
            startDown(f,localBaseDir,remoteBaseDir);
        } catch (Exception e) {
            if(LOG.isInfoEnabled()){
                LOG.info("下载失败,错误源于startDown方法内部暴露");
            }
            LOG.error(e);
        }
    }
    
    /**
     *
     * 下载FTP文件 当你需要下载FTP文件的时候,调用此方法 根据<b>获取的文件名,本地地址,远程地址</b>进行下载
     *
     * @param ftpFile
     * @param relativeLocalPath
     * @param relativeRemotePath
     */
    private static void downloadFile(final FTPFile ftpFile, final String relativeLocalPath,
            final String relativeRemotePath) {
        if (ftpFile.isFile()) {
            if (ftpFile.getName().indexOf("?") == -1) {
                //if (ftpFile.getName().equals(relativeRemotePath)) {
                    OutputStream outputStream = null;
                    try {
                        File locaFile = new File(relativeLocalPath + ftpFile.getName());
                        // 判断文件是否存在,存在则返回
                        if (locaFile.exists()) {
                            return;
                        } else {
                            outputStream = new FileOutputStream(relativeLocalPath + ftpFile.getName());
                            ftp.retrieveFile(ftpFile.getName(), outputStream);
                            outputStream.flush();
                            outputStream.close();
                        }
                    } catch (Exception e) {
                        LOG.error(e);
                    } finally {
                        try {
                            if (outputStream != null) {
                                outputStream.close();
                            }
                        } catch (IOException e) {
                            if (LOG.isInfoEnabled()) {
                                LOG.info("输出文件流异常");
                            }
                        }
                    }
                //}
            }
        } else {
            String newlocalRelatePath = relativeLocalPath + ftpFile.getName();
            String newRemote = new String(relativeRemotePath + ftpFile.getName().toString());
            File fl = new File(newlocalRelatePath);
            if (!fl.exists()) {
                fl.mkdirs();
            }
            try {
                newlocalRelatePath = newlocalRelatePath + '/';
                newRemote = newRemote + "/";
                String currentWorkDir = ftpFile.getName().toString();
                boolean changedir = ftp.changeWorkingDirectory(currentWorkDir);
                if (changedir) {
                    FTPFile[] files = null;
                    files = ftp.listFiles();
                    for (int i = 0; i < files.length; i++) {
                        downloadFile(files[i], newlocalRelatePath, newRemote);
                    }
                }
                if (changedir) {
                    ftp.changeToParentDirectory();
                }
            } catch (Exception e) {
                LOG.error(e);
            }
        }
    }
    /**
     * 根据mapp名称创建模板服务并上传到ftp
     * @param mappName
     * @return
     */
    public static String upload(final String mappName){
        String ftpUrl= "ftp://"+SystemConfigUtil.get("FTPIPADDR","FTP")+SystemConfigUtil.get("FTPPATH","FTP");
        FtpVO f = new FtpVO();
        f.setIpAddr(SystemConfigUtil.get("FTPIPADDR","FTP"));
        f.setUserName(SystemConfigUtil.get("FTPUSERNAME","FTP"));
        f.setPwd(SystemConfigUtil.get("FTPPWD","FTP"));
        f.setPath(SystemConfigUtil.get("FTPPATH","FTP")); //根目录
        f.setFolderName("source"); //业务子目录(支持无限层)
        ftpUrl+="source/"+mappName;
        try {
            FtpUtil.connectFtp(f);
            String templePrjPath = SystemConfigUtil.get("SERVER_BASE_HOME","FTP")+"/mapp/";  
            MappFileUtil.createProjectByMappName("mapptemplate",null,mappName, templePrjPath);
            File file = new File(templePrjPath.substring(0,templePrjPath.indexOf("/")+1)+mappName);
            FtpUtil.upload(file);
            ForderUtil.deleteFolder(templePrjPath.substring(0,templePrjPath.indexOf("/")+1)+mappName);
        } catch (Exception e) {
            if(LOG.isInfoEnabled()){
                LOG.info("FTP链接失败");
            }
            LOG.error(e);
        }
        
        return ftpUrl;
        
    }
    /**
     * 根据mappName名称和folderName下载资源
     * @param mappName
     * @param folderName 目录的名称
     * @param fileEndType 文件末尾类型 (.zip,.jar)
     * @return
     */
    public static InputStream downloadInputStream(final String mappName,final String folderName,String fileEndType,final String type) {
        InputStream input1 = null;
        FtpVO f = new FtpVO();
        f.setIpAddr(SystemConfigUtil.get("FTPIPADDR","FTP"));
        f.setUserName(SystemConfigUtil.get("FTPUSERNAME","FTP"));
        f.setPwd(SystemConfigUtil.get("FTPPWD","FTP"));
        f.setPath(SystemConfigUtil.get("FTPPATH","FTP")); // 根目录
        f.setFolderName(type+File.separator+mappName); // 业务子目录(支持无限层)
        try {
            FtpUtil.connectFtp(f);
            String templePrjPath = SystemConfigUtil.get("SERVER_BASE_HOME","FTP")+File.separator;
            String basePath = templePrjPath+type;
            if(!StringUtil.isNotEmptyString(fileEndType)){
                fileEndType=".zip";
            }
            //删除之前下载文档,避免一直下载旧资源/服务包
            ForderUtil.deleteFolder(basePath+File.separator+mappName+"."+folderName+fileEndType);
            File file =new File(basePath);
            //如果文件夹不存在,创建一个对应文件夹
            if(!file.exists()){
               file.mkdirs();
            }
            FtpUtil.startDown(f, basePath+File.separator, mappName+"."+folderName+fileEndType);
            if("server".equals(type)){
               EndorsementUtil.changeZipFile(basePath+File.separator, mappName+"."+folderName+fileEndType, mappName);
            }
            input1 = new FileInputStream(new File(basePath+File.separator+mappName+"."+folderName+fileEndType));
            if (LOG.isInfoEnabled()) {
                LOG.info("将ftp服务器上的mappName文件下在到localAddress");
            }
        } catch (Exception e) {
            if (LOG.isInfoEnabled()) {
                LOG.info("FTP链接失败");
            }
            LOG.error(e);
        } // 下载ftp文件测试
        return input1;
    }
    /**
     * 将ftp服务器上的mappName文件下在到localAddress
     * @param localAddress
     * @param mappName
     */
    public static void download(final String localAddress,final String mappName){
        FtpVO f = new FtpVO();
        f.setIpAddr(SystemConfigUtil.get("FTPIPADDR","FTP"));
        f.setUserName(SystemConfigUtil.get("FTPUSERNAME","FTP"));
        f.setPwd(SystemConfigUtil.get("FTPPWD","FTP"));
        f.setPath(SystemConfigUtil.get("FTPPATH","FTP")); //根目录
        f.setFolderName("source"); //业务子目录(支持无限层)
        try {
            FtpUtil.connectFtp(f);
            FtpUtil.startDown(f, localAddress,mappName);
            if(LOG.isInfoEnabled()){
                LOG.info("将ftp服务器上的mappName文件下在到localAddress");
            }
        } catch (Exception e) {
             if(LOG.isInfoEnabled()){
                    LOG.info("FTP链接失败");
                }
                LOG.error(e);
        }// 下载ftp文件测试
    }
    
    /**
     * 测试方法
     *
     * @param args
     * @throws Exception
     */
    public static void main(final String[] args) throws Exception {
        FtpVO f = new FtpVO();
        f.setIpAddr("ecpresource.ygsoft.com");
        f.setUserName("sunhao");
        f.setPwd("1234.zxcv");
        f.setPath("/ECP_Version/MAPP/"); //根目录
        f.setFolderName("server/mpftest6050"); //业务子目录(支持无限层)
        boolean c =FtpUtil.connectFtp(f);
        
        //File file = new File("F:/ziptest.zip");
        //FtpUtil.upload(file);// 把文件上传在ftp上
        //FileInputStream input = new FileInputStream(file);
        //FtpUtil.uploadByInputStream(input, "x002", "x002.zip","ziptest.zip");
        //FtpUtil.startDown(f, "G:/","zjzf");// 下载ftp文件测试
        //FtpUtil.upload("ww89");
        //FtpUtil.download("G:/", "mpftest6050.1.0.jar");
        
        
//         FileOutputStream out = new FileOutputStream("G:/c.jar");
//         InputStream in =FtpUtil.downloadInputStream("mpftest6050","1.0",".jar");
//        
//         byte[] buffer = new byte[1024];
//         int byteread = 0; // 读取的字节数
//         while ((byteread = in.read(buffer)) != -1) {
//         out.write(buffer, 0, byteread);
//         }
//         in.close();
//         out.close();
        System.out.println("ok"+c);
        //  ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(""));
    }

}


/************FtpVO**********************************/


/*
 * Copyright 2000-2020 YGSoft.Inc All Rights Reserved.
 */
package com.ygsoft.ecp.app.mappcore.impl.util;

/**
 * FTP数据模型.<br>
 *
 * @author mapengfei <br>
 * @version 1.0.0 2016年4月9日<br>
 * @see
 * @since JDK 1.5.0
 */
public class FtpVO {

    private String ipAddr;// ip地址

    private Integer port;// 端口号

    private String userName;// 用户名

    private String pwd;// 密码
    
    private String folderName; // 根目录文件夹(当前用户在ftp上的权限范围根目录或指定目录,如只指定对mapp目录进行操作)

    /**
     * 获取folderName.
     * @return the folderName
     */
    public String getFolderName() {
        return folderName;
    }

    /**
     * 设置folderName.
     * @param newFolderName the folderName to set
     */
    public void setFolderName(final String newFolderName) {
        folderName = newFolderName;
    }

    /**
     * 获取ipAddr.
     *
     * @return the ipAddr
     */
    public String getIpAddr() {
        return ipAddr;
    }

    /**
     * 设置ipAddr.
     *
     * @param newIpAddr
     *            the ipAddr to set
     */
    public void setIpAddr(final String newIpAddr) {
        ipAddr = newIpAddr;
    }

    /**
     * 获取port.
     *
     * @return the port
     */
    public Integer getPort() {
        return port;
    }

    /**
     * 设置port.
     *
     * @param newPort
     *            the port to set
     */
    public void setPort(final Integer newPort) {
        port = newPort;
    }

    /**
     * 获取userName.
     *
     * @return the userName
     */
    public String getUserName() {
        return userName;
    }

    /**
     * 设置userName.
     *
     * @param newUserName
     *            the userName to set
     */
    public void setUserName(final String newUserName) {
        userName = newUserName;
    }

    /**
     * 获取pwd.
     *
     * @return the pwd
     */
    public String getPwd() {
        return pwd;
    }

    /**
     * 设置pwd.
     *
     * @param newPwd
     *            the pwd to set
     */
    public void setPwd(final String newPwd) {
        pwd = newPwd;
    }

    /**
     * 获取path.
     *
     * @return the path
     */
    public String getPath() {
        return path;
    }

    /**
     * 设置path.
     *
     * @param newPath
     *            the path to set
     */
    public void setPath(final String newPath) {
        path = newPath;
    }

    private String path;// aaa路径
}