package com.yifu.cloud.plus.v1.yifu.common.core.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;

import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * @program: master
 * @description: 序号生成工具
 * @description: 例如三位数的全部序号如下 000~999、A01~A99 ……Z01~Z99，ZA1~ZA9……ZZ1~ZZ9，ZZA~ZZZ
 * @author: pwang
 * @create: 2020-05-12 09:55
 **/
@Slf4j
public class NoUtil {

    private static char[] alphatableb = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
            'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
            'V', 'W', 'X', 'Y', 'Z'};
    /**
     * 数字加一规则
     *
     * @Author pwang
     * @Date 2020-05-12 14:29
     * @param null
     * @return
     **/
    private static Map<String, String> numberMap = new HashMap() {
        {
            put("0", "1");
            put("1", "2");
            put("2", "3");
            put("3", "4");
            put("4", "5");
            put("5", "6");
            put("6", "7");
            put("7", "8");
            put("8", "9");
        }
    };
    /**
     * 字符加一规则
     *
     * @Author pwang
     * @Date 2020-05-12 14:28
     * @param null
     * @return
     **/
    private static Map<String, String> charMap = new HashMap() {

        {
            put("A", "B");
            put("B", "C");
            put("C", "D");
            put("D", "E");
            put("E", "F");
            put("F", "G");
            put("G", "H");
            put("H", "I");
            put("I", "J");
            put("J", "K");
            put("K", "L");
            put("L", "M");
            put("M", "N");
            put("N", "O");
            put("O", "P");
            put("P", "Q");
            put("Q", "R");
            put("R", "S");
            put("S", "T");
            put("T", "U");
            put("U", "V");
            put("V", "W");
            put("W", "X");
            put("X", "Y");
            put("Y", "Z");
        }
    };

    /**
     * @param args
     */
    public static void main(String[] args) {
        //打印所有流水号
        String initStr = "皖A0000";
        int maxIntStr = 9999;
        String maxStr = "ZZZZ";

        NoUtil noUtil = new NoUtil();

        long d3 = System.currentTimeMillis();
        long i = 0L;
        while (!initStr.equals("皖AZZZZ")) {
            i++;
            initStr = NoUtil.productionNo(initStr,2);
           /*log.info(initStr);*/
            // 测试断点
            if (initStr.equals("皖AZZZZ")) {
                break;
            }
        }
        long d4 = System.currentTimeMillis();
        long d1 = System.currentTimeMillis();
        //重新初始化
        long j = 0L;
        initStr = "0000";
        while (!initStr.equals(maxStr)) {
            j++;
            initStr = noUtil.algorithm4Code(5, initStr, maxIntStr, maxStr);;
            /*log.info(initStr);*/
            // 测试断点
            if (initStr.equals(maxStr)) {
                break;
            }
        }
        long d2 = System.currentTimeMillis();
        log.info("2位最大编码数：" + numberCount(2));
        log.info("3位最大编码数：" + numberCount(3));
        log.info("原方法耗时：" + (d2 - d1));
        log.info("原方法编码数：" + String.valueOf(j));
        log.info("新方法耗时：" + (d4 - d3));
        log.info("新方法编码数：" + String.valueOf(i));
    }



    /**
     * 生成编码算法
     *
     * @param digit      位数
     * @param currentStr 当前流水号
     * @param maxIntStr  最大流水号（数字部分）
     * @param maxStr     最大流水号
     * @return
     */
    public String algorithm4Code(int digit, String currentStr, int maxIntStr, String maxStr) {

        //流水序号，默认4位
        String formatStr1 = "00000";
        int maxNum = maxIntStr;
        StringBuffer tmpBuff = new StringBuffer();
        StringBuffer tmpBuff1 = new StringBuffer();
        for (int i = 1; i < digit; i++) {
            tmpBuff.append(0);
            tmpBuff1.append(9);
        }
        formatStr1 = tmpBuff.toString() + "0";
        maxNum = Integer.parseInt(tmpBuff1.append(9).toString());

        String initStr = "";
        if (currentStr == null) {
            initStr = maxNum + "";
        } else {
            initStr = currentStr;
        }

        //找出字符串最后一位字母
        int sign = 0;
        boolean isfind = false;
        for (int i = initStr.length() - 1; i >= 0; i--) {
            if (initStr.charAt(i) >= 'A' && initStr.charAt(i) <= 'Z') {
                sign = i;
                isfind = true;
                break;
            }
        }
        //分隔字母和数字
        String letterStr = "";
        String numStr = "";
        if (isfind) {
            letterStr = initStr.substring(0, sign + 1);
            numStr = initStr.substring(sign + 1);
        } else {
            numStr = initStr;
        }

        //如果数字部分不全为9，则直接加一，返回
        boolean isAllNine = false;
        for (int i = 0; i < numStr.length(); i++) {
            if (numStr.charAt(i) == '9') {
                isAllNine = true;
            } else {
                isAllNine = false;
                break;
            }
        }
        if (!isAllNine && !"".equals(numStr)) {
            int nextNum = Integer.parseInt(numStr) + 1;
            return letterStr + supplementNumPrefix(nextNum, numStr.length());
        } else {
            //数字部分全为9或者数字部分为空，需要分情况分析
            String nextNum = "";
            if ("".equals(letterStr) && !numStr.equals(String.valueOf(maxIntStr))) {
                //字母部分为空
                String nineStr = numStr.substring(1);
                // nextNum = "A"+restNumberFunc(nineStr);
                nextNum = restNumberFunc(nineStr);
            } else if (numStr.equals(String.valueOf(maxIntStr))) {
                String nineStr = numStr.substring(1);
                nextNum = "A" + restNumberFunc(nineStr);
            } else {
                //字母部分不为空
                //判断字母部分的最后一位字母是否有下一位，比如A，则有下一位B，Z则没有。
                char lastLetter = letterStr.charAt(letterStr.length() - 1);
                int pos = -1;
                //顺序查找
                for (int i = 0; i < alphatableb.length; i++) {
                    if (alphatableb[i] == lastLetter) {
                        pos = i;
                        break;
                    }
                }
                if (pos == -1) {
                    log.info("查找字母出错");
                    return "error";
                }
                if ('Z' == alphatableb[pos]) {
                    //最后一位字母为'Z'
                    if (!"".equals(numStr)) {
                        //Z9999
                        nextNum = letterStr.substring(0, letterStr.length())
                                + 'A' + restNumberFunc(numStr.substring(1));
                    } else {
                        //ZZZZZ
						log.info("商户序号已达到最大值，请联系管理员");
                        return "error";
                    }
                } else {
                    //最后一位字母不为'Z'
                    if (!"".equals(numStr)) {
                        //ZA99
                        nextNum = letterStr.substring(0, letterStr.length() - 1)
                                + alphatableb[pos + 1] + restNumberFunc(numStr);
                    } else {
                        //ZZZA
                        nextNum = letterStr.substring(0, letterStr.length() - 1)
                                + alphatableb[pos + 1];
                    }
                }

            }
            return nextNum;

        }

    }

    /**
     * 补充数字前缀
     *
     * @param nextNum
     * @param numLen
     * @return
     */
    private String supplementNumPrefix(int nextNum, int numLen) {
        StringBuffer tmpBuff = new StringBuffer();
        for (int i = 0; i < numLen; i++) {
            tmpBuff.append(0);
        }
        DecimalFormat format = new DecimalFormat(tmpBuff.toString());
        return format.format(nextNum);
    }

    /**
     * 数据重置函数
     *
     * @param nineStr
     * @return
     */
    public String restNumberFunc(String nineStr) {
        if ("".equals(nineStr)) return nineStr;
        String zeroStr = nineStr.replace('9', '0');
        DecimalFormat format = new DecimalFormat(zeroStr);
        int firstNum = Integer.parseInt(zeroStr) + 1;
        return format.format(firstNum);
    }

    /**
     * 最大序号数量
     *
     * @param digit 位数
     * @return
     * @Author pwang
     * @Date 2020-05-11 18:17
     **/
    public static double numberCount(int digit) {
        //计算规律 (10^digit-1) + （26*(10^(digit-1)-1)+……+26*（10-1））+ 26
        double maxIntStr = Math.pow(10, digit) - 1;
        double reuslt = maxIntStr;
        for (int i = digit - 1; i > 0; i--) {
            reuslt += 26 * (Math.pow(10, i) - 1);
        }
        return reuslt + 26;
    }

    /**
     * 类似35进制找下一个序号
     **/
    public String nextNoByMapFor35(String currentStr) throws RuntimeException {
        char result[] = currentStr.toCharArray();
        boolean resultInfo = false;
        String temp = null;
        for (int i = result.length - 1; i >= 0; i--) {
            if ('Z' != result[i]) {
                temp = charMap.get(String.valueOf(result[i]));
                Assert.notNull(temp, currentStr.concat("含有非法字符！"));
                result[i] = temp.charAt(0);
                resultInfo = true;
                break;
            } else {
                temp = charMap.get(String.valueOf(result[i]));
                Assert.notNull(temp, currentStr.concat("含有非法字符！"));
                result[i] = temp.charAt(0);
            }
        }
        Assert.isTrue(resultInfo, "序号已达到最大值，请联系管理员");
        return String.valueOf(result);
    }

    /**
     * 找下一个序号
     **/
    public static String nextNoByMap(String currentStr) throws RuntimeException {
        Assert.isTrue(null != currentStr,"当前串不能为空！");
        char result[] = currentStr.toUpperCase().toCharArray();
        String temp = null;
        for (int i = result.length - 1; i >= 0; i--) {
            if ('Z' != result[i]) {
                if ('9' == result[i]) {
                    //进位处理
                    if (0 == i || 'Z' == result[i - 1]) {
                        //计算到最高位为9或者下高位是Z本为进位成A
                        result[i] = 'A';
                        if (result.length - 1 != i) {
                            //若本位不是最低位则最低置1
                            result[result.length - 1] = '1';
                        }
                        break;
                    } else {
                        result[i] = '0';
                    }
                } else {
                    temp = numberMap.get(String.valueOf(result[i]));
                    if (null == temp) {
                        //查看是不是字符加一
                        temp = charMap.get(String.valueOf(result[i]));
                        //字符加一也找不到抛出异常
                        Assert.isTrue(null != temp, currentStr.concat("含有非法字符！"));
                        if (result.length - 1 != i) {
                            //字符加一，若本位不是最低位则最低置1
                            result[result.length - 1] = '1';
                        }
                    }
                    result[i] = temp.charAt(0);
                    break;
                }
            } else {
                Assert.isTrue(i != result.length - 1, "序号已达到最大值，请联系管理员");
            }
        }
        return String.valueOf(result);
    }
    /**
     * 开始到starPos保留 + 从第starPos+1开始截取至结尾生产序号
     * @Author pwang
     * @Date 2020-05-14 9:53
     * @param currentStr 当前串
     * @param starPos 从第starPos+1开始有效
     * @return
     **/
    public static String productionNo(String currentStr,int starPos){
       Assert.isTrue(null != currentStr,"当前串不能为空！");
       Assert.isTrue(starPos<currentStr.length(),"当前串共".concat(String.valueOf(currentStr.length())).concat("位，不能从第").concat(String.valueOf(starPos+1)).concat("位截取！"));
       return currentStr.substring(0,starPos).concat(NoUtil.nextNoByMap(currentStr.substring(starPos,currentStr.length())));
    }
}
