package com.mvc.service;

import com.mvc.JniCode;
import com.mvc.entity.TPackLog;
import com.mvc.model.TAicnnModel;
import com.mvc.netty.dealconstant.ResourceTag;
import com.mvc.utils.DateUtil;
import com.mvc.utils.FileUtil;
import com.mvc.utils.NumberUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;

/**
 * 报文日志管理
 */
@Component
public class PackLogMana {

    private static Environment env;

    @Resource
    public void setEnv(Environment env) {
        PackLogMana.env = env;
    }

    private static String runLogDirName = "runLog/";   //MCU运行日志存放的目录
    private static String packLogDirName = "packLog/"; //报文日志存放的目录
    private static String cnnDataDirName = "cnnData/"; //CNN网络输出数据
    private static int[] cnnBitLenArray = {7, 7, 9, 8, 9, 8};//CNN精简后每列占用的bit

    /**
     * 存储运行日志(MCU上传的报文,需要解压)
     *
     * @param logger
     * @param stationCode
     * @return
     * @throws IOException
     */
    public static String saveRunLog(StringBuffer logger, String stationCode, Date sampleTime, String logFrom) throws IOException {
        byte[] encodedData = NumberUtil.hexStringToBytes(logger.toString());
        byte[] decodedData = decodeMessage(encodedData);
        String path = env.getProperty(ResourceTag.PackLogPathTag.getTag()) + runLogDirName + stationCode + "/";
        sampleTime = sampleTime == null ? new Date() : sampleTime;
        Integer flag = StringUtils.isNotEmpty(logFrom) ? Integer.parseInt(logFrom) : 9;//9代表报文中未获取到有效数据来源标记
        //String fileName = flag + DateUtil.formateDate(sampleTime, "yyyyMMddHHmmss") + ".txt";
        //改为系统时间命名,采样时间可能有多个日志 2024-06-19 guozhao
        String fileName = flag + DateUtil.formateDate(new Date(), "yyyyMMddHHmmss") + ".txt";
        File saveDir = new File(path);
        if (!saveDir.isDirectory() || !saveDir.exists()) {
            saveDir.mkdirs();
        }
        FileUtil.writeBytesFile(path, fileName, decodedData);
        encodedData = null;
        decodedData = null;
        return fileName;
    }

