package com.cm.common.plugin.pojo.util;

import com.cm.common.config.properties.SystemProperties;
import com.cm.common.utils.DateUtil;
import com.github.tobato.fastdfs.FdfsClientConfig;
import com.github.tobato.fastdfs.domain.fdfs.FileInfo;
import com.github.tobato.fastdfs.domain.fdfs.MetaData;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.fdfs.ThumbImageConfig;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadByteArray;
import com.github.tobato.fastdfs.service.AppendFileStorageClient;
import com.github.tobato.fastdfs.service.DefaultGenerateStorageClient;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.csource.fastdfs.ProtoCommon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.support.RegistrationPolicy;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Set;
import java.util.regex.Pattern;

/**
 集成FastDFS分布式文件系统
 崔宝铖
 2020年10月17日14:55:20
 application.yml中添加配置
 fdfs:
    so-timeout: 1501                #socket连接超时时长
    connect-timeout: 601            #连接tracker服务器超时时长
    thumb-image:                    #缩略图的宽高，可选
        width: 60
        height: 60
    tracker-list:                   #TrackerList参数,支持多个
        - 192.168.1.105:22122
        - 192.168.1.106:22122
    pool:
        max-total: -1               #从池中借出的对象的最大数目（配置为-1表示不限)
        max-wait-millis: 5000       #获取连接时的最大等待毫秒数(默认配置为5秒)
        max-total-per-key: 50       #每个key最大连接数
        max-idle-per-key: 10        #每个key对应的连接池最大空闲连接数
        max_idle_per_key: 5         #每个key对应的连接池最小空闲连接数
 */
@Configuration
@Import(FdfsClientConfig.class)// 导入FastDFS-Client组件(自动读取application.yml中fdfs下的配置)
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)// 解决jmx重复注册bean的问
public class FastDFSUtil {

    @Autowired
    private FastFileStorageClient fastFileStorageClient;
    @Autowired
    private DefaultGenerateStorageClient defaultGenerateStorageClient;
    @Autowired
    // 此服务上传功能支持断点续传, 后期根据业务需要进行集成封装
    private AppendFileStorageClient appendFileStorageClient;
    @Autowired
    private SystemProperties systemProperties;
    @Autowired
    private ThumbImageConfig thumbImageConfig;

    // 图片正则
    private final String image = ".+(.jpeg|.jpg|.png|.bmp|.gif|.JPEG|.JPG|.PNG|.BMP|.GIF)$";
    // 音频正则
    private final String audio = ".+(.mp3|.wma|.wav|.amr|.MP3|.WMA|.WAV|.AMR)$";
    // 视频正则
    private final String video = ".+(.3gp|.mp4|.rmvb|.avi|.mov|.3GP|.MP4|.RMVB|.AVI|.MOV)$";
    // Word文档正则
    private final String word = ".+(.docx|.doc|.DOCX|.DOC)$";
    // Excel表格正则
    private final String excel = ".+(.xlsx|.xls|.XLSX|.XLS)$";
    // PDF表格正则
    private final String pdf = ".+(.pdf|.PDF)$";
    // 压缩文件正则
    private final String zip = ".+(.rar|.zip|.RAR|.ZIP)$";
    // 文本文件格式
    private final String txt = ".+(.txt|.TXT)$";
    // 禁止格式
    private final String prohibit = ".+(.ini|.jsp|.java|.exe|.html|.js|.css|.bat|.com|.dll|.log|.asp|.php|.INI|.JSP|.JAVA|.EXE|.HTML|.JS|.CSS|.BAT|.COM|.DLL|.LOG|.ASP|.PHP)$";
    // 防盗链私钥
    private final String secret_key = "FastDFS1234567890";

