package cc.smtweb.system.bpm.spring.controller;

import cc.smtweb.framework.core.annotation.SwParam;
import cc.smtweb.framework.core.cache.redis.RedisManager;
import cc.smtweb.framework.core.common.R;
import cc.smtweb.framework.core.common.SwConsts;
import cc.smtweb.framework.core.util.FileUtil;
import cc.smtweb.framework.core.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.PrintWriter;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

/**
 * Created with IntelliJ IDEA.
 * User: AKhh
 * Date: 12-12-31 上午11:17
 * 验证码，放入Session
 */
@Slf4j
@RestController
@RequestMapping("/api")
public class VerifyCodeController {
    private final static String CODES = "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYXZ";

    //生成验证码
    @RequestMapping(value = "/getVerifyCode")
    public void getVerifyCode(@SwParam("uuid") String uuid, HttpServletRequest request, HttpServletResponse response) throws Exception {
        setNoCache(response);
        // 检验码只有4位长
        String code = createCode();
        RedisManager.getInstance().set(uuid + "_" + SwConsts.LOGIN_VERIFY_CODE, code, 600);
        // 在内存中创建图象
        int count = code.length();
        int fontSize = 28; //code的字体大小
        int fontMargin = fontSize / 18; //字符间隔
        int width = 90; //图片长度
        int height = 38; //图片高度，根据字体大小自动调整；调整这个系数可以调整字体占图片的比例
        int avgWidth = (int) (width / count / 1.2); //字符平均占位宽度
        int maxDegree = 26; //最大旋转度数
        //生成随机类
        ThreadLocalRandom random = ThreadLocalRandom.current();
        //背景颜色
        Color bkColor = Color.WHITE;
        Color bdColor = new Color(220, 223, 230);

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();

        //填充底色为灰白
        g.setColor(bkColor);
        g.fillRect(0, 0, width, height);

        //画边框
        g.setColor(bdColor);
        g.drawRect(0, 0, width - 1, height - 1);

        //画干扰字母、数字
        int dSize = (int) (fontSize / 2.5); //调整分母大小以调整干扰字符大小
        Font font = new Font("Fixedsys", Font.PLAIN, dSize);
        g.setFont(font);
        int dNumber = width * height * 2 / dSize / dSize;//根据面积计算干扰字母的个数
        for (int i = 0; i < dNumber; i++) {
            char d_code = CODES.charAt(random.nextInt(CODES.length()));
            g.setColor(getRandColor(100, 150));
            g.drawString(String.valueOf(d_code), random.nextInt(width), random.nextInt(height));
        }

        //开始画验证码：

        // 创建字体
        font = new Font(Font.MONOSPACED, Font.ITALIC | Font.BOLD, fontSize);
        // 设置字体
        g.setFont(font);

        for (int i = 0; i < count; i++) {
            char c = code.charAt(i);
            g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));//随机选取一种颜色

            //随机旋转一个角度[-maxDegre, maxDegree]
            int degree = random.nextInt(-maxDegree, maxDegree + 1);

            //偏移系数，和旋转角度成反比，以避免字符在图片中越出边框
            double offsetFactor = 1 - (Math.abs(degree) / (maxDegree + 1.0));//加上1，避免出现结果为0

            g.rotate(degree * Math.PI / 180); //旋转一个角度
            int x_bound = avgWidth - fontSize;
            if (x_bound < 0) x_bound = 1;
            int x = (int) ((fontMargin * (i - 1)) + random.nextInt(x_bound) * offsetFactor) - 8; //横向偏移的距离
            int y = (int) (fontSize + random.nextInt(height - fontSize) * offsetFactor); //上下偏移的距离

            g.rotate(-degree * Math.PI / 180); //画完一个字符之后，旋转回原来的角度
            g.translate(avgWidth, 0);//移动到下一个画画的原点

            g.drawString(String.valueOf(c), x, y); //x,y是字符的左下角，偏离原点的距离！！！
            //System.out.println(c+": x="+x+" y="+y+" degree="+degree+" offset="+offsetFactor);

            //X、Y坐标在合适的范围内随机，不旋转：
            //g.drawString(String.valueOf(c), width / count * i + random.nextInt(width / count - fontSize), fontSize + random.nextInt(height - fontSize));
        }
        g.dispose();
        writeResponseJson(response, JsonUtil.encodeString(R.success(FileUtil.imgToBase64(image))));
    }

    private void writeResponseJson(HttpServletResponse response, String ret) {
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0L);
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
            writer.write(ret);
            writer.flush();
        } catch (Exception e) {
            log.error("response error", e);
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

    private void setNoCache(HttpServletResponse response) {
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
    }

    //生成验证码内容
    private String createCode() {
        //生成随机类
        Random random = new Random();
        // 生成四个随机数
        int a = random.nextInt(CODES.length());
        int b = random.nextInt(CODES.length());
        int c = random.nextInt(CODES.length());
        int d = random.nextInt(CODES.length());
        StringBuilder sb = new StringBuilder(4);
        sb.append(CODES.charAt(a)).append(CODES.charAt(b)).append(CODES.charAt(c)).append(CODES.charAt(d));
        return sb.toString();
    }

    private String createCodeEx() {
        //生成随机类
        Random random = new Random();
        // 生成四个随机数
        int a = random.nextInt(10);
        int b = random.nextInt(10);
        int c = random.nextInt(10);
        int d = random.nextInt(10);
        StringBuilder sb = new StringBuilder(4);
        sb.append(a).append(b).append(c).append(d);
        return sb.toString();
    }

    //给定范围获得随机颜色
    private Color getRandColor(int fc, int bc) {
        Random random = new Random();
        if (fc > 255) fc = 255;
        if (bc > 255) bc = 255;
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }
}
