package com.yeechart.dotMatrix.font;


import com.yeechart.dotMatrix.font.bean.FontObject;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 自定义字体库 XZP
 */


@Component
public class XZPFontLoaderUtil {


    private List<FontObject> fontObjects = new ArrayList<>();
    private Map<String, List<FontObject>> fontMap = new HashMap<>();


    @PostConstruct
    public void init() {
        String filePath = "fonts/font_2024_03_15.DAT";

        // 获取资源文件的输入流
        InputStream inputStream = XZPFontLoaderUtil.class.getClassLoader().getResourceAsStream(filePath);

        if (inputStream == null) {
            throw new RuntimeException("文件未找到！");
        }

        try {
            fontObjects = parseFontFile(inputStream);
            fontMap = fontlistToMap(fontObjects);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 得到 字符串 指定的编码集 编号
     *
     * @param text
     * @return
     */
    public  String getEncoding(String text, String charsetName) {
        String encoding = "";
        try {
            byte[] bytes = String.valueOf(text).getBytes(charsetName);
            StringBuilder hex = new StringBuilder();
            if (bytes != null && bytes.length > 0) {
                // 将字节转换为16进制字符串
                for (byte b : bytes) {
                    hex.append(String.format("%02x", b));
                }
//                 System.out.println(text+"  GB2312编码: " + hex.toString());
            }

            encoding = hex.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return encoding;
    }

    /**
     * 判断字符串是否仅由英文字母构成
     *
     * @param str
     * @return
     */
    public  boolean isAllLetters(String str) {
        return str.matches("^[a-zA-Z]+$");
    }

    /**
     * 判断字符串是否仅由数字组成
     *
     * @param str
     * @return
     */
    public  boolean isAllDigits(String str) {
        return str.matches("^[0-9]+$");
    }

    /**
     * 判断字符串是否仅由英文字母和数字组成
     *
     * @param str
     * @return
     */
    public  boolean isAlphanumeric(String str) {
        return str.matches("^[a-zA-Z0-9]+$");
    }

    /**
     * 将 字库点阵列表 转换为 map
     *
     * @param fontObjectList
     * @return
     */
    private Map<String, List<FontObject>> fontlistToMap(List<FontObject> fontObjectList) {
        Map<String, List<FontObject>> fontMap = new HashMap<>();
        for (FontObject fontObject : fontObjectList) {
            List<FontObject> fontObjects1;
            if (fontMap.containsKey(fontObject.getEncoding())) {
                fontObjects1 = fontMap.get(fontObject.getEncoding());
                fontObjects1.add(fontObject);
            } else {
                fontObjects1 = new ArrayList<>();
                fontObjects1.add(fontObject);
            }
            fontMap.put(fontObject.getEncoding(), fontObjects1);
        }

        return fontMap;
    }

    private List<FontObject> parseFontFile(InputStream inputStream) {
        List<FontObject> fontObjects = new ArrayList<>();

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
            String line;
            FontObject fontObject = null;

            Pattern pattern = null;
            Matcher matcher = null;

            //一行行读取
            while ((line = reader.readLine()) != null) {

                //这是第一行
                if (line.contains("[Paint_DrawChar] font lib start") || line.contains("[Paint_DrawChar_CN] font lib start")) {

                    fontObject = new FontObject();
                    fontObjects.add(fontObject);

                    //将字符串去掉头
                    line = line.replace("[Paint_DrawChar] font lib start", "");
                    line = line.replace("[Paint_DrawChar_CN] font lib start", "");

                    //按照逗号隔开
//                    String[] lineArray = line.split(",");


                    // 解析fontEncoding和encoding
                    pattern = Pattern.compile("\\[(\\S+) = (0x[\\da-fA-F]+(?:\\s+0x[\\da-fA-F]+)*)\\]");
                    matcher = pattern.matcher(line);

                    if (matcher.find()) {
                        // 解析fontEncoding
                        fontObject.setFontEncoding(matcher.group(1));
                        // 解析encoding
                        fontObject.setEncoding(matcher.group(2).replace("0x", "").replace(" ", ""));

                    }

                    // 解析type
                    pattern = Pattern.compile("\\[type\\s=\\s(.*?)\\]");
                    matcher = pattern.matcher(line);
                    if (matcher.find()) {
                        fontObject.setType(matcher.group(1));
                    }

                    // 解析fontWidth和fontHeight
                    pattern = Pattern.compile("width=\\s(.*?)\\s,\\sheight=\\s(.*?)\\s");
                    matcher = pattern.matcher(line);
                    if (matcher.find()) {
                        fontObject.setFontWidth(Integer.parseInt(matcher.group(1)));
                        fontObject.setFontHeight(Integer.parseInt(matcher.group(2)));
                    }

                } else if (line.contains("font lib end!!")) {
                    fontObject = null;

                } else if (fontObject != null) {
                    // 解析hexArrays
                    pattern = Pattern.compile("(0x[\\da-fA-F]+)\\s");
                    matcher = pattern.matcher(line);

                    while (matcher.find()) {
                        fontObject.addHexArray(matcher.group(1));
                    }

                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return fontObjects;
    }

    /**
     * 转换为完整的一维的二进制
     *
     * @param hexStrings
     * @return
     */
    private int[] convertToBinaryArray(List<String> hexStrings) {
        int numRows = hexStrings.size();
        int[] binaryArray = new int[numRows * 8];

        for (int i = 0; i < numRows; i++) {

            String hexString = hexStrings.get(i);
            int decimalValue = Integer.parseInt(hexString.substring(2), 16);
            String binaryString = String.format("%8s", Integer.toBinaryString(decimalValue)).replace(' ', '0');

            for (int j = 0; j < 8; j++) {

                binaryArray[i * 8 + j] = Integer.parseInt(String.valueOf(binaryString.charAt(j)));
            }
        }
        return binaryArray;
    }

    /**
     * 转换为指定像素的二进制
     *
     * @param hexStrings
     * @param fontWidth
     * @param fontHeight
     * @return
     */
    private int[][] convertToBinaryArray(List<String> hexStrings, int fontWidth, int fontHeight) {

        int[] binaryArray1 = convertToBinaryArray(hexStrings);

        //System.out.println("该字体的完整的2进制点阵: "+ Arrays.toString(binaryArray1));

        int[][] binaryArray = new int[fontHeight][fontWidth];

        //获取每行的点数
        int pooints = fontWidth / 8;
        if (fontWidth % 8 > 0) {
            pooints = pooints + 1;
        }

        //先转换为完整二进制
        for (int i = 0; i < fontHeight; i++) {
            for (int j = 0; j < fontWidth; j++) {
                binaryArray[i][j] = binaryArray1[i * pooints * 8 + j];
            }

        }
        return binaryArray;
    }

    /**
     * 获取单个字体的点阵数组
     *
     * @param encoding 文本编码
     * @param font     文本的字体大小
     * @return
     */
    public int[][] getSingleFontBinaryArray(String encoding, int font) {

        try {

            List<FontObject> myFontList = new ArrayList<>();

            List<FontObject> myFontList2 = new ArrayList<>();

            List<FontObject> myFontList3 = new ArrayList<>();
            if (fontMap.containsKey(encoding)) {
                myFontList3.addAll(fontMap.get(encoding));
            }

            if (encoding.length() <= 2) {
                if (fontMap.containsKey("00" + encoding)) {
                    myFontList3.addAll(fontMap.get("00" + encoding));
                }
            }

            //过滤掉无效的字库 即内容为空的
            if (!"20".equals(encoding)) {
                myFontList2 = myFontList3.stream().filter(
                        value -> !value.getHexArrays().stream().allMatch(s -> s.equals("0x00"))
                ).collect(Collectors.toList());
            } else {
                myFontList2 = myFontList3;
            }

            myFontList = myFontList2;

            if (myFontList.isEmpty()) {
                System.out.println("没有找到对应的字库编码 : " + encoding);
                return null;
            }

            //获取第一个
            FontObject fontObject = null;
            FontObject miniFontObject = myFontList.get(0);//最小字体
            FontObject multipleFontObject = null;//适合的倍数字体

            for (FontObject fontObject1 : myFontList) {


                if (fontObject1.getFontWidth() == font) {
                    fontObject = fontObject1;
                    break;

                }

                if (fontObject1.getFontWidth() < miniFontObject.getFontWidth()) {
                    miniFontObject = fontObject1;
                }

                if (font % fontObject1.getFontWidth() == 0) {
                    //使用最大的放大
                    if (multipleFontObject == null || multipleFontObject.getFontHeight() <= fontObject1.getFontWidth()) {
                        multipleFontObject = fontObject1;
                    }

                }

            }

            if (fontObject == null) {
                if (multipleFontObject != null) {
                    fontObject = multipleFontObject;
                } else {
                    fontObject = miniFontObject;
                }
            }

            List<String> hexArrays = fontObject.getHexArrays();


            return convertToBinaryArray(hexArrays, fontObject.getFontWidth(), fontObject.getFontHeight());

        } catch (Exception e) {
            e.printStackTrace();

        }

        return null;

    }


}