    /**
     * 保存运行日志(APP保存时使用,非HexString)
     *
     * @param msg
     * @param stationCode
     * @return
     * @throws IOException
     */
    public static String saveRunLogByRawMsg(String msg, String stationCode) {
        try {
            byte[] date = msg.getBytes(StandardCharsets.UTF_8);
            String path = env.getProperty(ResourceTag.PackLogPathTag.getTag()) + runLogDirName + stationCode + "/";
            String fileName = "0" + DateUtil.formateDate(new Date(), "yyyyMMddHHmmss") + ".txt";//0开头代表APP
            File saveDir = new File(path);
            if (!saveDir.isDirectory() || !saveDir.exists()) {
                saveDir.mkdirs();
            }
            FileUtil.writeBytesFile(path, fileName, date);
            return fileName;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 保存报文日志文件
     *
     * @param logs
     * @return
     * @throws IOException
     */
    public static String savePackLog(List<TPackLog> logs) {
        if (logs == null || logs.size() == 0) return null;
        try {
            String stationCode = logs.get(0).getStationCode();
            String path = env.getProperty(ResourceTag.PackLogPathTag.getTag()) + packLogDirName + stationCode + "/";
            String upDown = logs.get(0).getUpordown();
            Integer upFlag = 9;//解析出错时,可能不是数值
            if (StringUtils.isNumeric(upDown)) {
                upFlag = Integer.parseInt(upDown);
            }
            Date sampleTime = logs.get(0).getDatatime() == null ? new Date() : logs.get(0).getDatatime();
            String mill = DateUtil.getCurrentTime("SSS");//防止中图和小图重名
            String fileName = logs.get(0).getFunCode() + "_" + upFlag + "_" + mill + "_" + DateUtil.formateDate(sampleTime, "yyyyMMddHHmmss") + ".txt";
            File saveDir = new File(path);
            if (!saveDir.isDirectory() || !saveDir.exists()) {
                saveDir.mkdirs();
            }
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < logs.size(); i++) {
                String temp = i == 0 ? "" : "\r\n\r\n";//每包之前加空行
                temp += ("第[" + (i + 1) + "]包数据:\r\n");
                sb.append(NumberUtil.bytesToHexStr(temp.getBytes(StandardCharsets.UTF_8)));
                String msg = logs.get(i).getOriginmessage().toUpperCase().replaceAll("(.{2})", " $1").substring(1);//转大写,每两位插空格
                sb.append(NumberUtil.bytesToHexStr(msg.getBytes(StandardCharsets.UTF_8)));
            }
            byte[] data = NumberUtil.hexStringToBytes(sb.toString());
            FileUtil.writeBytesFile(path, fileName, data);
            data = null;
            return fileName;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解压数据
     *
     * @param encodedData
     * @return
     */
    private static byte[] decodeMessage(byte[] encodedData) {
        byte[] decodedData = new byte[1024 * 100];
        int decodedLen = JniCode.decondeData(encodedData, decodedData, encodedData.length);
        byte[] data = new byte[decodedLen];
        System.arraycopy(decodedData, 0, data, 0, decodedLen);
        decodedData = null;
        return data;
    }

    public static String getFileContent(String fileName, String stationCode, Integer fileType) throws IOException {
        String content = "";
        String type = fileType == 0 ? runLogDirName : packLogDirName;
        String path = env.getProperty(ResourceTag.PackLogPathTag.getTag()) + type + stationCode + "/" + fileName;
        File logFile = new File(path);
        if (logFile.isFile() && logFile.exists()) {
            byte[] buffer = FileUtil.readBytesFile(path);
            content = new String(buffer, "UTF-8");
        }

        return content;
    }

    /**
     * 保存CNN网络输出数据报文->文件
     *
     * @param model
     * @param logger
     * @return
     */
    public static String saveCnnDataByRawMsg(TAicnnModel model, StringBuffer logger) {
        try {
            byte[] encodedData = NumberUtil.hexStringToBytes(logger.toString());
            byte[] data = null;
            if (model.getIsCompress().equals("1")) {
                data = decodeMessage(encodedData);                  //又改成根据压缩前长度前4bit判断是否压缩
            } else {
                data = encodedData;
            }

            String path = env.getProperty(ResourceTag.PackLogPathTag.getTag()) + cnnDataDirName + model.getStationCode() + "/";
            Date sampleTime = model.getSampleTime() == null ? new Date() : model.getSampleTime();
            String fileName = DateUtil.formateDate(sampleTime, "yyyyMMddHHmmss") + ".cnn";
            File saveDir = new File(path);
            if (!saveDir.isDirectory() || !saveDir.exists()) {
                saveDir.mkdirs();
            }
            FileUtil.writeBytesFile(path, fileName, data);
            model.setZipBeforeLen(data.length);
            encodedData = null;
            data = null;
            return fileName;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回原始的一维Byte数组(字节序未调整)
     *
     * @param stationCode
     * @param fileName
     * @return
     */
    public static byte[] getCnnRawData(String stationCode, String fileName) {
        try {
            String path = env.getProperty(ResourceTag.PackLogPathTag.getTag()) + cnnDataDirName + stationCode + "/" + fileName;
            File logFile = new File(path);
            if (logFile.isFile() && logFile.exists()) {
                byte[] buffer = FileUtil.readBytesFile(path);
                return buffer;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取CNN原始数据(返回二维int数组,字节序调整)
     *
     * @param stationCode
     * @param fileName
     * @return 二维数组
     */
    public static int[][] getCnnRawData2(String stationCode, String fileName) {
        try {
            int colNum = 6;//二维数组的列数,暂时是固定值
            int bytNum = 2;//两个字节表示一个值
            String path = env.getProperty(ResourceTag.PackLogPathTag.getTag()) + cnnDataDirName + stationCode + "/" + fileName;
            File logFile = new File(path);
            if (!logFile.isFile() || !logFile.exists()) return null;

            byte[] buffer = FileUtil.readBytesFile(path);
            int[][] data = new int[buffer.length / bytNum / colNum][colNum];
            int x = 0;
            int y = 0;
            byte[] temp = new byte[bytNum];
            for (int i = 0; i < buffer.length; i += bytNum) {
                System.arraycopy(buffer, i, temp, 0, temp.length);
                data[x][y] = NumberUtil.bytes2ToIntLittleEndian(temp);
                y++;
                if (y == colNum) {
                    y = 0;
                    x++;
                }
            }
            return data;

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

    /**
     * 获取CNN原始数据(将精简后的数据还原)
     *
     * @param model
     * @return
     */
    public static int[][] getCnnRawData_Simple(TAicnnModel model) {
        try {
            int colNum = cnnBitLenArray.length;
            String path = env.getProperty(ResourceTag.PackLogPathTag.getTag()) + cnnDataDirName + model.getStationCode() + "/" + model.getFileName();
            File logFile = new File(path);
            if (!logFile.isFile() || !logFile.exists()) return null;

            byte[] buffer = FileUtil.readBytesFile(path);
            String msg = NumberUtil.byteToBinaryString(buffer);
            int[][] data = new int[model.getTargetsNum()][colNum];
            int x = 0;
            int y = 0;

            String temp = "";
            while (msg.length() > 0) {
                temp = msg.substring(0, cnnBitLenArray[y]);
                data[x][y] = NumberUtil.binaryToDecimal(temp);
//                System.out.print(data[x][y]);
//                System.out.print(",");
                msg = msg.substring(cnnBitLenArray[y]);
                y++;
                if (y == colNum) {
                    y = 0;
                    x++;
                    //System.out.println();
                }
            }
            return data;

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

    /**
     * 读取CNN内容(为服务侧识别预留)
     *
     * @param model
     * @return
     */
    public static byte[] getCnnRawData(TAicnnModel model) {
        return getCnnRawData(model.getStationCode(), model.getFileName());
    }
}
