package com.apobates.forum.bucket.thumbnail.servlet;

import com.apobates.forum.bucket.thumbnail.ImagePath;
import com.apobates.forum.bucket.thumbnail.ThumbConstant;
import com.apobates.forum.utils.Commons;
import com.apobates.forum.utils.image.OverlayBox;
import com.apobates.forum.utils.image.OverlayBox.BoxColor;
import com.apobates.forum.utils.image.OverlayBox.BoxPosition;
import com.apobates.forum.utils.image.OverlayBox.OverlayConfig;
import com.apobates.forum.utils.image.OverlayTextElement.TextElementConfig;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Optional;
import java.util.Properties;
import javax.imageio.ImageIO;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * /cover?dir=$1&amp;file=$2.$4&amp;scale=$3
 *
 * @author xiaofanku
 * @since 20200529
 */
public class ThumbBuilderServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private String originalDir;
    private String thumbDir;
    private int maxWidth;
    //水印相关的
    private boolean allowWater;
    private float waterOpacity;
    private String waterType;
    private BoxPosition waterPosition;
    private static final Logger logger = LoggerFactory.getLogger(ThumbBuilderServlet.class);
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String scaleParameter = req.getParameter("scale"); //接受:auto|width<x>height
        String imageFileName = req.getParameter("file");
        String directory = req.getParameter("dir");
        String water = req.getParameter("water");
        //
        if (null == scaleParameter || scaleParameter.isEmpty()) {
            resp.sendError(400, "scale parameter lost");
            return;
        }
        if (imageFileName.isEmpty() || imageFileName.indexOf(".") == -1) {
            resp.sendError(400, "image file is not exist");
            return;
        }
        if (null == water) { //ADD xiaofanku@20200830 若不存在表示增加水印
            water = "1";
        }
        try {
            String originalImageDirect = getServletContext().getRealPath("/") + originalDir + ThumbConstant.FS;
            String originalImagePath;
            if (!"/".equals(directory)) {
                originalImagePath = directory + ThumbConstant.FS + imageFileName;
            } else {
                originalImagePath = imageFileName;
            }
            Optional<OverlayBox> ob = getWaterOverlayBox(water.equals("1"));
            //是否裁剪
            int imageWidth = getOriginalImageWidth(originalImageDirect + originalImagePath);
            if (imageWidth <= maxWidth && "auto".equals(scaleParameter)) {
                logger.info("[Thumb][TBS]图片尺寸不用裁剪");
                if (!ob.isPresent()) {
                    RequestDispatcher rd = getServletContext().getRequestDispatcher("/" + originalDir + ThumbConstant.WEB_FS + originalImagePath);
                    rd.forward(req, resp);
                } else {
                    try (OutputStream responseOutStream = resp.getOutputStream()) { //20200329@AutoCloseable
                        File originalImage = new File(getServletContext().getRealPath("/" + originalDir + ThumbConstant.WEB_FS + originalImagePath));
                        ob.get().toStream(originalImage, responseOutStream);
                    }
                }
                return;
            }
            //裁剪开始
            ImagePath ip = new ImagePath(scaleParameter, (originalImageDirect + originalImagePath), imageWidth, new File(getServletContext().getRealPath("/") + thumbDir + ThumbConstant.FS));
            if (!ip.getImagePhysicalPath().exists()) {
                if (ob.isPresent()) {
                    logger.info("[Thumb][TBS]设置水印");
                    ip.water(ob);
                }
                logger.info("[Thumb][TBS]开始裁剪");
                ip.makeThumb();
            }
            logger.info("[Thumb][TBS]裁剪图已经存在无需再裁剪");
            redirectThumbImage(req, resp, ip);
        } catch (IOException e) {
            if (logger.isDebugEnabled()) {
                logger.debug("[Thumb][TBS]image thumb create fail");
            }
        }
    }
    
    private Optional<OverlayBox> getWaterOverlayBox(boolean isWater) {
        if (!allowWater || !isWater) {
            return Optional.empty();
        }
        if ("image".equals(waterType)) {
            //图片水印遮盖
            File watermarkImgFile = new File(getServletContext().getRealPath("/watermark/image.png"));
            OverlayBox tmp = OverlayConfig.getDefault().backgroundColor(BoxColor.TRANSPARENT).position(waterPosition).opacity(waterOpacity).isContinueSave(true).image(watermarkImgFile);
            return Optional.of(tmp);
        }
        if ("text".equals(waterType)) {
            Properties p = getTextWatermarkConfig(getServletContext().getRealPath("/watermark/text.properties"));
            if (null != p) {
                TextElementConfig tec = TextElementConfig
                        .getDefault()
                        .fontSize(Commons.stringToInteger(p.getProperty("fontSize"), -1))
                        .fontColor(p.getProperty("fontColor"))
                        .fontFamily(p.getProperty("fontFamily"))
                        .isBold(Boolean.valueOf(p.getProperty("bold")))
                        .rectangle(Commons.stringToInteger(p.getProperty("width"), -1), Commons.stringToInteger(p.getProperty("height"), -1));
                OverlayBox tmp = OverlayConfig.getDefault().backgroundColor(BoxColor.TRANSPARENT).position(waterPosition).opacity(waterOpacity).isContinueSave(true).text(p.getProperty("content"), tec);
                return Optional.of(tmp);
            }
        }
        return Optional.empty();
    }
    
    private Properties getTextWatermarkConfig(String configPath) {
        try {
            Properties configProps = new Properties();
            configProps.load(new FileInputStream(configPath));
            return configProps;
        } catch (IOException e) {
            return null;
        }
    }
    
    /**
     * 获得初始化值
     * @param config
     * @throws javax.servlet.ServletException
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        this.originalDir = config.getInitParameter("original"); //原目录
        this.thumbDir = config.getInitParameter("thumb"); //封面目录
        this.maxWidth = Commons.stringToInteger(config.getInitParameter("maxWidth"), 900);
        //水印相关的
        this.allowWater = Boolean.valueOf(config.getInitParameter("allowWater"));
        //透明度
        this.waterOpacity = Commons.stringToFloat(config.getInitParameter("waterOpacity"), 0.5f);
        if (waterOpacity > 1.0f || waterOpacity < 0.0f) {
            waterOpacity = 0.5f;
        }
        //水印的位置
        this.waterPosition = BoxPosition.getInstance(Commons.stringToInteger(config.getInitParameter("waterPosition"), 0));
        if (null == waterPosition) {
            waterPosition = BoxPosition.BOTTOM_RIGHT;
        }
        //水印的类型
        this.waterType = config.getInitParameter("waterType");
    }
    
    /**
     * 跳转到缩略图地址
     *
     * @param req
     * @param resp
     * @param ip
     * @throws ServletException
     * @throws IOException
     */
    protected void redirectThumbImage(HttpServletRequest req, HttpServletResponse resp, ImagePath ip) throws ServletException, IOException {
        RequestDispatcher rd = getServletContext().getRequestDispatcher(ip.getThumbWebHref(thumbDir));
        rd.forward(req, resp);
    }
    
    /**
     * 计算原始图片的宽度
     *
     * @param originalImagePath 原始图片的物理地址
     * @return
     */
    private int getOriginalImageWidth(String originalImagePath) {
        int imageWidth = 0;
        try {
            BufferedImage bimg = ImageIO.read(new File(originalImagePath));
            imageWidth = bimg.getWidth();
        } catch (NullPointerException | IOException e) {
        }
        return imageWidth;
    }
}