package com.yfd.platform.component.nettyudpclient;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.yfd.platform.component.nettyudpserver.MyMessageProtocol;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import lombok.extern.slf4j.Slf4j;

import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.sql.Timestamp;
import java.time.LocalDateTime;

/**
 * UDP Client
 */
@Slf4j
public class NettyUdpClient {
    private static final Charset CHARSET = Charset.forName("GB2312");

    public static void main(String[] args) throws Exception {
        //模拟主辅设备发送联动配置文件
//                testSendLinkFile();

        //模拟主辅设备发送一键顺控  86  3 103 21
        testSendLinkComand("192.168.1.20", "1", "1060", "9301");
        Thread.sleep(15000);
        testSendLinkComand("192.168.1.20","1","1061","9301");
//        Thread.sleep(500);
//        testSendLinkComand("192.168.22.1","1","21","9300");
        //模拟主辅设备发送智能联动
//                testSendLinkComand1();
    }

    //模拟主辅设备发送联动信号配置文件
    public static void testSendLinkFile() {
        // 创建事件循环组
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            // 创建启动器
            Bootstrap b = new Bootstrap();
            // 设置事件循环组，通道类型，广播选项和处理器
            b.group(group)
                    .channel(NioDatagramChannel.class)
                    .option(ChannelOption.SO_BROADCAST, true)
                    .handler(new NettyUdpClientHandler())
            ;
            // 绑定本地端口并同步等待通道
            Channel channel = b.bind(8081).sync().channel();
            // 创建一个ByteBuf对象用于存储消息内容
            String filecontent = CimFileUtil.getCimFile();
            byte[] content = filecontent.getBytes("GB2312");
            int k = content.length / 240;
            for (int i = 0; i <= k; i++) {
                int nextflag = 0;
                if (i < k) {
                    nextflag = 1;
                }
                ByteBuf buf = NettyUdpClient.createFileFramebuf(nextflag, i, i * 240);
                channel.writeAndFlush(new DatagramPacket(buf, new InetSocketAddress("192.168.1.20", 9300)));
            }


            // 等待通道关闭
            channel.closeFuture().sync();
        } catch (InterruptedException e) {
            log.error(e.getMessage());;
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());;
        } finally {
            // 释放资源
            group.shutdownGracefully();
        }
    }

    public static ByteBuf createFileFramebuf(int nextflag, int frameno, int startlocation) throws UnsupportedEncodingException {
        ByteBuf buf = Unpooled.buffer();
        byte[] frametype = new byte[]{(byte) 0x43, (byte) 0x90, (byte) 0xEB, (byte) 0x90, (byte) 0xEB};
        buf.writeBytes(frametype);
        buf.writeShortLE(1);//站序号
        buf.writeByte(nextflag);//后续位标志  0：无后续帧；1：有后续帧
        buf.writeShortLE(frameno);//帧序号 0 开始，后续累加 1
        buf.writeIntLE(startlocation);//起始传输位置  本帧传输的文件起始地址在全部文件中的位置
        // 写入CIM文件内容
        String filecontent = CimFileUtil.getCimFile();
        byte[] content = filecontent.getBytes(CHARSET);
        if (frameno == 0 && nextflag == 0) {//是第一帧，并且无后续帧
            int length = content.length;
            byte[] framecontent = new byte[length];
            System.arraycopy(content, startlocation, framecontent, 0, length);
            buf.writeByte(framecontent.length);
            buf.writeBytes(framecontent);
            short Totallength = Short.parseShort(String.valueOf(10 + framecontent.length));
            buf.writeByte(Totallength);  //校验文件流
        } else if (frameno == 0 && nextflag > 0) {//大于第一帧，并且有后续帧
            byte[] framecontent = new byte[240];
            System.arraycopy(content, startlocation, framecontent, 0, 240);
            buf.writeByte(framecontent.length);
            buf.writeBytes(framecontent);
            short Totallength = Short.parseShort(String.valueOf(10 + framecontent.length));
            buf.writeByte(Totallength);  //校验文件流
        } else if (frameno > 0 && nextflag > 0) {//大于第一帧，并且有后续帧
            byte[] framecontent = new byte[240];
            System.arraycopy(content, startlocation, framecontent, 0, 240);
            buf.writeByte(framecontent.length);
            buf.writeBytes(framecontent);
            short Totallength = Short.parseShort(String.valueOf(10 + framecontent.length));
            buf.writeByte(Totallength);  //校验文件流
        } else if (frameno > 0 && nextflag == 0) {//大于第一帧，并且无后续帧
            int length = content.length - frameno * 240;
            byte[] framecontent = new byte[length];
            System.arraycopy(content, startlocation, framecontent, 0, length);
            buf.writeByte(framecontent.length);
            buf.writeBytes(framecontent);
            short Totallength = Short.parseShort(String.valueOf(10 + framecontent.length));
            buf.writeByte(Totallength);  //校验文件流
        }
        return buf;
    }

    //模拟主辅设备发送联动信息
    public static void testSendLinkComand(String ip, String no, String index, String port) {
        // 创建事件循环组
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            // 创建启动器
            Bootstrap b = new Bootstrap();
            // 设置事件循环组，通道类型，广播选项和处理器
            b.group(group)
                    .channel(NioDatagramChannel.class)
                    .option(ChannelOption.SO_BROADCAST, true)
                    .handler(new NettyUdpClientHandler())
            ;
            // 绑定本地端口并同步等待通道
            Channel channel = b.bind(8081).sync().channel();
            //EB90EB9055
            // 创建一个ByteBuf对象用于存储消息内容
            ByteBuf buf = Unpooled.buffer();
            byte[] frametype = new byte[]{(byte) 0xEB, (byte) 0x90, (byte) 0xEB, (byte) 0x90, (byte) 0x55};
            buf.writeBytes(frametype);

            //示例数据：1 1039 0 动作 保护跳闸 2022-02-01 08:18:55.356
            buf.writeShortLE(Integer.parseInt(no));
            buf.writeShortLE(Integer.parseInt(index));
            buf.writeByte(0);
            // 写入第一个字符串长度和内容
            String firstString = "动作-主变保护跳闸类";
            buf.writeByte(firstString.getBytes(CHARSET).length);
            buf.writeBytes(firstString.getBytes(CHARSET));
            // 写入第二个字符串长度和内容
            String secondString = "合位";
            buf.writeByte(secondString.getBytes(CHARSET).length);
            buf.writeBytes(secondString.getBytes(CHARSET));
            //“2022-02-01 08:18:55.356”  [01,64,3B,08,40,80,CB]
            byte[] eventtimes = MyMessageProtocol.timeStringToCP56(DateUtil.format(new Timestamp(System.currentTimeMillis()), "yyyy-MM-dd HH:mm:ss.SSS"));
            buf.writeBytes(eventtimes);
            short Totallength = Short.parseShort(String.valueOf(14 + firstString.getBytes(CHARSET).length + secondString.getBytes(CHARSET).length));
            buf.writeShort(Totallength);
            // 向服务端发送消息
            channel.writeAndFlush(new DatagramPacket(buf, new InetSocketAddress(ip, Integer.parseInt(port))));
            // 等待通道关闭
//            channel.closeFuture().sync();
            channel.close();
        } catch (InterruptedException e) {
            log.error(e.getMessage());;
        } finally {
            // 释放资源
            group.shutdownGracefully();
        }
    }

    //模拟主辅设备发送联动信息
    public static void testSendLinkComand1() {
        // 创建事件循环组
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            // 创建启动器
            Bootstrap b = new Bootstrap();
            // 设置事件循环组，通道类型，广播选项和处理器
            b.group(group)
                    .channel(NioDatagramChannel.class)
                    .option(ChannelOption.SO_BROADCAST, true)
                    .handler(new NettyUdpClientHandler())
            ;
            // 绑定本地端口并同步等待通道
            Channel channel = b.bind(8081).sync().channel();
            // 创建一个ByteBuf对象用于存储消息内容
            ByteBuf buf = Unpooled.buffer();
            byte[] frametype = new byte[]{(byte) 0x55, (byte) 0x90, (byte) 0xEB, (byte) 0x90, (byte) 0xEB};
            buf.writeBytes(frametype);

            //示例数据：1 1039 0 动作 保护跳闸 2022-02-01 08:18:55.356
            buf.writeShort(1);
            buf.writeShort(1042);
            buf.writeByte(0);
            // 写入第一个字符串长度和内容
            String firstString = "动作";
            buf.writeByte(firstString.getBytes(CHARSET).length);
            buf.writeBytes(firstString.getBytes(CHARSET));
            // 写入第二个字符串长度和内容
            String secondString = "启动";
            buf.writeByte(secondString.getBytes(CHARSET).length);
            buf.writeBytes(secondString.getBytes(CHARSET));
            //“2022-02-01 08:18:55.356”  [01,64,3B,08,40,80,CB]
            byte[] eventtimes =
                    MyMessageProtocol.timeStringToCP56(DateUtil.format(new Timestamp(System.currentTimeMillis()),
                            "yyyy-MM-dd HH:mm:ss.SSS"));
            buf.writeBytes(eventtimes);
            short Totallength =
                    Short.parseShort(String.valueOf(14 + firstString.getBytes(CHARSET).length + secondString.getBytes(CHARSET).length));
            buf.writeShort(Totallength);
            // 向服务端发送消息
            channel.writeAndFlush(new DatagramPacket(buf, new InetSocketAddress("192.168.1.7", 9300)));
            // 等待通道关闭
            channel.closeFuture().sync();
        } catch (InterruptedException e) {
            log.error(e.getMessage());;
        } finally {
            // 释放资源
            group.shutdownGracefully();
        }
    }
}

