package org.ts.ddcs.dataStream;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import org.ts.ddcs.common.enums.AgreementEnum;

import java.util.*;
import java.util.concurrent.*;


/**
 * 适配器，用于连接网络接口与数据处理器
 *
 * @author dylan
 */
@Data
@Slf4j
public abstract class DataStreamAdapter {
    protected LinkedBlockingQueue<byte[]> blockQueue = new LinkedBlockingQueue<>();
    protected ChannelHandlerContext ctx;
    private byte[] remainBuff = new byte[0];
    public Map<String, Object> keyStore = new ConcurrentHashMap<>();
    protected String remoteIp;
    protected String rtuCode;
    protected String adapterKey;
    private boolean isClose = false;
    private boolean lock = false;
    private String agreement;
    private String channelKey;
    private Long lookTime;

    public DataStreamAdapter() {
        this.adapterKey = UUID.randomUUID().toString().replace("-", "").toLowerCase();
    }

    public void init(String channelKey, String agreement, String remoteIp) {
        log.info("{} 初始化连接 IP:{}", this.adapterKey, remoteIp);
        this.channelKey = channelKey;
        this.agreement = agreement;
        this.remoteIp = remoteIp;
        DataStreamManageHolder.newInstance().dataStreamManager.regConnect(this);
    }

    public void putValue(String key, Integer value) {
        this.keyStore.put(key, value);
    }

    public Integer getIntValue(String key) {
        return (Integer) this.keyStore.get(key);
    }

    public void putValue(String key, String value) {
        this.keyStore.put(key, value);
    }

    public String getStringValue(String key) {
        return (String) this.keyStore.get(key);
    }

    public void putValue(String key, byte[] value) {
        this.keyStore.put(key, value);
    }

    public byte[] getByteValue(String key) {
        return (byte[]) this.keyStore.get(key);
    }

    public String getAdapterKey() {
        return this.adapterKey;
    }

    public void error() {
        log.info("{} 数据处理发生错误,测站编码:{}", this.adapterKey, this.rtuCode);
        this.remainBuff = new byte[0];
    }

    public boolean remaining() {
        if (remainBuff.length > 0) {
            return true;
        }
        if (blockQueue.isEmpty()) {
            return false;
        }
        return true;
    }

    public byte[] getBlock() {
        try {
            if (null == blockQueue) {
                return new byte[0];
            }
            if (!blockQueue.isEmpty()) {
                byte[] block = blockQueue.poll();
                int len = block.length;
                if (remainBuff.length > 0) {
                    len += remainBuff.length;
                }
                byte[] tmpBuff = new byte[len];
                if (remainBuff.length > 0) {
                    System.arraycopy(remainBuff, 0, tmpBuff, 0, remainBuff.length);
                }
                System.arraycopy(block, 0, tmpBuff, remainBuff.length, block.length);
                remainBuff = tmpBuff;
                return remainBuff;
            } else {
                if (remainBuff.length > 0) {
                    return remainBuff;
                } else {
                    return new byte[0];
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            return new byte[0];
        }
    }

    void readIndex(int index) {
        if (index <= 0 || index > remainBuff.length) {
            log.info("{} DataStreamAdapter read out index", this.adapterKey);
        } else {
            if (index == remainBuff.length) {
                remainBuff = new byte[0];
            } else {
                byte[] tmpBuff = new byte[remainBuff.length - index];
                System.arraycopy(remainBuff, index, tmpBuff, 0, remainBuff.length - index);
                remainBuff = tmpBuff;
            }
        }
    }

    public void close() {
        log.info("{} 连接关闭 ", this.adapterKey);
        this.ctx = null;
        this.isClose = true;
//        if (null == this.remainBuff || this.remainBuff.length == 0) {
//            DataStreamManageHolder.newInstance().dataStreamManager.closeConnect(this);
//        }
    }

    public void clear(){

    }

    public int moveToNext() {
        if (null != agreement && agreement.equals(AgreementEnum.AGREEMENT_SW.getName())) {
            for (int i = 3; i < this.remainBuff.length; i++) {
                if (this.remainBuff[i - 1] == 0x7E && this.remainBuff[i] == 0x7E) {
                    return i - 1;
                }
            }
        } else if (null != agreement && agreement.equals(AgreementEnum.AGREEMENT_SW_EXT.getName())) {
            for (int i = 3; i < this.remainBuff.length; i++) {
                if (this.remainBuff[i - 1] == 0x7E && this.remainBuff[i] == 0x7E) {
                    return i - 1;
                }
            }
        } else if (null != agreement && agreement.equals(AgreementEnum.AGREEMENT_SW_NM_EXT.getName())) {
            for (int i = 3; i < this.remainBuff.length; i++) {
                if (this.remainBuff[i - 1] == 0x7E && this.remainBuff[i] == 0x7E) {
                    return i - 1;
                }
            }
        } else if (null != agreement && agreement.equals(AgreementEnum.AGREEMENT_SZY.getName())) {
            for (int i = 5; i < this.remainBuff.length; i++) {
                if (this.remainBuff[i - 2] == 0x68 && this.remainBuff[i] == 0x68) {
                    return i - 2;
                }
            }
        }
        return this.remainBuff.length;
    }

    /**
     * 输出到数据连接通道
     *
     * @param respBody
     */
    public abstract void output(byte[] respBody);

    /**
     * UDP数据包
     *
     * @param buf
     * @param cx
     * @param datagramPacket
     */
    public abstract void pushData(ByteBuf buf, ChannelHandlerContext cx, DatagramPacket datagramPacket);

    /**
     * TCP数据包
     *
     * @param buf
     * @param cx
     */
    public abstract void pushData(ByteBuf buf, ChannelHandlerContext cx);

}
