package org.ts.ddcs.net;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.ts.ddcs.dataStream.TcpDataStreamAdapter;

import java.net.SocketAddress;

/**
 * TCP网络通道处理器
 *
 * @author dylan
 */
@Slf4j
public class TcpDataHandler extends ChannelInboundHandlerAdapter {

    private String channelKey;
    private String bindAgreeement;
    private TcpDataStreamAdapter templateAdapter = new TcpDataStreamAdapter();


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

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        try {
            log.info("{} channel handler add" ,this.templateAdapter.getAdapterKey());
            SocketAddress socketAddress = ctx.channel().remoteAddress();
            String remoteIp = "";
            if (null != socketAddress) {
                remoteIp = socketAddress.toString();
                int index = remoteIp.lastIndexOf("/");
                if (index >= 0) {
                    remoteIp = remoteIp.substring(index + 1);
                }
                log.info("{} remote ip {}" ,this.templateAdapter.getAdapterKey() ,remoteIp);
            }
            this.templateAdapter.init(channelKey,bindAgreeement,remoteIp);
            DataChannelHolder.newInstance().dataChannel.online(this.templateAdapter);
        } catch (Exception e) {
            log.error(this.getClass().getName(),e);
            ctx.close();
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf in = (ByteBuf) msg;
        try {
            log.info("{} channel handler channelRead" , this.templateAdapter.getAdapterKey() );
            this.templateAdapter.pushData(in, ctx);
        } catch (Exception e) {
            log.error(this.getClass().getName(),e);
        } finally {
            ReferenceCountUtil.release(in);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        try {
            log.info("{} channel handler exceptionCaught {}",  this.templateAdapter.getAdapterKey() , cause.getMessage());
            this.templateAdapter.close();
            DataChannelHolder.newInstance().dataChannel.offline(this.templateAdapter);
        } catch (Exception e) {
            log.error(this.getClass().getName(),e);
        } finally {
            ctx.close();
        }
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        try {
            log.info("{} channel handler handlerRemoved" , this.templateAdapter.getAdapterKey());
            this.templateAdapter.close();
             DataChannelHolder.newInstance().dataChannel.offline(this.templateAdapter);
        } catch (Exception e) {
            log.error(this.getClass().getName(),e);
        }
    }
}
