/**
 * Copyright 2019 DH
 * All right reserved.
 * 项目名称: 大恒泰山系统
 * 创建日期:2022/1/5
 */
package org.ts.ddcs.process;


import com.alibaba.fastjson.JSONObject;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.ts.ddcs.controller.simulator.entity.SimulatorInfo;
import org.ts.ddcs.log.LogHelper;
import org.ts.ddcs.tool.BytesHelp;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Callable;

/***
 * Date:2022/1/5
 * Title:文件所属模块（必须填写）
 * Description：对本文件的详细描述，原则上不能少于30字
 * @author dylan
 * @mender：（文件的修改者，文件创建者之外的人）
 * @version 1.0
 * Remark：认为有必要的其他信息
 */
@SuppressWarnings("all")
public class SimulatorWorker implements Callable<Integer> {

    private String getLastDatagram(String rtuCode) {
        try {
            SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            RedisTemplate redisTemplate = DataProcessHolder.newInstance().dataProcess.redisTemplate;
            ListOperations<String, String> opsList = redisTemplate.opsForList();
            HashOperations<String, String, String> opsHash = redisTemplate.opsForHash();
            Calendar calendar = Calendar.getInstance();

            String hourKey = rtuCode + ":List:Hour";
            long size = opsList.size(hourKey);
            List<String> hourlist = opsList.range(hourKey, 0, size);

            for (int i = hourlist.size() - 1; i >= 0; i--) {
                Date dt = timeFormat.parse(hourlist.get(i));
                calendar.setTime(dt);
                String year = String.format("%d", calendar.get(Calendar.YEAR));
                String month = String.format("%02d", calendar.get(Calendar.MONTH) + 1);
                String day = String.format("%02d", calendar.get(Calendar.DAY_OF_MONTH));
                String hour = String.format("%02d", calendar.get(Calendar.HOUR_OF_DAY));
                //  String mintue = String.format("%02d", calendar.get(Calendar.MINUTE));
                String minuteKey = rtuCode + ":List:Minute:" + year + month + day + hour;
                if (redisTemplate.hasKey(minuteKey)) {
                    size = opsList.size(minuteKey);
                    List<String> minutelist = opsList.range(minuteKey, 0, size);
                    for (int j = minutelist.size() - 1; j >= 0; j--) {
                        String d = minutelist.get(j);
                        if (null != d) {
                            String[] att = d.split("=");
                            if (att.length == 2) {
                                String jsonStr = att[1];
                                JSONObject json = JSONObject.parseObject(jsonStr);
                                String datagram = json.getString("datagram");
                                if (datagram.length() > "7E7E010533525415000032".length()) {
                                    String func = datagram.substring("7E7E0105335254150000".length(), "7E7E010533525415000032".length());
                                    if (func.equals("32")) {
                                        return datagram;
                                    }
                                }
                            }
                        }
                    }
                }
            }


//            Set<String> keysSet = opsHash.keys(rtuCode + ":datagram");
//            List<String> keysList = new LinkedList<>();
//            for (String key : keysSet) {
//                keysList.add(key);
//            }
//            keysList.sort(new Comparator<String>() {
//                @Override
//                public int compare(String o1, String o2) {
//                    long o1v = Long.parseLong(o1);
//                    long o2v = Long.parseLong(o2);
//                    if (o1v > o2v) {
//                        return -1;
//                    } else if (o1v < o2v) {
//                        return 1;
//                    }
//                    return 0;
//                }
//            });
//            for (String key : keysList) {
//                String datagram = opsHash.get(rtuCode + ":datagram", key);
//                if (datagram.length() > "7E7E010533525415000032".length()) {
//                    String func = datagram.substring("7E7E0105335254150000".length(), "7E7E010533525415000032".length());
//                    if (func.equals("32")) {
//                        return datagram;
//                    }
//                }
//            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private boolean needSendStatus(String id, String sendDatagramTime) {
        try {
            SimpleDateFormat timeFormat = new SimpleDateFormat("yyyyMMddHHmmss");
            Date sendDatagramDt = timeFormat.parse(sendDatagramTime);
            List<SimulatorInfo> list = DataProcessHolder.newInstance().dataProcess.rtuSimulatorService.querySendDatagramDetail(id, sendDatagramDt);
            if (null != list && list.size() > 0) {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    private void sendData(String sendDatagramTime, String id, String datagram, String ip, String port) {
        try {
            SimpleDateFormat timeFormat = new SimpleDateFormat("yyyyMMddHHmmss");
            LogHelper.info("send datagram:" + datagram);
            Socket socket = new Socket(ip, Integer.parseInt(port));
            // 建立连接后获得输出流
            OutputStream outputStream = socket.getOutputStream();
            InputStream input = socket.getInputStream();
            byte[] buff = BytesHelp.hexStr2Bytes(datagram);
            outputStream.write(buff);
            outputStream.flush();
            Date sendDatagramDt = timeFormat.parse(sendDatagramTime);
            int timeout = 0;
            byte[] tmpbuff = new byte[2048];
            byte[] bytes = new byte[1];
            int step = 0;
            int count = 0;
            int packlen = 0;
            while (true) {
                int read = input.available();
                if (read <= 0) {
                    if (timeout > 1000) {
                        break;
                    }
                    Thread.sleep(100);
                    timeout += 100;
                } else {
                    int len = input.read(bytes, 0, 1);
                    if (len != -1) {
                        System.arraycopy(bytes, 0, tmpbuff, count, len);
                        count += len;
                        if (step == 0) {
                            if (count == 13) {
                                byte[] dataAreaLen = new byte[2];
                                dataAreaLen[0] = tmpbuff[11];
                                dataAreaLen[1] = tmpbuff[12];
                                String dflag = BytesHelp.byte2HexStr(dataAreaLen);
                                dflag = "0" + dflag.substring(1, dflag.length());
                                byte[] lenbuff = BytesHelp.hexStr2Bytes(dflag);
                                // 报文长度(int)
                                int contensize = BytesHelp.bytes2Int(lenbuff, 0, 2);
                                packlen = 11 + contensize + 6;
                                step = 1;
                            }
                        } else {
                            if (count == packlen) {
                                break;
                            }
                        }
                    } else {
                        break;
                    }
                }
            }
            Date backDatagramDt = null;
            String backDatagram = null;
            if (count > 0) {
                byte[] responseBuff = new byte[count];
                System.arraycopy(tmpbuff, 0, responseBuff, 0, count);
                byte[] packetCrc16 = new byte[2];
                packetCrc16[0] = responseBuff[responseBuff.length - 2];
                packetCrc16[1] = responseBuff[responseBuff.length - 1];
                LogHelper.info("************* rtu get response " + BytesHelp.byte2HexStr(responseBuff));
                byte[] crc16 = BytesHelp.crcFun2014(responseBuff, 0, responseBuff.length - 2);
                if (!BytesHelp.byte2HexStr(packetCrc16).equals(BytesHelp.byte2HexStr(crc16))) {
                    LogHelper.info("校验码错误：报文中 CRC=" + BytesHelp.byte2HexStr(packetCrc16) + " 计算的 CRC=" + BytesHelp.byte2HexStr(crc16));
                } else {
                    LogHelper.info("报文校验成功");
                    backDatagramDt = new Date();
                    backDatagram = BytesHelp.byte2HexStr(responseBuff);
                }
            }
            DataProcessHolder.newInstance().dataProcess.rtuSimulatorService.savePostDatagramInfo(id, sendDatagramDt, datagram, backDatagramDt, backDatagram);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            LogHelper.info("end****************");
        }
    }

    private void postDatagram(Date tm, SimulatorInfo simulatorInfo) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(tm);
        String predatagram = getLastDatagram(simulatorInfo.getRtuCode());
        if (null != predatagram) {
            String datagram = predatagram.substring(0, "7E7E010533525415000032002B020C31".length());
            String year = String.format("%d", calendar.get(Calendar.YEAR));
            String month = String.format("%02d", calendar.get(Calendar.MONTH) + 1);
            String day = String.format("%02d", calendar.get(Calendar.DAY_OF_MONTH));
            String hour = String.format("%02d", calendar.get(Calendar.HOUR_OF_DAY));
            datagram += year.substring(2, 4) + month + day + hour + "0000";
            predatagram = predatagram.substring("7E7E010533525415000032002B020C31220105160022".length());
            if (predatagram.indexOf("F0F0") >= 0) {
                datagram += predatagram.substring(0, predatagram.indexOf("F0F0"));
                predatagram = predatagram.substring(predatagram.indexOf("F0F0"));
                datagram += "F0F0";
                datagram += year.substring(2, 4) + month + day + hour + "00";
                if (predatagram.length() - "F0F02201051600".length()-4>0) {
                    datagram += predatagram.substring("F0F02201051600".length(), predatagram.length() - 4);
                }
            } else {
                datagram += predatagram.substring(0, predatagram.length() - 4);
            }

            byte[] crc16 = BytesHelp.crcFun2014(BytesHelp.hexStr2Bytes(datagram));
            datagram += BytesHelp.byte2HexStr(crc16);

            String sendDatagramTime = year + month + day + hour + "0000";
            if (needSendStatus(simulatorInfo.getId(), sendDatagramTime)) {
                sendData(sendDatagramTime, simulatorInfo.getId(), datagram, simulatorInfo.getRemoteIp(), simulatorInfo.getRemotePort());
            }
        }
    }

    private boolean findDatagram(Date tm, SimulatorInfo simulatorInfo) {
        try {
            String predatagram = getLastDatagram(simulatorInfo.getRtuCode());
            if (null != predatagram) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(tm);
                String year = String.format("%d", calendar.get(Calendar.YEAR));
                String month = String.format("%02d", calendar.get(Calendar.MONTH) + 1);
                String day = String.format("%02d", calendar.get(Calendar.DAY_OF_MONTH));
                String hour = String.format("%02d", calendar.get(Calendar.HOUR_OF_DAY));
                String sendTm = year.substring(0, 2) + predatagram.substring("7E7E010533525415000032002B020C31".length(), "7E7E010533525415000032002B020C31".length() + 12);
                SimpleDateFormat timeFormat = new SimpleDateFormat("yyyyMMddHHmmss");
                calendar.setTime(timeFormat.parse(sendTm));
                String year2 = String.format("%d", calendar.get(Calendar.YEAR));
                String month2 = String.format("%02d", calendar.get(Calendar.MONTH) + 1);
                String day2 = String.format("%02d", calendar.get(Calendar.DAY_OF_MONTH));
                String hour2 = String.format("%02d", calendar.get(Calendar.HOUR_OF_DAY));
                if (year.equals(year2) && month.equals(month2) && day.equals(day2) && hour.equals(hour2)) {
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public Integer call() throws Exception {
        try {
            Date now = new Date();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(now);
            SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            List<SimulatorInfo> list = DataProcessHolder.newInstance().dataProcess.rtuSimulatorService.simulatorList();
            if (null != list && list.size() > 0) {
                for (SimulatorInfo info : list) {
                    String startTime = info.getStartTime();
                    if (null != startTime) {
                        Date st = timeFormat.parse(startTime);
                        if (st.before(now)) {
                            //判断任务是否开始
                            String endTime = info.getEndTime();
                            if (null != endTime) {
                                Date et = timeFormat.parse(endTime);
                                if (et.before(now)) {
                                    //结束时间已过，停止任务
                                    DataProcessHolder.newInstance().dataProcess.rtuSimulatorService.updateSimulatorStatus(info.getId(), "2");
                                } else {
                                    //判断补发延时时间
                                    String delayTime = info.getDelayTime();
                                    if (null != delayTime) {
                                        int delayValue = Integer.parseInt(delayTime);
                                        int minute = calendar.get(Calendar.MINUTE);
                                        if (minute >= delayValue) {
                                            //判断当前时间是否收到定时报
                                            if (!findDatagram(now, info)) {
                                                postDatagram(now, info);
                                            }
                                        }
                                    }
                                }
                            } else {
                                //判断补发延时时间
                                String delayTime = info.getDelayTime();
                                if (null != delayTime) {
                                    int delayValue = Integer.parseInt(delayTime);
                                    int minute = calendar.get(Calendar.MINUTE);
                                    if (minute >= delayValue) {
                                        //判断当前时间是否收到定时报
                                        if (!findDatagram(now, info)) {
                                            postDatagram(now, info);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            LogHelper.error(e);
        }
        return 0;
    }
}
