package digital.laboratory.platform.inspection.utils;

import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

/**
 * @author xy
 * @version 1.0
 * @title TextEncodeUtil  文本文件编码工具类
 * @description
 * @create 2024/1/8 16:20
 */

public class TextEncodeUtil {

    /**
     * 检查文件的字符集
     *
     * @param inputStream
     * @return
     * UTF-8 表示是 UTF-8 格式
     * UTF-16 表示是 UTF-16 格式
     * GBK 表示是 GBK 格式
     */
    public static String checkFileCharset(MultipartFile file) throws IOException {
        byte[] bytes = new byte[256];
        InputStream inputStream=file.getInputStream();
        int n = inputStream.read(bytes);
        inputStream.close();
        if (n<=2) {
            return "GBK";
        }
        if (bytes[0]==-17 && bytes[1]==-69 && bytes[2]==-65) {
            return "UTF-8";
        }

        ENCODE_TYPE encodeType =detectEncodeType(bytes);
        if (encodeType ==ENCODE_TYPE.UTF8)
            return "UTF-8";
        else

            return "GBK";
    }
    public static String formatStream(MultipartFile file, String charset) throws IOException {

        InputStream inputStream=file.getInputStream();
        Reader reader = new InputStreamReader(inputStream, charset);
        StringBuilder sbText = new StringBuilder();
        char[] buffer = new char[1024];
        int n;
        while ((n = reader.read(buffer)) != -1) {
            sbText.append(buffer, 0, n);
        }
        inputStream.close();
        return sbText.toString();
    }
    public enum ENCODE_TYPE {
        UNKNOW,
        ANSI,
        UTF8,
        UTF16_big_endian,
        UTF16_little_endian
    }
    public static ENCODE_TYPE detectEncodeType(byte[] inputBuffer /*, int bufLen*/) {
        ENCODE_TYPE filetype = ENCODE_TYPE.ANSI;

        if (Byte.toUnsignedInt(inputBuffer[0]) == 0xFF
                && Byte.toUnsignedInt(inputBuffer[1]) == 0xFE) //fffe,小头,windows默认
            filetype = ENCODE_TYPE.UTF16_little_endian;
        else if (Byte.toUnsignedInt(inputBuffer[0]) == 0xFE
                && Byte.toUnsignedInt(inputBuffer[1]) == 0xFF)
            filetype = ENCODE_TYPE.UTF16_big_endian;
        else {
            if (validUtf8(inputBuffer)) {
                filetype = ENCODE_TYPE.UTF8;
            }
        }
        return filetype;
    }
    static final int MASK1 = 1 << 7;
    static final int MASK2 = (1 << 7) + (1 << 6);

    public static boolean validUtf8(byte[] data) {
        int m = data.length;
        int index = 0;
        while (index < m) {
            int num = Byte.toUnsignedInt(data[index]);
            int n = getBytes(num);
            if (n < 0 || index + n > m) {
                return false;
            }
            for (int i = 1; i < n; i++) {
                if (!isValid(Byte.toUnsignedInt(data[index + i]))) {
                    return false;
                }
            }
            index += n;
        }
        return true;
    }

    public static boolean validUtf8(int[] data) {
        int m = data.length;
        int index = 0;
        while (index < m) {
            int num = data[index];
            int n = getBytes(num);
            if (n < 0 || index + n > m) {
                return false;
            }
            for (int i = 1; i < n; i++) {
                if (!isValid(data[index + i])) {
                    return false;
                }
            }
            index += n;
        }
        return true;
    }

    public static int getBytes(int num) {
        if ((num & MASK1) == 0) {
            return 1;
        }
        int n = 0;
        int mask = MASK1;
        while ((num & mask) != 0) {
            n++;
            if (n > 4) {
                return -1;
            }
            mask >>= 1;
        }
        return n >= 2 ? n : -1;
    }

    public static boolean isValid(int num) {
        return (num & MASK2) == MASK1;
    }
}
