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

import lombok.extern.slf4j.Slf4j;
import org.ts.ddcs.common.enums.AgreementEnum;
import org.ts.ddcs.common.util.BytesUtil;
import org.ts.ddcs.constant.BusinessConstant;
import org.ts.ddcs.dataStream.sink.DataStreamSink;
import org.ts.ddcs.datatemplate.Template;
import org.ts.ddcs.datatemplate.TestState;
import org.ts.ddcs.itemdatatemplate.DataItemTemplate;
import org.ts.ddcs.itemdatatemplate.ItemTemplate;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;


/***
 * Date:2022/3/25
 * Title:数据流处理链
 * Description：数据链处理管理器
 * @author dylan
 * @version 1.0
 * Remark：认为有必要的其他信息
 */
@Slf4j
public class DataStreamLineManager {

    private boolean isLock = false;
    /**
     * 数据处理器
     */
    private Map<String, List<DataStreamProcessor>> processors = new HashMap<>();
    /**
     * 数据元素解析器
     */
    private Map<String, Map<String, DataItemTemplate>> itemTemplates = new HashMap<>();
    /**
     * 输出处理器
     */
    private Map<String, List<DataStreamSink>> sinks = new HashMap<>();
    /**
     * 缓存器
     */
    private DataStreamCache dataStreamCache = new DataStreamCache();

    public void lock(boolean lock) {
        this.isLock = lock;
    }

    public boolean lock() {
        return this.isLock;
    }

