package com.wdkl.ncs.android.middleware.tcp;

import android.util.Log;

import com.wdkl.ncs.android.middleware.common.Constant;
import com.wdkl.ncs.android.middleware.common.MessageEvent;
import com.wdkl.ncs.android.middleware.tcp.channel.DeviceChannel;
import com.wdkl.ncs.android.middleware.tcp.channel.DeviceUtil;
import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel;

import org.greenrobot.eventbus.EventBus;

import java.util.concurrent.TimeUnit;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;

@ChannelHandler.Sharable
public class TcpClientHandler extends SimpleChannelInboundHandler<String> {
    private static final String TAG = TcpClientHandler.class.getSimpleName();
    ChannelHandlerContext ctx;
    //重连间隔
    private static Integer retrySeconds = 5;
    //重连计数
    private static Integer retryTimes = 0;
    //总共总连接次数，总连接次数过多可能是网络不稳定
    private static Integer totalRetryTimes = 0;
    //是否连接成功
    private static Boolean connected = false;

    //连接成功执行的方法
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        Log.i(TAG, "连接成功");
        this.ctx = ctx;
        connected = true;
        retryTimes = 0;
        Constant.TCP_CONNECTED = true;
        EventBus.getDefault().post(new MessageEvent(1, Constant.EVENT_TCP_STATE));
        TcpModel tcpModel = DeviceUtil.deviceConnect(Constant.LOCAL_MAC);
        TcpClient.getInstance().sendMsg(tcpModel.toJson());
    }

    //断开连接
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        connected = false;
        Constant.TCP_CONNECTED = false;
        EventBus.getDefault().post(new MessageEvent(0, Constant.EVENT_TCP_STATE));
        Log.i(TAG, "失去连接");
        TcpClient.getInstance().doConnect();
    }

    //读取String消息
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String source) throws Exception {
        if(source.equals("1")){
            Log.i(TAG,"收到服务器返回的心跳 "+source);
        }else {
            TcpModel tcpModel = TcpModel.getModelByJson(source);

            if (tcpModel != null) {
                TcpModel responseTcpModel = DeviceChannel.handleTcpReceived(tcpModel);
                if (responseTcpModel != null) {
                    ctx.writeAndFlush(responseTcpModel.toJson());
                } else {
                    ReferenceCountUtil.release(source);
                }
            }
        }

    }

    //写心跳包。没有消息发送时，每间隔一定时间会由此方法向服务端发送心跳
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.WRITER_IDLE) { //超时未执行写操作,在指定的超时时间内未有写操作，要发送心跳包，告诉服务器连接还存活。服务器收到心跳立马回应，正常客户端收到后执行读操作，
                ctx.writeAndFlush("0");                //这种情况下不会引发READER_IDLE事件。如果服务器因为网络或其他原因导致回应的心跳，客户端没有收到，在超过写超时时间2个周期后依然没有收到，
            } else if (event.state() == IdleState.READER_IDLE) { //认为服务不可用，主动断开连接
                Log.i(TAG, "TcpClientHandler ===> READER_IDLE");
                ctx.close();
            } else if (event.state() == IdleState.ALL_IDLE) {
                Log.i(TAG, "TcpClientHandler ===> ALL_IDLE");
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
        Constant.TCP_CONNECTED = false;
        EventBus.getDefault().post(new MessageEvent(0, Constant.EVENT_TCP_STATE));
        connected = false;
        System.out.println("失去连接，错误引起");
    }

    //发送消息，不直接调用些方法，调用TcpClient中的发送消息
    public void sendMsg(String msg){
        if (ctx==null){
            System.out.println("ctx is null");
            return;
        }
        System.out.println("send tcp msg====" + msg);
        ctx.writeAndFlush(Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));
    }
}
