package com.artfess.file.util;

import com.artfess.base.exception.BaseException;
import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.converter.StreamOpenOfficeDocumentConverter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.net.ConnectException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * office文档转换为pdf
 * 注意事项：1、openoffice在linux安装卸载，由于一开始openoffice装的版本不太对，后面想卸载发现怎么都卸载不干净，
 * 这里提供一个完全卸载的命令rpm -e `rpm -qa |grep openoffice` `rpm -qa |grep ooobasis`
 * 2、本地调用openoffice转pdf正常，部署到服务器文件乱码。这是由于linux缺少windows环境下中文字体库，通过将C:\Windows\Fonts文件夹下字体，
 * 上传到/usr/share/fonts文件夹下，再通过fc-cache -fv命令更新字体缓存，然后重启openoffice即可解决
 *
 * @author heyifan
 * @company 阿特菲斯信息技术有限公司
 * @email heyf@jee-soft.cn
 * @date 2018年9月30日
 */
@Component
@Slf4j
public class OfficeToPdf {

    @Value("${file.office.ip-addr}")
    String ipAddr;

    @Value("${file.office.port:9193}")
    String port;

    @Resource
    ConverterUtils converterUtils;

    /**
     * 使Office2003-2007全部格式的文档(.doc|.docx|.xls|.xlsx|.ppt|.pptx) 转化为pdf文件<br>
     *
     * @param inputFilePath  源文件路径，如："e:/test.docx"
     * @param outputFilePath 目标文件路径，如："e:/test_docx.pdf"
     * @return
     */
    public boolean openOfficeToPDF(String inputFilePath, String outputFilePath) {
        return office2pdf(inputFilePath, outputFilePath);
    }

    /**
     * 使Office2003-2007全部格式的文档(.doc|.docx|.xls|.xlsx|.ppt|.pptx) 转化为pdf文件<br>
     *
     * @param inputFilePath  源文件路径，如："e:/test.docx"
     * @param outputFilePath 目标文件路径，如："e:/test_docx.pdf"
     * @param remoteStatus 是否使用远程连接openoffice
     * @return
     */
    public boolean openOfficeToPDF(String inputFilePath, String outputFilePath, boolean remoteStatus) {
        if(remoteStatus) {
            return office2pdf(inputFilePath, outputFilePath);
        }else{
            return localOffice2pdf(inputFilePath, outputFilePath);
        }

    }



    /**
     * 转换文件
     *
     * @param inputFile
     * @param outputFilePath_end
     * @param inputFilePath
     * @param outputFilePath
     */
    public void converterFile(File inputFile, String outputFilePath_end, String inputFilePath, String outputFilePath) {
        File outputFile = new File(outputFilePath_end);

        // 假如目标路径不存在,则新建该路径
        if (!outputFile.exists()) {
            outputFile.getParentFile().mkdirs();
        }

        // 解析端口列表并随机选择一个
        String[] portsArray = port.split(",");
        List<Integer> portList = Arrays.stream(portsArray)
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .map(Integer::parseInt)
                .collect(Collectors.toList());

        Collections.shuffle(portList); // 打乱顺序，随机选择

        boolean isConnected = false;

        for (int port : portList) {
            try {
                log.info("尝试连接 OpenOffice 服务，IP: {}, 端口: {}", ipAddr, port);
                SocketOpenOfficeConnection connection = new SocketOpenOfficeConnection(ipAddr, port);
                connection.connect();
                StreamOpenOfficeDocumentConverter converter = new StreamOpenOfficeDocumentConverter(connection);
                converter.convert(inputFile, outputFile);
                isConnected = true;
                break;
            } catch (ConnectException e) {
                log.warn("连接端口失败：{}", port);
            } catch (Exception e) {
                log.error("转换出错，端口：{}", port, e);
            }
        }

        if (!isConnected) {
            throw new BaseException("未能连接到任何可用的 OpenOffice 端口.");
        }
    }



