package xyz.wbsite.frame.utils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

/**
 * 验证码生成工具
 * 通过Builder对象构建参数
 *
 * @author wangbing
 * @version 0.0.1
 * @since 2020-05-01
 */
public class VerifyCodeUtil {

    public static class Builder {
        private String code;
        private int size = 35;
        private String dict = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
        private BufferedImage bufferedImage;
        private boolean freeColor = true;
        private Color color = Color.BLACK;
        private Color bgColor = Color.WHITE;

        public Builder code(String code) {
            this.code = code;
            return this;
        }

        public Builder size(int size) {
            this.size = size;
            return this;
        }

        public Builder dict(String dict) {
            this.dict = dict;
            return this;
        }

        public Builder freeColor(boolean freeColor) {
            this.freeColor = freeColor;
            return this;
        }

        public Builder color(Color color) {
            this.color = color;
            return this;
        }

        public Builder bgColor(Color bgColor) {
            this.bgColor = bgColor;
            return this;
        }

        public boolean toFile(File file) {
            if (bufferedImage == null) build();
            try {
                ImageIO.write(bufferedImage, "png", file);
                return true;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return false;
        }

        public String toCode() {
            return code;
        }

        public byte[] toBytes() {
            if (bufferedImage == null) build();
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            try {
                ImageIO.write(bufferedImage, "png", stream);
                return stream.toByteArray();
            } catch (IOException e) {

            }
            return null;
        }

        public String toBase64() {
            if (bufferedImage == null) build();
            return Base64Util.encodeToString(toBytes());
        }

        public Builder build() {
            if (StringUtil.isEmpty(code)) {
                this.code = RandomUtil.getString(dict, 4);
            }

            if (bufferedImage == null) {
                bufferedImage = new BufferedImage(size * code.length(), size, BufferedImage.TYPE_INT_RGB);
            }

            draw(this, bufferedImage);
            return this;
        }
    }

    /**
     * 根据Builder参数取绘制验证码
     *
     * @param builder   构建参数
     * @param verifyImg 抽象图片
     */
    public static void draw(Builder builder, BufferedImage verifyImg) {
        //验证码
        String code = builder.code;
        //方块大小
        int size = builder.size;
        //宽度
        int width = builder.size * builder.code.length();
        //高度
        int height = builder.size;
        //背景色
        Color bgColor = builder.bgColor;
        //是否随机颜色
        boolean freeColor = builder.freeColor;
        //字符颜色，仅当freeColor为false时生效
        Color color = builder.color;

        Graphics2D graphics = (Graphics2D) verifyImg.getGraphics();
        graphics.setColor(bgColor);//设置画笔颜色-验证码背景色
        graphics.fillRect(0, 0, width, height);//填充背景
        graphics.setFont(new Font("微软雅黑", Font.BOLD, (int) (height * 0.9)));

        for (int i = 0; i < code.length(); i++) {
            char c = code.charAt(i);
            int descent = graphics.getFontMetrics().getDescent();// 字符基线以下高度
            int charWidth = graphics.getFontMetrics().charWidth(c);// 字符高度
            int charHeight = graphics.getFontMetrics().getHeight();// 字符高度

            int centerX = size * i + size / 2;// 字符水平中心坐标
            int centerY = size / 2;// 字符垂直中心坐标
            int offsetX = -charWidth / 2;
            int offsetY = charHeight / 2 - descent;

            // 设置颜色
            graphics.setColor(freeColor ? getRandomColor() : color);
            // 设置字体旋转角度
            int degree = RandomUtil.getInt(-30, 30);
            // 旋转
            graphics.rotate(degree * Math.PI / 180, centerX, centerY);
            // 绘制字符
            graphics.drawString(String.valueOf(c), centerX + offsetX, centerY + offsetY);
            // 恢复旋转
            graphics.rotate(-degree * Math.PI / 180, centerX, centerY);
        }

        //画干扰线
        for (int i = 0; i < size / 5; i++) {
            // 设置颜色
            graphics.setColor(freeColor ? getRandomColor() : color);
            // 随机画线
            graphics.drawLine(RandomUtil.getInt(1, width), RandomUtil.getInt(1, height), RandomUtil.getInt(1, width), RandomUtil.getInt(1, height));
        }

        //添加噪点
        for (int i = 0; i < size; i++) {
            int x1 = RandomUtil.getInt(1, width);
            int y1 = RandomUtil.getInt(1, height);
            graphics.setColor(freeColor ? getRandomColor() : color);
            graphics.fillRect(x1, y1, 2, 2);
        }
    }

    /**
     * 获得一个随机颜色
     */
    private static Color getRandomColor() {
        int r = RandomUtil.getInt(0, 256);
        int g = RandomUtil.getInt(0, 256);
        int b = RandomUtil.getInt(0, 256);
        Color color = new Color(r, g, b);
        return color;
    }
}
