package cn.exploring.engine.server.core.util;

import cn.exploring.engine.server.core.storage.StorageService;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Map;

public class ImageUtil {
    /**
     * 原图存到服务器上的名称的前缀
     */
    private static final String PRE_FIX_SRC_KEY = "src-";

    /**
     * 原图存到服务器上的运动图片名称的前缀
     */
    private static final String PRE_FIX_SRC_STEP_KEY = "STEP-";

    /**
     * 图片最大size。任何图都不能超这个值
     */
    private static final Long DES_FILE_SIZE = 500L;

    /**
     * 图片压缩率
     */
    private static final Double ACCURACY = 0.8D;

    public static void main(String[] args) {
        String srcPath = "E:/storage/actmpstorage/storage/";
        String desPath = "E:/storage/actmpstorage/dec/";

        File srcDir = new File(srcPath);
        File desDir = new File(desPath);
        desDir.mkdir();

        File[] srcFiles = srcDir.listFiles();

        for (File srcFile : srcFiles) {
            String desFileName = FilenameUtils.removeExtension(srcFile.getName()) + ".jpg";
            compress(srcFile.getAbsolutePath(), desPath + desFileName);
        }
    }

    /**
     * 将原始图片上传到服务器本地，并压缩
     * @param storageService
     * @param file
     * @param step 是否是运动图片
     * @return 压缩后的文件流
     * @throws IOException
     */
    public static String storeSrcAndCompress(StorageService storageService, MultipartFile file, Boolean... step) throws IOException {
        String originalFilename = file.getOriginalFilename();
        Map.Entry<String, String> keys = storageService.generateKeyEntry(originalFilename);

        // 原始图片名前缀。运动图片和其它图片不一样，目的是方便在服务器目录找到运动图片
        String pre = PRE_FIX_SRC_KEY;
        if (step != null && step.length > 0 && step[0] != null && step[0] == true) {
            pre = PRE_FIX_SRC_STEP_KEY;
        }

        // 上传原始图片到本地
        String path = storageService.localStore(file.getInputStream(), file.getSize(), file.getContentType(), file.getOriginalFilename(), pre + keys.getKey());

        // 压缩原始图片并返回
        String newPath = path.replace(keys.getKey(), keys.getValue()).replace(pre, "");
        File newFile = compress(path, newPath);

        if (newFile == null || !newFile.exists()) {
            System.out.println("----------------- " + newPath + " 不存在！");
            return null;
        }

        // 如果是本地上传。则不走存储，上一步已经存储了.如果不是本地存储（即阿里云存储，就没办法记数据库了）
        if (storageService.getActive().equals("local")) {
            return storageService.dbStore(newFile.length(), "image/jpeg", originalFilename, keys.getValue());
        } else {
            String url = storageService.storageStore(new FileInputStream(newFile), newFile.length(), "image/jpeg", originalFilename,  keys.getValue());
            return url;
        }
    }

    /**
     * 压缩图片（等比例）
     * @param srcPath
     * @param desPath
     * @return
     */
    private static File compress(String srcPath, String desPath) {
        if (StringUtils.isEmpty(srcPath) || StringUtils.isEmpty(srcPath)) {
            return null;
        }
        if (!new File(srcPath).exists()) {
            return null;
        }
        try {
            File srcFile = new File(srcPath);

            String prefixName = FilenameUtils.removeExtension(srcFile.getName());

            long srcFileSize = srcFile.length();

            // 转换成jpg，输出到目标目录
            Thumbnails.of(srcPath).scale(1f).outputFormat("jpg").toFile(desPath);

            // 递归压缩，直到目标文件大小小于desFileSize
            compressCycle(desPath, DES_FILE_SIZE, ACCURACY);

            File desFile = new File(desPath);

            return desFile;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 压缩方法，递归
     * @param desPath
     * @param desFileSize
     * @param accuracy
     * @throws IOException
     */
    private static void compressCycle(String desPath, long desFileSize, double accuracy) throws IOException {
        File srcFileJPG = new File(desPath);
        long srcFileSizeJPG = srcFileJPG.length();

        if (srcFileSizeJPG <= desFileSize * 1024) {
	        return;
        }
        // 计算宽高
        BufferedImage bim = ImageIO.read(srcFileJPG);
        int srcWdith = bim.getWidth();
        int srcHeigth = bim.getHeight();
        int desWidth = new BigDecimal(srcWdith).multiply(new BigDecimal(accuracy)).intValue();
        int desHeight = new BigDecimal(srcHeigth).multiply(new BigDecimal(accuracy)).intValue();

        Thumbnails.of(desPath).size(desWidth, desHeight).outputQuality(accuracy).toFile(desPath);
        compressCycle(desPath, desFileSize, accuracy);
    }

}
