package org.ts.ddcs.Worker;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.ts.ddcs.DataItemTemplate.DataItemTemplateInterface;
import org.ts.ddcs.DataTemplate.DataTemplateLine;
import org.ts.ddcs.DataTemplate.DataTemplateManager;
import org.ts.ddcs.DataTemplate.TemplateLineNode;
import org.ts.ddcs.Entity.RtuBaseInfo;
import org.ts.ddcs.log.LogHelper;
import org.ts.ddcs.Tool.BytesHelp;
import org.ts.ddcs.utils.GBConstants;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Callable;

/**
 * 报文解析器
 *
 * @author dylan
 */
public class DataGramSw2014Process implements Callable<Integer> {

    /**
     * 报文数据，JSON字符串格式
     * 报文16进制字符串：datagram
     * 测站编码：rtuCode
     * 规约：agreement
     * 报文接收时间：datagramPickTime
     */
    private String jsonBody;

    DataGramSw2014Process(String jsonBody) {
        this.jsonBody = jsonBody;
    }

    @Override
    public Integer call() {
        try {
            String logId = LogHelper.createLogId("DataGramProcess");
            Date now = new Date();
            SimpleDateFormat timeFormat = new SimpleDateFormat("yyyyMMddHHmmss");
            SimpleDateFormat timeFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            LogHelper.info(logId + ":" + timeFormat2.format(now) + ":" + " Start Data Gram Process ");
            JSONObject body = JSONObject.parseObject(this.jsonBody);
            String rtuCode = body.getString(GBConstants.BASE_KEY_RTU);
            LogHelper.info(logId + ":" + "测站编码" + ":" + rtuCode);
            String datagram = body.getString(GBConstants.BASE_KEY_DATAGRAM);
            LogHelper.info(logId + ":" + "报文" + ":" + datagram);
            String pickTm = body.getString(GBConstants.BASE_KEY_DATAGRAM_PICK_TM);
            LogHelper.info(logId + ":" + "接收时间" + ":" + pickTm);
            String agreement = body.getString(GBConstants.BASE_KEY_AGREEMENT);
            LogHelper.info(logId + ":" + "规约" + ":" + agreement);
            //接收时间
            Date pickDt = timeFormat.parse(pickTm);
            //采集时间
            Date collectTime = new Date(now.getTime());
            RedisTemplate redisTemplate = DataProcessHolder.newInstance().dataProcess.redisTemplate;
            HashOperations<String, String, String> opsHash = redisTemplate.opsForHash();
            //报文转换到2进制字节数组
            byte[] datagramBuff = BytesHelp.hexStr2Bytes(datagram);
            //报文解析
            DataTemplateLine line = DataTemplateManager.newInstance().createTemplateLine();
            line.Stream(datagramBuff);
            TemplateLineNode macth = line.MacthTemplate();
            if (null != macth) {
                byte[] buff = macth.getDataTemplate().SendPacketTime();
                if (null != buff && buff.length > 0) {
                    String tm = BytesHelp.byte2HexStr(buff);
                    tm = pickTm.substring(0, 2) + tm;
                    collectTime = timeFormat.parse(tm);
                }
                //功能码
                String func = macth.getDataTemplate().GetFeture();
                /**自动创建测站**/
                RtuBaseInfo rtuInfo = new RtuBaseInfo();
                rtuInfo.setRtuCode(rtuCode);
                if (func.equals("30") || func.equals("31") || func.equals("32") || func.equals("33") || func.equals("34")) {
                    byte[] kindBuf = macth.getDataTemplate().SiteKind();
                    if (null != kindBuf && kindBuf.length > 0) {

                        if (kindBuf[0] == 0x50) {
                            //降水 "P"
                            rtuInfo.setRtuKind("ff808081762c3a7f01771de8b6bc0017");
                        } else if (kindBuf[0] == 0x48) {
                            //"H"河道
                            rtuInfo.setRtuKind("ff808081762c3a7f01771de9387a0018");
                        } else if (kindBuf[0] == 0x4B) {
                            //"K"水库(湖泊)
                            rtuInfo.setRtuKind("ff808081762c3a7f01771de9bdca0019");
                        } else if (kindBuf[0] == 0x5A) {
                            // "Z"闸坝
                            rtuInfo.setRtuKind("ff808081762c3a7f01771dea36a2001a");
                        } else if (kindBuf[0] == 0x44) {
                            // "D"泵站
                            rtuInfo.setRtuKind("ff808081762c3a7f01771dfd7fe4001b");
                        } else if (kindBuf[0] == 0x54) {
                            //"T"潮汐
                            rtuInfo.setRtuKind("ff808081762c3a7f01771dff607d001c");
                        } else if (kindBuf[0] == 0x4D) {
                            //"M"墒情
                            rtuInfo.setRtuKind("ff808081762c3a7f01771e008cf3001d");
                        } else if (kindBuf[0] == 0x47) {
                            //"G"地下水
                            rtuInfo.setRtuKind("ff808081762c3a7f01771e017a02001e");
                        } else if (kindBuf[0] == 0x51) {
                            // "Q"水质
                            rtuInfo.setRtuKind("ff808081762c3a7f01771e0219f5001f");
                        } else if (kindBuf[0] == 0x49) {
                            //"I"取水口
                            rtuInfo.setRtuKind("ff808081762c3a7f01771e032ec60020");
                        } else if (kindBuf[0] == 0x4F) {
                            //"O"排水口
                            rtuInfo.setRtuKind("ff808081762c3a7f01771e03963b0021");
                        } else {
                            rtuInfo.setRtuKind("ff808081762c3a7f01771e0408d20022");
                        }
                    }
                }

                rtuInfo.setRtuCode2(rtuCode);
                DataProcessHolder.newInstance().dataProcess.rtuService.saveOrUpdateRtu(rtuInfo);

                /**指令执行完成**/
                if (macth.getDataTemplate().ClearCommand()) {
                    DataProcess.CommandComplete(rtuCode, BytesHelp.byte2HexStr(macth.getDataTemplate().FuncCode()));
                }

                opsHash.put(rtuCode, "lastTime", timeFormat2.format(pickDt));
                opsHash.put(rtuCode, GBConstants.REDIS_KEY_RTU_SPACE_TIME, "0");


                /**数据入库处理*/
                if (DataProcess.config().isDataBaseSave()) {
//                    if (macth.getDataTemplate().GetFeture().equals("0200")) {
//                        Map<String, Object> p = new HashMap<>(2);
//                        LinkedList<DataItemTemplateInterface> items = macth.getDataTemplate().matchDataItem(null, null);
//                        if (items.size() > 0) {
//                            Map<String, Object> datas = items.get(0).GetDatas();
//
//                            p.put("lng", new BigDecimal((String) datas.get("lng")));
//                            p.put("lat", new BigDecimal((String) datas.get("lat")));
//
//
//                            macth.getDataSaveProcess().Save(macth.getDataTemplate(), p);
//                        }

                        DataProcessHolder.newInstance().dataProcess.SubmitDataSaveTask(macth);
//                    } else {
//                        if (null != macth.getDataSaveProcess()) {
//                            Map<String, Object> p = new HashMap<>(2);
//                            p.put("photoUrlPath", body.getString("photoUrlPath"));
//                            p.put("fileName", body.getString("fileName"));
//                            p.put("fileType", body.getString("fileType"));
//                            p.put("fileExt", body.getString("fileExt"));
//                            macth.getDataSaveProcess().Save(macth.getDataTemplate(), p);
//                        }
//                    }
                }

                /**
                 * 转发报文到管理后台系统
                 */
                if (DataProcess.config().isRelayToTaishan()) {
                    if (macth.getDataTemplate().GetFeture().equals("0200")) {
                        Map<String, DataItemTemplateInterface> dataItem = macth.getDataTemplate().DataItem();
                        DataItemTemplateInterface itemTemplateInterface = dataItem.get("location");
                        if (null != itemTemplateInterface){
                            Map<String,Object> location =itemTemplateInterface.GetDatas();
                            String lng = (String)location.get("lng");
                            String lat = (String)location.get("lat");
                            JSONObject msg = new JSONObject();
                            msg.put("msg_code","map_track_point_update");
                            JSONObject data = new JSONObject();
                            data.put("lng",lng);
                            data.put("lat",lat);
                            msg.put("data",data);
                            DataProcessHolder.newInstance().dataProcess.mqttServer.send(msg.toJSONString());
                        }
                    }else{
                        String dataInfo = macth.getDataTemplate().getDataInfo();
                        if (null != dataInfo) {
                            JSONObject dataInfoBody = JSONObject.parseObject(dataInfo);
                            DataProcessHolder.newInstance().dataProcess.SubmitRelayManageTask(rtuCode, dataInfoBody);
                        }
                    }
                }

                /**报文转发处理*/
                if (func.equals("30") || func.equals("31") || func.equals("32") || func.equals("33") || func.equals("34") || func.equals("C0")) {
                    if (opsHash.hasKey(rtuCode, GBConstants.RELAY_DATAGRAM_KEY)) {
                        String isRelay = opsHash.get(rtuCode, GBConstants.RELAY_DATAGRAM_KEY);
                        if (null != isRelay && isRelay.equals(GBConstants.RELAY_DATAGRAM_ACTIVE)) {
                            if (opsHash.hasKey(rtuCode, GBConstants.RELAY_DATAGRAM_REMOTE_IP_KEY)) {
                                String relayIp = opsHash.get(rtuCode, GBConstants.RELAY_DATAGRAM_REMOTE_IP_KEY);
                                if (null != relayIp && relayIp.length() > 0) {
                                    if (agreement.equals(GBConstants.AGREEMENT_KIND_SZY)) {
                                        if (rtuCode.equals("1522001A00") || rtuCode.equals("1522002700")) {
                                            DataProcessHolder.newInstance().dataProcess.SubmitXamSzy2012DataGramRelayTask(rtuCode, collectTime, pickDt, relayIp, datagram);
                                        } else if (rtuCode.equals("0020160011")) {
                                            DataProcessHolder.newInstance().dataProcess.SubmitDlSzy2012DataGramRelayTask(rtuCode, collectTime, pickDt, relayIp, datagram);
                                        } else {
                                            DataProcessHolder.newInstance().dataProcess.SubmitSzy2012DataGramRelayTask(rtuCode, collectTime, pickDt, relayIp, datagram);
                                        }
                                    } else if (agreement.equals(GBConstants.AGREEMENT_KIND_SW)) {
                                        if (rtuCode.equals("0020160011")) {
                                            DataProcessHolder.newInstance().dataProcess.SubmitDlSzy2012DataGramRelayTask(rtuCode, collectTime, pickDt, relayIp, datagram);
                                        } else {
                                            DataProcessHolder.newInstance().dataProcess.SubmitSw2014DataGramRelayTask(rtuCode, collectTime, pickDt, relayIp, datagram);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }


                /**计算主连接服务器优先度**/
                if (DataProcess.config().isConnectManage()) {
                    String serverId = body.getString(GBConstants.BASE_KEY_COLLECT_SERVER);
                    DataProcessHolder.newInstance().dataProcess.SubmitConnectManageTask(rtuCode, serverId, new Date());
                }

                /**把RTU自报状态数据写入到缓存中*/
                if (func.equals("F5")) {
                    opsHash.put(rtuCode, GBConstants.REDIS_KEY_RTU_STATUS_DATAGRAM, datagram);
                }

                /**检查RTU设备状态*/
                if (DataProcess.config().isRtuStatusCheck()) {
                    /**测试报，定时报，加报，小时报*/
                    if (func.equals("30") || func.equals("31") || func.equals("32") || func.equals("33") || func.equals("34") || func.equals("C0")) {
                        DataProcessHolder.newInstance().dataProcess.SubmitRtuStatusNotifyTask(pickDt,collectTime, macth, datagram);
                    }
                    if (func.equals("F5")) {
                        DataProcessHolder.newInstance().dataProcess.SubmitRtuStatusNotifyTask(pickDt,collectTime, macth, datagram);
                    }
                }

                /**通知指令下行
                 * 接收图片时不下发指令
                 **/
                if (!func.equals("36")) {
                    DataProcessHolder.newInstance().dataProcess.SubmitDownCommandNotifyTask(rtuCode);
                }

                /**
                 * 检查是否有数据异常
                 */
                if (func.equals("30") || func.equals("31") || func.equals("32") || func.equals("33") || func.equals("34") || func.equals("C0")) {
                    if (macth.getDataTemplate().NeedCheckOutlierData()) {
                        List<DataItemTemplateInterface> OutlierData = macth.getDataTemplate().OutlierData();
                        if (null != OutlierData && OutlierData.size() > 0) {
                            JSONObject warningInfoBody = new JSONObject();
                            warningInfoBody.put(GBConstants.BASE_KEY_WARNING_CHECK_TIME, timeFormat2.format(new Date()));
                            warningInfoBody.put(GBConstants.BASE_KEY_AGREEMENT, agreement);
                            warningInfoBody.put(GBConstants.BASE_KEY_RTU, rtuCode);
                            warningInfoBody.put(GBConstants.BASE_KEY_DATAGRAM, datagram);
                            warningInfoBody.put(GBConstants.BASE_KEY_WARNING_KIND, GBConstants.WARNING_TYPE_OUTLIER_DATA);
                            warningInfoBody.put(GBConstants.BASE_KEY_WARNING_INFO, "数据异常");
                            JSONObject warningContent = new JSONObject();
                            JSONArray outlierdataContent = new JSONArray();
                            for (DataItemTemplateInterface itemTemplateInterface : OutlierData) {
                                JSONObject errorData = new JSONObject();
                                byte[] valueBuff = itemTemplateInterface.GetByteArray();
                                String hexValue = BytesHelp.byte2HexStr(valueBuff);
                                errorData.put("value", hexValue);
                                errorData.put("desc", itemTemplateInterface.GetDesc());
                                errorData.put("afn", itemTemplateInterface.GetFeture());
                                outlierdataContent.add(errorData);
                            }
                            warningContent.put("data", outlierdataContent);
                            warningInfoBody.put(GBConstants.BASE_KEY_WARNING_CONTENT, warningContent.toJSONString());
                            warningInfoBody.put(GBConstants.BASE_KEY_WARNING_STATUS, GBConstants.WARNING_STATUS_HAPPEN);
                            String queue = DataProcessHolder.newInstance().dataProcess.queueConfig.getWarningMessage();
                             DataProcessHolder.newInstance().dataProcess.kafkaTemplate.send(queue, warningInfoBody.toJSONString());
                        } else {
                            //判断是否已预警
                            if (opsHash.hasKey(rtuCode, "warning_" + GBConstants.WARNING_TYPE_OUTLIER_DATA)) {
                                String warning = opsHash.get(rtuCode, "warning_" + GBConstants.WARNING_TYPE_OUTLIER_DATA);
                                if (null != warning && warning.equals(GBConstants.WARNING_STATUS_HAPPEN)) {
                                    JSONObject warningInfoBody = new JSONObject();
                                    warningInfoBody.put(GBConstants.BASE_KEY_WARNING_CHECK_TIME, timeFormat2.format(new Date()));
                                    warningInfoBody.put(GBConstants.BASE_KEY_AGREEMENT, agreement);
                                    warningInfoBody.put(GBConstants.BASE_KEY_RTU, rtuCode);
                                    warningInfoBody.put(GBConstants.BASE_KEY_DATAGRAM, datagram);
                                    warningInfoBody.put(GBConstants.BASE_KEY_WARNING_KIND, GBConstants.WARNING_TYPE_OUTLIER_DATA);
                                    warningInfoBody.put(GBConstants.BASE_KEY_WARNING_INFO, "数据异常错误已恢复");
                                    warningInfoBody.put(GBConstants.BASE_KEY_WARNING_STATUS, GBConstants.WARNING_STATUS_RECOVERY);
                                    String queue = DataProcessHolder.newInstance().dataProcess.queueConfig.getWarningMessage();
                                      DataProcessHolder.newInstance().dataProcess.kafkaTemplate.send(queue, warningInfoBody.toJSONString());
                                }
                            }
                        }
                    }
                }
                /**
                 * 检查是否有CRC校验错误
                 */
                if (opsHash.hasKey(rtuCode, "warning_" + GBConstants.WARNING_TYPE_CRC_ERROR)) {
                    String warning = opsHash.get(rtuCode, "warning_" + GBConstants.WARNING_TYPE_CRC_ERROR);
                    if (null != warning && warning.equals(GBConstants.WARNING_STATUS_HAPPEN)) {
                        JSONObject warningInfoBody = new JSONObject();
                        warningInfoBody.put(GBConstants.BASE_KEY_WARNING_CHECK_TIME, timeFormat2.format(new Date()));
                        warningInfoBody.put(GBConstants.BASE_KEY_AGREEMENT, agreement);
                        warningInfoBody.put(GBConstants.BASE_KEY_RTU, rtuCode);
                        warningInfoBody.put(GBConstants.BASE_KEY_DATAGRAM, datagram);
                        warningInfoBody.put(GBConstants.BASE_KEY_WARNING_KIND, GBConstants.WARNING_TYPE_CRC_ERROR);
                        warningInfoBody.put(GBConstants.BASE_KEY_WARNING_INFO, "CRC校验错误已恢复");
                        warningInfoBody.put(GBConstants.BASE_KEY_WARNING_STATUS, GBConstants.WARNING_STATUS_RECOVERY);
                        String queue = DataProcessHolder.newInstance().dataProcess.queueConfig.getWarningMessage();
                          DataProcessHolder.newInstance().dataProcess.kafkaTemplate.send(queue, warningInfoBody.toJSONString());
                    }
                }

                /**
                 * 发送报文到后台运维日志分析
                 */
                if (DataProcessHolder.newInstance().dataProcess.config.isRelayToLog()) {
                    JSONObject jsonLog = new JSONObject();
                    jsonLog.put("logTime", timeFormat2.format(pickDt));
                    jsonLog.put("datagram", datagram);
                    jsonLog.put("agreement", agreement);
                    jsonLog.put("rtu", rtuCode);
                    String mq_log = DataProcessHolder.newInstance().dataProcess.queueConfig.getLogMessage();
                    LogHelper.info("send to log **** "+jsonLog.toJSONString());
                    DataProcessHolder.newInstance().dataProcess.kafkaTemplate.send(mq_log, jsonLog.toJSONString());
                }
            }

        } catch (Exception e) {
            LogHelper.error(e);
        }
        return 0;
    }
}