    /**
     * 使Office2003-2007全部格式的文档(.doc|.docx|.xls|.xlsx|.ppt|.pptx) 转化为pdf文件
     *
     * @param inputFilePath  源文件路径，如："e:/test.docx"
     * @param outputFilePath 目标文件路径，如："e:/test_docx.pdf"
     * @return
     */
    public boolean office2pdf(String inputFilePath, String outputFilePath) {
        boolean flag = false;
        if (null != inputFilePath) {
            File inputFile = new File(inputFilePath);
            // 判断目标文件路径是否为空
            if (null == outputFilePath) {
                // 转换后的文件路径
                String outputFilePath_end = getOutputFilePath(inputFilePath);
                if (inputFile.exists()) {// 找不到源文件, 则返回
                    converterFile(inputFile, outputFilePath_end, inputFilePath, outputFilePath);
                    flag = true;
                }
            } else {
                if (inputFile.exists()) {// 找不到源文件, 则返回
                    converterFile(inputFile, outputFilePath, inputFilePath, outputFilePath);
                    flag = true;
                }
            }
        } else {
            flag = false;
        }
        return flag;
    }

    /**
     * 转换文件
     *
     * @param inputFile
     * @param outputFilePath_end
     * @param inputFilePath
     * @param outputFilePath
     * @param converter
     */
    public static void converterFile(File inputFile, String outputFilePath_end,
                                     String inputFilePath, String outputFilePath,
                                     OfficeDocumentConverter converter) {
        File outputFile = new File(outputFilePath_end);

        // 假如目标路径不存在,则新建该路径
        if (!outputFile.exists()) {
            outputFile.getParentFile().mkdirs();
        }
        @SuppressWarnings("unused")
        String outputExtension = FilenameUtils.getExtension(outputFile.getName());
        try {
            converter.convert(inputFile, outputFile);
        }
        catch(NullPointerException e) {
            throw new BaseException("未找到服务端的附件预览组件.",e);
        }
    }

    /**
     * 使Office2003-2007全部格式的文档(.doc|.docx|.xls|.xlsx|.ppt|.pptx) 转化为pdf文件
     *
     * @param inputFilePath
     *            源文件路径，如："e:/test.docx"
     * @param outputFilePath
     *            目标文件路径，如："e:/test_docx.pdf"
     * @return
     */
    public  boolean localOffice2pdf(String inputFilePath, String outputFilePath) {
        boolean flag = false;
        OfficeDocumentConverter converter = converterUtils.getDocumentConverter();
        if (null != inputFilePath) {
            File inputFile = new File(inputFilePath);
            // 判断目标文件路径是否为空
            if (null == outputFilePath) {
                // 转换后的文件路径
                String outputFilePath_end = getOutputFilePath(inputFilePath);
                if (inputFile.exists()) {// 找不到源文件, 则返回
                    converterFile(inputFile, outputFilePath_end, inputFilePath,
                            outputFilePath, converter);
                    flag = true;
                }
            } else {
                if (inputFile.exists()) {// 找不到源文件, 则返回
                    converterFile(inputFile, outputFilePath, inputFilePath,
                            outputFilePath, converter);
                    flag = true;
                }
            }
        } else {
            flag = false;
        }
        return flag;
    }

    /**
     * 获取输出文件
     *
     * @param inputFilePath
     * @return
     */
    public static String getOutputFilePath(String inputFilePath) {
        String outputFilePath = inputFilePath.replaceAll("." + getPostfix(inputFilePath), ".pdf");
        return outputFilePath;
    }

    /**
     * 获取inputFilePath的后缀名，如："e:/test.pptx"的后缀名为："pptx"
     *
     * @param inputFilePath
     * @return
     */
    public static String getPostfix(String inputFilePath) {
        return inputFilePath.substring(inputFilePath.lastIndexOf(".") + 1);
    }
}