    public void addProcessor(String agreement, Template template) throws NullPointerException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        if (null == agreement || null == template) {
            throw new NullPointerException("参数不能为空");
        }
        if (null == template.getStreamProcessorClass()) {
            throw new NullPointerException("处理器类不能为空");
        }
        Class className = Class.forName(template.getStreamProcessorClass());
        Object instance = className.newInstance();
        if (instance instanceof DataStreamProcessor) {
            DataStreamProcessor dataStreamProcessor = (DataStreamProcessor) instance;
            dataStreamProcessor.setProcessorName(template.getProcessorName());
            dataStreamProcessor.setTemplateName(template.getTemplateName());
            if (this.processors.containsKey(agreement)) {
                List<DataStreamProcessor> processorList = this.processors.get(agreement);
                if (processorList.size() > 0) {
                    dataStreamProcessor.setPreProcessor(processorList.get(processorList.size() - 1));
                    processorList.get(processorList.size() - 1).setNextProcessor(dataStreamProcessor);
                }
                processorList.add(dataStreamProcessor);
                dataStreamProcessor.init(this);
            } else {
                List<DataStreamProcessor> processorList = new LinkedList<>();
                processorList.add(dataStreamProcessor);
                dataStreamProcessor.init(this);
                this.processors.put(agreement, processorList);
            }
        } else {
            throw new ClassNotFoundException();
        }
    }

    public void addItemTemplates(String agreement, ItemTemplate itemTemplate) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        if (null == agreement || null == itemTemplate) {
            throw new NullPointerException("参数不能为空");
        }
        if (null == itemTemplate.getItemTemplateClass()) {
            throw new NullPointerException("处理器类不能为空");
        }
        Class className = Class.forName(itemTemplate.getItemTemplateClass());
        Object instance = className.newInstance();
        if (instance instanceof DataItemTemplate) {
            DataItemTemplate dataItemTemplate = (DataItemTemplate) instance;
            dataItemTemplate.setFeture(itemTemplate.getFunc());
            dataItemTemplate.setName(itemTemplate.getFuncName());
            dataItemTemplate.setUnit(itemTemplate.getUnit());
            dataItemTemplate.setDesc(itemTemplate.getDesc());
            if (this.itemTemplates.containsKey(agreement)) {
                Map<String, DataItemTemplate> map = this.itemTemplates.get(agreement);
                map.put(itemTemplate.getFunc(), dataItemTemplate);
            } else {
                Map<String, DataItemTemplate> map = new HashMap<>();
                map.put(itemTemplate.getFunc(), dataItemTemplate);
                this.itemTemplates.put(agreement, map);
            }
        } else {
            throw new ClassNotFoundException();
        }
    }

    public void addSink(String agreement, Template template) throws NullPointerException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        if (null == agreement || null == template) {
            throw new NullPointerException("参数不能为空");
        }
        if (null == template.getStreamProcessorClass()) {
            throw new NullPointerException("处理器类不能为空");
        }
        Class className = Class.forName(template.getStreamProcessorClass());
        Object instance = className.newInstance();
        if (instance instanceof DataStreamSink) {
            DataStreamSink dataStreamSink = (DataStreamSink) instance;
            dataStreamSink.setSinkName(template.getProcessorName());
            dataStreamSink.setTemplateName(template.getTemplateName());
            if (this.sinks.containsKey(agreement)) {
                List<DataStreamSink> sinkList = this.sinks.get(agreement);
                sinkList.add(dataStreamSink);
                dataStreamSink.init(this);
            } else {
                List<DataStreamSink> sinkList = new LinkedList<>();
                sinkList.add(dataStreamSink);
                dataStreamSink.init(this);
                this.sinks.put(agreement, sinkList);
            }
        } else {
            throw new ClassNotFoundException();
        }
    }

    public DataStreamCache getCache() {
        return this.dataStreamCache;
    }

    public Map<String, DataItemTemplate> getItemTemplate(String agreement) {
        if (this.itemTemplates.containsKey(agreement)) {
            return this.itemTemplates.get(agreement);
        }
        return null;
    }

    public void stream(DataStreamAdapter dataStreamAdapter) {
        try {
            log.info("{} 开始处理数据", dataStreamAdapter.getAdapterKey());
            int readIndex = 0;
            byte[] block = dataStreamAdapter.getBlock();
            if (block.length == 0) {
                return;
            }
            log.info("{} 待处理数据包 {}", dataStreamAdapter.getAdapterKey(), BytesUtil.byte2HexStr(block));
            String agreement = dataStreamAdapter.getAgreement();
            if (null == agreement) {
                if (block.length >= 3) {
                    if (block[0] == 0x7e && block[1] == 0x7e) {
                        dataStreamAdapter.setAgreement(AgreementEnum.AGREEMENT_SW.getName());
                        agreement = AgreementEnum.AGREEMENT_SW.getName();
                    } else if (block[0] == 0x68 && block[2] == 0x68) {
                        dataStreamAdapter.setAgreement(AgreementEnum.AGREEMENT_SZY.getName());
                        agreement = AgreementEnum.AGREEMENT_SZY.getName();
                    }
                } else if (block.length >= 2) {
                    if (block[0] == 0x7e && block[1] == 0x7e) {
                        dataStreamAdapter.setAgreement(AgreementEnum.AGREEMENT_SW.getName());
                        agreement = AgreementEnum.AGREEMENT_SW.getName();
                    }
                }
            }
            if (null != agreement && processors.containsKey(agreement)) {
                List<DataStreamProcessor> processorList = processors.get(agreement);
                this.dataStreamCache.resetStore();
                this.dataStreamCache.setDataBuff(block);
                this.dataStreamCache.setState(TestState.LOOK);
                this.dataStreamCache.setReadSize(0);
                processorList.get(0).stream(dataStreamAdapter);
                if (dataStreamCache.getState() == TestState.ERROR) {
                    DataStreamProcessor matchProcessor = this.dataStreamCache.getMatchProcessor();
                    matchProcessor.batchComplete(dataStreamAdapter);
                    readIndex = dataStreamCache.getReadSize();
                    dataStreamAdapter.setLookTime(0L);
                } else if (dataStreamCache.getState() == TestState.LOOK) {
                    Long lookTime = dataStreamAdapter.getLookTime();
                    if (0 == lookTime) {
                        dataStreamAdapter.setLookTime(System.currentTimeMillis());
                    } else {
                        if ((System.currentTimeMillis() - lookTime) >= BusinessConstant.DATAGRAM_DELAY_TIME) {
                            readIndex = dataStreamAdapter.moveToNext();
                        }
                    }
                } else if (this.dataStreamCache.getState() == TestState.MATHCE) {
                    DataStreamProcessor matchProcessor = this.dataStreamCache.getMatchProcessor();
                    //回包
                    matchProcessor.batchComplete(dataStreamAdapter);
                    //输出
                    List<Map<String, Object>> elementDatas = matchProcessor.sink(dataStreamAdapter);
                    if (null != elementDatas) {
                        List<DataStreamSink> sinkList = this.sinks.get(agreement);
                        if (null != sinkList && sinkList.size() > 0) {
                            for (DataStreamSink streamSink : sinkList) {
                                streamSink.sink(dataStreamAdapter, elementDatas);
                            }
                        }
                    }
                    readIndex = this.dataStreamCache.getReadSize();
                    dataStreamAdapter.setLookTime(0L);
                } else {
                    //未定义报文，不做任何处理
                    DataStreamProcessor matchProcessor = this.dataStreamCache.getMatchProcessor();
                    matchProcessor.batchComplete(dataStreamAdapter);
                    readIndex = dataStreamCache.getReadSize();
                    dataStreamAdapter.setLookTime(0L);
                }
                dataStreamAdapter.readIndex(readIndex);
            } else {
                log.info("{} 没找到适配处理器", dataStreamAdapter.getAdapterKey());
                dataStreamAdapter.readIndex(1);
            }
        } catch (Exception e) {
            log.error(dataStreamAdapter.getAdapterKey(), e);
            dataStreamAdapter.error();
        } finally {
            log.info("{} 数据处理任务结束", dataStreamAdapter.getAdapterKey());
        }
    }
}
