package com.cisdi.data.RFID.gateway;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public class RfidClient {
    private static final Logger logger = LoggerFactory.getLogger(RfidClient.class);
    private volatile Channel channel = null;
    private EventLoopGroup workerGroup = null;
    private RfidTaskStartVo startVo;
    private Long lastHeartbeatTime = System.currentTimeMillis();

    public RfidClient(RfidTaskStartVo startVo) {
        this.startVo = startVo;

        if (Epoll.isAvailable()) {
            logger.info("rfid enable epoll and have tcp SO_KEEPALIVE check");
        } else {
            logger.info("rfid disable epoll and not have custom SO_KEEPALIVE check");
        }
    }

    public boolean close() {
        boolean result = false;
        if (workerGroup == null && channel == null) {
            return true;
        }

        if (channel != null) {
            try {
                channel.close().sync();
                channel = null;
                result = true;
            } catch (Exception e) {
                logger.error(e.getLocalizedMessage(), e);
            }
        }

        if (workerGroup != null) {
            try {
                workerGroup.shutdownGracefully().sync();
                workerGroup = null;
                result = true;
            } catch (InterruptedException e) {
                logger.error("永锋物流rfid到 {}:{}的连接关闭失败,{}",
                        startVo.getSocketParam().getPeerIp(), startVo.getSocketParam().getPeerPort(), e);
            }
        }

        if (channel != null || workerGroup != null) {
            logger.info("channel:{},workgoup:{}", channel, workerGroup);
        }

        return result;
    }

    public void run() throws IOException {
        start();
    }

    private void start() {
        lastHeartbeatTime = System.currentTimeMillis();
        if (channel != null) {
            close();
        }

        //设置一个多线程循环器
        //启动附注类
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);

        if (Epoll.isAvailable()) {
            bootstrap.channel(EpollSocketChannel.class);
            bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
            bootstrap.option(EpollChannelOption.TCP_KEEPIDLE, 10);
            bootstrap.option(EpollChannelOption.TCP_KEEPINTVL, 5);
            bootstrap.option(EpollChannelOption.TCP_KEEPCNT, 2);
            workerGroup = new EpollEventLoopGroup(2);
        } else {
            workerGroup = new NioEventLoopGroup(2);
            bootstrap.channel(NioSocketChannel.class);
        }

        bootstrap.group(workerGroup);
        //指定所使用的NIO传输channel
        //指定客户端初始化处理
        bootstrap.handler(new RfidClientInitializer(startVo, this));
        try {
            channel = bootstrap.connect(startVo.getSocketParam().getPeerIp(),
                    startVo.getSocketParam().getPeerPort()).sync().channel();
            //channel.closeFuture().sync();  // 如果会话关闭，会退出当前线程
        } catch (InterruptedException e) {
            logger.warn(e.getMessage(), e);
        }
    }

    public void reconnect() {
        logger.info("永锋物流rfid重新连接中......{}:{}", getIp(), getPort());
        close();
        start();
    }

    public Channel getChannel() {
        return channel;
    }

    public void setChannel(Channel channel) {
        this.channel = channel;
    }

    public String getIp() {
        return startVo.getSocketParam().getPeerIp();
    }

    public int getPort() {
        return startVo.getSocketParam().getPeerPort();
    }

    public Long getLastHeartbeatTime() {
        return lastHeartbeatTime;
    }

    public void setLastHeartbeatTime(Long lastHeartbeatTime) {
        this.lastHeartbeatTime = lastHeartbeatTime;
    }
}
