package org.ts.ddcs.net;


import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import lombok.extern.slf4j.Slf4j;
import org.ts.ddcs.dataStream.DataStreamAdapter;
import org.ts.ddcs.dataStream.UdpDataStreamAdapter;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;


/**
 * UDP网络通道处理器
 *
 * @author dylan
 */
@Slf4j
public class UdpDataHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    private String channelKey;
    private String bindAgreeement;
    private Map<String, UdpDataStreamAdapter> templateAdapter = new HashMap<>();

    public UdpDataHandler(String channelKey, String bindAgreeement) {
        this.channelKey = channelKey;
        this.bindAgreeement = bindAgreeement;
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        log.info("********* udp handlerAdded *********");
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, DatagramPacket datagramPacket) throws Exception {
        try {
            ByteBuf in = datagramPacket.content();
            InetSocketAddress address = datagramPacket.sender();
            String hostName = address.getHostName();
            if (this.templateAdapter.containsKey(hostName)) {
                UdpDataStreamAdapter udpAdapter = this.templateAdapter.get(hostName);
                udpAdapter.pushData(in, channelHandlerContext, datagramPacket);
            } else {
                UdpDataStreamAdapter udpAdapter = new UdpDataStreamAdapter();
                udpAdapter.init(channelKey, bindAgreeement, hostName);
                DataChannelHolder.newInstance().dataChannel.online(udpAdapter);
                this.templateAdapter.put(hostName, udpAdapter);
                udpAdapter.pushData(in, channelHandlerContext, datagramPacket);
            }
        } catch (Exception e) {
            log.error("error",e);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable cause)
            throws Exception {
        try {
            Set<String> keys = this.templateAdapter.keySet();
            for (String key : keys) {
                DataStreamAdapter adapter = this.templateAdapter.get(key);
                adapter.close();
                DataChannelHolder.newInstance().dataChannel.offline(adapter);
            }
            this.templateAdapter.clear();
            log.info("********* udp exceptionCaught " + cause.getMessage());
        } catch (Exception e) {
            log.error("error",e);
            throw e;
        } finally {
            channelHandlerContext.close();
        }
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        try {
            Set<String> keys = this.templateAdapter.keySet();
            for (String key : keys) {
                DataStreamAdapter adapter = this.templateAdapter.get(key);
                adapter.close();
                DataChannelHolder.newInstance().dataChannel.offline(adapter);
            }
            this.templateAdapter.clear();
            log.info("********* udp handlerRemoved *********");
        } catch (Exception e) {
            log.error("error",e);
        }
    }
}
