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

import java.net.InetSocketAddress;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

public class UdpClient {
    private final String TAG = getClass().getSimpleName();

    private NioEventLoopGroup workGroup;
    public Channel channel;
    private Bootstrap bootstrap;

    Lock lock = new ReentrantLock();
    public static String result = null;

    public static final String SEARCH_SERVER = "search_server";
    public static final Integer UDP_TARGET_PORT = 10010;
    static Integer retrySendCountLimit = 5; //最大重发次数
    static Integer retrySendSeconds = 3;    //重发间隔
    static Integer retrySendCount = 0;  //重发计数

    UdpClientHandler udpClientHandler = new UdpClientHandler();

    //单例
    private static class UdpClientHolder {
        private static UdpClient instance = new UdpClient();
    }

    public static UdpClient getInstance() {
        return UdpClientHolder.instance;
    }

    private void run(){
        workGroup = new NioEventLoopGroup(2);
        bootstrap = new Bootstrap();
        bootstrap.group(workGroup)
                .channel(NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST,true)
                .handler(udpClientHandler);
        try {
            channel = bootstrap.bind(0).sync().channel();
        }catch (Exception ex){
            System.out.println(ex.getMessage());
        }
    }


    public String broadMsg(String msg, Integer serverPort){
        lock.lock();
        CountDownLatch latch = new CountDownLatch(1);
        udpClientHandler.resetLatch(latch);
        run();
        System.out.println("发送消息：" + msg);
        try {
            String broadcastAddress = NetIpUtil.calBroadcastAddress();
            channel.writeAndFlush(new DatagramPacket(
                    Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8),
                    new InetSocketAddress(broadcastAddress, serverPort)
            )).sync().addListener(new GenericFutureListener<Future<? super Void>>() {
                @Override
                public void operationComplete(Future<? super Void> future) throws Exception {
                    if (future.isSuccess()){
                        System.out.println("发送成功");
                    }
                }
            });
            //等待3秒后，未收到信息，再次发送udp
            if (latch.await(retrySendSeconds, TimeUnit.SECONDS)){
                if (retrySendCount>=retrySendCountLimit){
                    retrySendCount = 0;
                    result = null;
                    close();
                }
                if (result==null) {
                    retrySendCount++;
                    broadMsg(msg, serverPort);
                } else {
                    return result;
                }
            }
            if (!channel.closeFuture().await(retrySendSeconds*retrySendCountLimit*1000)){
                //超时15秒
                System.out.println("超时停止");
                result = null;
            }
        }catch (Exception ex){
            System.out.println(ex.getMessage());
            result = null;
        }finally {
            close();
        }
        return null;
    }

    private void close(){
        workGroup.shutdownGracefully();
        try{
            if (lock!=null){
                lock.unlock();
            }
        }catch (IllegalMonitorStateException ex){
            Thread.currentThread().interrupt();
        }
    }

    public static void main(String[] args) {
        System.out.println("result = " + UdpClient.getInstance().broadMsg(SEARCH_SERVER,UDP_TARGET_PORT));
    }
}