    /**
     * 获得token拼接后的路径
     * @param filePath 文件路径
     */
    public String getTokenJoinPath(String filePath) {
        String substring = filePath.substring(filePath.indexOf("/")+1);
        // unix时间戳 以秒为单位
        int ts = (int) (System.currentTimeMillis() / 1000);
        String token = new String();
        try {
            // 算出Token
            token= ProtoCommon.getToken(substring, ts, secret_key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        StringBuilder sb = new StringBuilder();
        sb.append(filePath);
        sb.append("?token=").append(token);
        sb.append("&ts=").append(ts);
        return sb.toString();
    }

    /**
     * 获得文件元数据
     * @param filePath 文件路径
     * @return
     */
    public FileInfo getFileInfo(String filePath) {
        String group = filePath.substring(0, filePath.indexOf("/"));
        String path = filePath.substring(filePath.indexOf("/")+1);
        return defaultGenerateStorageClient.queryFileInfo(group, path);
    }

    /**
     * 获得文件元数据
     * @param filePath 文件路径
     * @return
     */
    public Set<MetaData>  getFileMeta(String filePath) {
        String group = filePath.substring(0, filePath.indexOf("/"));
        String path = filePath.substring(filePath.indexOf("/")+1);
        return defaultGenerateStorageClient.getMetadata(group, path);
    }

    /**
     * 删除文件
     * @param group 指定组的文件
     * @param filePath 文件路径
     */
    public void delete(String group, String filePath) {
        fastFileStorageClient.deleteFile(group, filePath);
    }

    /**
     * 删除文件
     * @param filePath 文件路径
     */
    public void delete(String filePath) {
        fastFileStorageClient.deleteFile(filePath);
    }

    /**
     * 图片上传 - 带缩略图
     * 路径解释 缩略图在原有的路径后拼接像素大小
     * 源图 http://localhost:8098/M00/00/17/rBEAAl33pQaAWNQNAAHYvQQn-YE374.jpg
     * 缩略图 http://localhost:8098/M00/00/17/rBEAAl33pQaAWNQNAAHYvQQn-YE374_150x150.jpg
     * @param uploadFile 上传的文件
     * @param mataData 自定义参数元数据
     * @return 图片路径对象
     */
    public ImagePath uploadFileImage(MultipartFile uploadFile, Set<MetaData> mataData) {
        StorePath storePath  = null;
        try {
            // 获得文件后缀名
            String extension = FilenameUtils.getExtension(uploadFile.getOriginalFilename());
            // 所属系统
            mataData.add(new MetaData("authorServer", systemProperties.getTitle()));
            // 文件大小
            mataData.add(new MetaData("fileLength", String.valueOf(uploadFile.getSize())));
            // 远程IP
            mataData.add(new MetaData("remoteIP", getRemoteIP()));
            // 上传时间
            mataData.add(new MetaData("uploadTime", DateUtil.getTime()));
            // 文件原名
            mataData.add(new MetaData("fileName", uploadFile.getOriginalFilename()));
            // 文件后缀名
            mataData.add(new MetaData("fileExtension", extension));
            // 文件类型
            mataData.add(new MetaData("fileType", getFileType(uploadFile.getOriginalFilename())));
            // 上传
            storePath = fastFileStorageClient.uploadImageAndCrtThumbImage(uploadFile.getInputStream(), uploadFile.getSize(), FilenameUtils.getExtension(uploadFile.getOriginalFilename()), mataData);
        }catch(Exception e) {
            e.printStackTrace();
        }
        if(storePath == null) {
            return null;
        }
        ImagePath path = new ImagePath();
        path.setPicturePath(storePath.getFullPath());
        path.setThumbnailPath( thumbImageConfig.getThumbImagePath(storePath.getFullPath()));
        return path;
    }

    /**
     * 文件上传
     * @param uploadFile 上传的文件
     * @param mataData 自定义参数元数据
     * @return 文件路径
     */
    public String uploadFile(MultipartFile uploadFile, Set<MetaData> mataData) {
        StorePath storePath  = null;
        try {
            // 获得文件后缀名
            String extension = FilenameUtils.getExtension(uploadFile.getOriginalFilename());
            // 所属系统
            mataData.add(new MetaData("authorServer", systemProperties.getTitle()));
            // 文件大小
            mataData.add(new MetaData("fileLength", String.valueOf(uploadFile.getSize())));
            // 远程IP
            mataData.add(new MetaData("remoteIP", getRemoteIP()));
            // 上传时间
            mataData.add(new MetaData("uploadTime", DateUtil.getTime()));
            // 文件原名
            mataData.add(new MetaData("fileName", uploadFile.getOriginalFilename()));
            // 文件后缀名
            mataData.add(new MetaData("fileExtension", extension));
            // 文件类型
            mataData.add(new MetaData("fileType", getFileType(uploadFile.getOriginalFilename())));
            // 上传
            storePath = fastFileStorageClient.uploadFile(uploadFile.getInputStream(), uploadFile.getSize(), FilenameUtils.getExtension(uploadFile.getOriginalFilename()), mataData);
        }catch(Exception e) {
            e.printStackTrace();
        }
        return storePath == null ? null : storePath.getFullPath();
    }

    /**
     * 文件下载
     * @param path 文件路径
     * @param filename 下载的文件命名
     * @return
     */
    public void download(String path, String filename, HttpServletResponse response) throws IOException {
        // 获取文件
        StorePath storePath = StorePath.parseFromUrl(path);
        if (StringUtils.isBlank(filename)) {
            filename = FilenameUtils.getName(storePath.getPath());
        }
        byte[] bytes = fastFileStorageClient.downloadFile(storePath.getGroup(), storePath.getPath(), new DownloadByteArray());
        response.reset();
        response.setContentType("applicatoin/octet-stream");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
        ServletOutputStream out = response.getOutputStream();
        out.write(bytes);
        out.close();
    }

    /**
     * 判断文件类型
     * 2020年2月11日22:06:31 崔宝铖
     * @param fileName
     * @return
     */
    private String getFileType(String fileName) {
        // 图片格式
        if(Pattern.compile(fileName).matcher(image).find()) {
            return "image";
        }
        // 音频格式
        if(Pattern.compile(fileName).matcher(audio).find()) {
            return "audio";
        }
        // 视频格式
        if(Pattern.compile(fileName).matcher(video).find()) {
            return "video";
        }
        // word文档格式
        if(Pattern.compile(fileName).matcher(word).find()) {
            return "word";
        }
        // Excel格式
        if(Pattern.compile(fileName).matcher(excel).find()) {
            return "excel";
        }
        // PDF格式
        if(Pattern.compile(fileName).matcher(pdf).find()) {
            return "pdf";
        }
        // 压缩文件格式
        if(Pattern.compile(fileName).matcher(zip).find()) {
            return "zip";
        }
        // 文本文件格式
        if(Pattern.compile(fileName).matcher(txt).find()) {
            return "txt";
        }
        // 禁止格式
        if(Pattern.compile(fileName).matcher(prohibit).find()) {
            return "prohibit";
        }
        // 未知
        return "unknown";
    }

    private String getRemoteIP() throws Exception {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = "";
        if (request.getHeader("x-forwarded-for") == null) {
            ip = request.getRemoteAddr();
        }else{
            ip = request.getHeader("x-forwarded-for");
        }
        return ip;
    }

}
