package com.jiuzhekan.cbkj.common.utils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 汉字转拼音（五笔）
 */
public class Dist {

    /**
     * 编码
     */
    private static byte CODE_INDEX = 0;

    /**
     * 汉字
     */
    private static byte CN_INDEX = 1;

    /**
     * 拼音
     */
    private static byte ZH_INDEX = 2;

    /**
     * 统一码
     */
    private static byte UNIFROM_INDEX = 3;

    /**
     * 顺序码
     */
    private static byte NO_INDEX = 4;

    /**
     * 五笔码
     */
    private static byte FIVE_INDEX = 5;

    /**
     * 仓颉
     */
    private static byte CANGJIE_INDEX = 6;

    /**
     * 郑码
     */
    private static byte ZHENG_INDEX = 7;

    /**
     * 四角
     */
    private static byte SJ_INDEX = 8;

    /**
     * 字典文件
     */
    private static String DISTPATH = "dist.ls";

    /**
     * 字典集合
     */
    private static List<String> disList = new ArrayList<>();


    /**
     * 装载字库到内存中
     */
    static {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        if (classLoader == null) {
            classLoader = ClassLoader.getSystemClassLoader();
        }

        java.net.URL url = classLoader.getResource("");
        String ROOT_CLASS_PATH = url.getPath() + "/";

        InputStream stream = classLoader.getResourceAsStream(DISTPATH);

        try (InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
             BufferedReader br = new BufferedReader(reader)) {
            String line;
            while ((line = br.readLine()) != null) {
                disList.add(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据编码获取字典信息（常规算法）
     *
     * @param code 编码
     * @return
     */
    public static String routine(int code) {

        String[] strs;
        for (String str : disList) {
            strs = str.split(",");
            if (Integer.parseInt(strs[CODE_INDEX]) == code) {
                return str;
            }
        }
        return null;
    }

    /**
     * 根据编码获取字典信息（两分查找算法）
     *
     * @param list 字库
     * @param code 编码
     * @return
     */
    public static String dichotomySerach(List<String> list, int code) {

        if (null != list) {

            int len = list.size();
            int size = len / 2;
            if (size == 1) {
                int oCode = Integer.parseInt(list.get(0).split(",")[CODE_INDEX]);
                int lCode = Integer.parseInt(list.get(1).split(",")[CODE_INDEX]);
                if (oCode == code) {
                    return list.get(0);
                }
                if (lCode == code) {
                    return list.get(1);
                }

            } else {
                String thisObj = list.get(size);
                List<String> newList;
                int objCode = Integer.parseInt(thisObj.split(",")[CODE_INDEX]);

                if (code == objCode) {
                    return thisObj;
                } else if (code > objCode) {
                    newList = list.subList(++size, len);
                } else {
                    newList = list.subList(0, size);
                }
                if (newList.size() > 0) {
                    return dichotomySerach(newList, code);
                }
            }
        }
        return null;
    }

    /**
     * 判断是否中文
     *
     * @param countname
     * @return
     */
    public static boolean checkcountname(String countname) {
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(countname);
        if (m.find()) {
            return true;
        }
        return false;
    }

    /**
     * 根据索引获取对应的参数
     *
     * @param cn    单个中文字符
     * @param index 索引值
     * @return
     */
    public static String getObjByIndex(String cn, byte index) {
        assert cn != null;
        if (!"".equals(Objects.requireNonNull(cn).trim()) && checkcountname(cn)) {
            String obj = dichotomySerach(disList, cn.hashCode());
            if (null != obj) {
                return obj.split(",")[index];
            }
        }
        return null;
    }

    /**
     * 根据汉字获取中文拼音（全拼）且返回音调，支持多音字
     *
     * @param cn 单个中文
     * @return
     */
    public static List<String> getCnPinYin(String cn) {

        String objStr = getPinYin(cn);
        if (null == objStr) {
            return null;
        }
        List<String> result = new ArrayList<>();
        for (String str : objStr.split("-")) {
            String cnStr = str.split(":")[1];
            if (!result.contains(cnStr)) {
                result.add(cnStr);
            }
        }
        return result;
    }

    /**
     * 根据汉字获取英文拼音（全拼 1,2,3,4 代表音高低）
     *
     * @param cn     单个中文
     * @param isTone true 返回音调 flase 不反回音调
     * @return
     */
    public static List<String> getZhPinYin(String cn, boolean isTone) {

        String objStr = getPinYin(cn);
        if (null == objStr) {
            return null;
        }
        List<String> result = new ArrayList<>();
        Pattern p = Pattern.compile("[1-4]");
        Matcher matcher;
        for (String str : objStr.split("-")) {
            String chAll = str.split(":")[0];
            if (isTone) {
                if (!result.contains(chAll)) {
                    result.add(chAll);
                }
            } else {
                matcher = p.matcher(chAll);
                String zh = matcher.replaceAll("");
                if (!result.contains(zh)) {
                    result.add(zh);
                }
            }
        }
        return result;
    }

    /**
     * 根据单个中文获取 拼音|英文
     *
     * @param cn 单个中文
     * @return
     */
    public static String getPinYin(String cn) {
        String objStr = getObjByIndex(cn, ZH_INDEX);
        if (null == objStr) {
            return null;
        }
        return objStr.replaceAll("\\{", "").replaceAll("}", "");
    }

    /**
     * 根据单个中文获取五笔码（全）
     *
     * @param cn
     * @return
     */
    public static String getFiveCode(String cn) {
        String objStr = getObjByIndex(cn, FIVE_INDEX);
        if (null == objStr) {
            return null;
        }
        return objStr;
    }

    /**
     * 根据单个中文获取统一码
     *
     * @param cn
     * @return
     */
    public static String getUNIFROM(String cn) {
        String objStr = getObjByIndex(cn, UNIFROM_INDEX);
        if (null == objStr) {
            return null;
        }
        return objStr;
    }

    /**
     * 根据单个中文获取顺序码
     *
     * @param cn
     * @return
     */
    public static String getNO(String cn) {
        String objStr = getObjByIndex(cn, NO_INDEX);
        if (null == objStr) {
            return null;
        }
        return objStr;
    }

    /**
     * 根据单个中文获取昌吉
     *
     * @param cn
     * @return
     */
    public static String getCANGJIE(String cn) {
        String objStr = getObjByIndex(cn, CANGJIE_INDEX);
        if (null == objStr) {
            return null;
        }
        return objStr;
    }

    /**
     * 根据单个中文获取郑码
     *
     * @param cn
     * @return
     */
    public static String getZHENG(String cn) {
        String objStr = getObjByIndex(cn, ZHENG_INDEX);
        if (null == objStr) {
            return null;
        }
        return objStr;
    }

    /**
     * 根据单个中文获取四角
     *
     * @param cn
     * @return
     */
    public static String getSJ(String cn) {
        String objStr = getObjByIndex(cn, SJ_INDEX);
        if (null == objStr) {
            return null;
        }
        return objStr;
    }

    /**
     * 根据词语获取拼音（全拼不反回音调）
     *
     * @param cns
     * @return
     */
    public static String getPinYins(String cns) {
        if (null != cns && cns.length() > 0) {
            String[] arrays = cns.split("");
            StringBuffer sb = new StringBuffer();
            List<String> pyList;
            for (String str : arrays) {
                pyList = getZhPinYin(str, false);
                if (null != pyList && pyList.size() > 0) {
                    sb.append(pyList.get(0));
                }
            }
            return sb.toString();
        }
        return null;
    }

    /**
     * 根据词语获取首拼
     *
     * @param cns
     * @return
     */
    public static String getFirstPinYins(String cns) {
        if (null != cns && cns.length() > 0) {
            String[] arrays = cns.split("");
            StringBuffer sb = new StringBuffer();
            List<String> pyList;
            for (String str : arrays) {
                if (!"".equals(Objects.requireNonNull(str).trim())) {
                    if (checkcountname(str)) {
                        pyList = getZhPinYin(str, false);
                        if (null != pyList && pyList.size() > 0) {
                            sb.append(pyList.get(0), 0, 1);
                        }
                    } else {
                        sb.append(str);
                    }
                }
            }
            return sb.toString();
        }
        return null;
    }

    /**
     * 根据词语获取第一个字的首拼大写
     *
     * @param cns
     * @return
     */
    public static String getFirstUpperPinYin(String cns) {
        if (null != cns && cns.length() > 0) {
            String str = cns.substring(0, 1);
            List<String> pyList = getZhPinYin(str, false);
            if (null != pyList && pyList.size() > 0) {
                return pyList.get(0).substring(0, 1).toUpperCase();
            }
        }
        return null;
    }

    /**
     * 根据词语获取五笔码
     * 一个字：全部，两个字：2+2，三个字：1+1+2，四个：1+1+1+1，五个及以上：前三个字的五笔第一画+最后一个字五笔第一画
     *
     * @param cns 中文
     * @return String
     */
    public static String getFives(String cns) {
        if (null != cns) {
            String[] arrays = cns.split("");
            int size = arrays.length;
            StringBuffer sb = new StringBuffer();
            String str;
            String fiveStr;
            for (int i = 0; i < size; i++) {
                str = arrays[i];
                fiveStr = getFiveCode(str);
                if (null != fiveStr && fiveStr.length() > 0) {
                    if (size == 1) {
                        sb.append(fiveStr);
                    } else if (size == 2) {
                        sb.append(fiveStr, 0, 2);
                    } else if (size == 3) {
                        if (i == 0 || i == 1) {
                            sb.append(fiveStr, 0, 1);
                        } else {
                            sb.append(fiveStr, 0, 2);
                        }
                    } else if (size == 4) {
                        sb.append(fiveStr, 0, 1);
                    } else {
                        if (i < 3 || i == size - 1) {
                            sb.append(fiveStr, 0, 1);
                        }
                    }
                }
            }
            return sb.toString();
        }
        return null;
    }

    /**
     * 根据词语获取五笔码两个字获取首位
     *
     * @param cns
     * @return
     */
    public static String getFiveByFirsts(String cns) {
        if (null != cns) {
            String[] arrays = cns.split("");
            int size = arrays.length;
            StringBuffer sb = new StringBuffer();
            String str;
            String fiveStr;
            for (int i = 0; i < size; i++) {
                str = arrays[i];
                fiveStr = getFiveCode(str);
                if (null != fiveStr && fiveStr.length() > 0) {
                    sb.append(fiveStr, 0, 1);
                }
            }
            return sb.toString();
        }
        return null;
    }

    public static void main(String[] args) {

//        System.out.println(getFives("他们"));
//        System.out.println(getFives("计算机"));
//        System.out.println(getFives("弄虚作假"));
//        System.out.println(getFives("中华人民共和国"));
//        System.out.println(Dist.getFirstPinYins("哈哈士大夫"));
        System.out.println(Dist.getFirstPinYins("哈哈abc士134大夫"));

    }
}