package org.kne.cloud.network.klalb.ui;

import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.*;
import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.function.Consumer;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.jfree.chart.plot.dial.*;
import org.jfree.data.general.DefaultValueDataset;
import org.kne.cloud.clock.HighAccuracyClock;
import org.kne.cloud.klalb.uitool.*;
import org.kne.cloud.network.MultiProtocolSocketAddress;
import org.kne.cloud.network.ipv6.IPv6Address;
import org.kne.cloud.network.ipv6.IPv6NetworkLink;
import org.kne.cloud.network.klalb.*;
import org.kne.cloud.network.klalb.ui.GraphPanel.GraphNode;
import org.kne.cloud.network.monitor.LinkStatus;
import org.kne.cloud.network.srv6.SRv6Router;
import org.kne.ui.XFrame;
import org.kne.ui.YScrollPane;

/**
 * KLALB状态监控GUI界面 - 版本3
 * 提供网络协议栈的监控面板，包括网络图、远程线路、仪表盘和配置管理
 */
public class KLALBStateGUI3 extends XFrame {

    // ==================== 定时任务相关 ====================
    private TimerTask tsk, tsk2, tsk3, tsk4, tsk5; // 各种定时任务
    private Timer t, t2, t3; // 定时器

    // ==================== 系统托盘相关 ====================
    private SystemTray st;  // 系统托盘
    private TrayIcon ti;    // 托盘图标

    // ==================== 仪表盘数据集 ====================
    private DefaultValueDataset upSpeed;       // 上行速度数据集
    private DefaultValueDataset downSpeed;     // 下行速度数据集
    private DefaultValueDataset upPPS;         // 上行包速率数据集
    private DefaultValueDataset downPPS;       // 下行包速率数据集
    private DefaultValueDataset upDataSpeed;   // 上行数据速度
    private DefaultValueDataset downDataSpeed; // 下行数据速度
    private DefaultValueDataset upDataPPS;     // 上行数据包速率
    private DefaultValueDataset downDataPPS;   // 下行数据包速率
	private DefaultValueDataset backplaneDelay;
	private DefaultValueDataset backplanePPS;
	private DefaultValueDataset backplaneECNRate;
	private DefaultValueDataset backplaneLossRate;

    // ==================== 仪表盘文本标注 ====================
    private DialTextAnnotation upSpeedText;    // 上行速度文本标注
    private DialTextAnnotation downSpeedText;  // 下行速度文本标注
    private DialTextAnnotation upPPSText;      // 上行包速率文本标注
    private DialTextAnnotation downPPSText;    // 下行包速率文本标注
	private DialTextAnnotation backplaneDelayText;
	private DialTextAnnotation backplanePPSText;
	private DialTextAnnotation backplaneECNRateText;
	private DialTextAnnotation backplaneLossRateText;

    // ==================== UI组件 ====================
    private YScrollPane ysp, yspc;                     // 可垂直滚动的面板
    private JTextField devicesOnline;                  // 在线设备数显示
    private JTextField textField;                      // 通用文本框
    private JTextField addressField;                   // 地址显示框
    private JTextField addressFieldSet;                // 地址设置框
    private JTextField asnFieldSet;                    // ASN设置框
    private JTextField tunDeviceName;                    // 虚拟网卡名称设置框
    private NetworkGraphPanel graph;                   // 网络图面板
    private JTextField textFieldLocate;                // 定位地址输入框
    private JTextField asnField2;                      // ASN显示框
    private JTextArea dnsAreaSet;                      // DNS服务器设置区域
    private JComboBox<PerformanceStrategyItem> comboPerformance;                   // 性能策略选择框
    private JComboBox comboCongestion;                   // 拥塞控制算法选择框
    private JTextField tcpListeningSet;                // TCP监听设置
    private JTextField udpListeningSet;                // UDP监听设置
    private JTextArea openLineTabelSet;                // 开放线路表设置
    private JTextArea connectLineTabelSet;             // 自动连接线路表设置
    private JComboBox comboLang;                       // 语言选择框
    private XDefaultListModel<NetworkInterface> nilsimdl; // 网络接口排除列表模型
    private JTextField textFieldTime;                  // 当前时间显示框
    private JTextArea ntpServerSet;                    // NTP服务器设置区域
	private JCheckBox denyBroadcast;
	private JCheckBox denyQuery;
    private ClosableTabbedPane tabbedPane;             // 可关闭的标签页面板
	private JCheckBox nogui;

    // ==================== 配置和回调 ====================
    private KLALBConfig config;                         // 配置文件
    private Consumer<KLALBConfig> saveComsumer;        // 保存配置的回调函数

    // ==================== 尺寸常量 ====================
    private Dimension dashSize = new Dimension((int) (145 * 0.7), (int) (165 * 0.7)); // 仪表盘尺寸

    // ==================== 菜单项 ====================
    private JCheckBoxMenuItem showoffline;             // 显示离线设备菜单项
    private SliderSettingItem  linkConnectionsCount;
	private SliderSettingItem nagleDelayTime;
	private SliderSettingItem linkNagleDelayTime;
	private SliderSettingItem burstLimit;
	private SliderSettingItem delayHbound;
	private SliderSettingItem delayLbound;
	private ComboSettingItem performanceStrategy;
	private ComboSettingItem congestions;

    // ==================== 构造方法 ====================
    /**
     * 默认构造方法，使用默认标题
     * @param kpcje KLALB控制器
     */
    public KLALBStateGUI3(KLALBController kpcje) {
        this(kpcje, CONST.klalb + " " + UIEnv.getRsb().getString("srv6acc") + " V" + CONST.klalbver);
    }

    /**
     * 主构造方法
     * @param kc KLALB控制器
     * @param title 窗口标题
     */
    public KLALBStateGUI3(KLALBController kc, String title) {
        initUI(kc, title);
        initSystemTray();
        initTimers(kc);
    }

    // ==================== UI初始化方法 ====================
    /**
     * 初始化UI界面
     */
    private void initUI(KLALBController kc, String title) {
        // 设置窗口基本属性
        setIconImage(UIEnv.getIcon());
        setTitleColor(UIEnv.getDefaultTitleColor());
        getContentPane().setBackground(UIEnv.getDefaultBackgroundColor());
        getTitlelabel().setFont(UIEnv.getFont().deriveFont(17.0f));
        getTitlepanel().setBorder(new LineBorder(Color.LIGHT_GRAY));
        getTitlelabel().setForeground(Color.WHITE);

        // 创建标签页面板
        tabbedPane = new ClosableTabbedPane(JTabbedPane.TOP);
        getContentPane().add(tabbedPane, BorderLayout.CENTER);

        // 创建网络图面板
        createNetworkGraphPanel(kc);
        

        // 创建仪表盘面板
        createDashboardPanel(kc);
        
        // 创建远程线路面板
        createRemoteLinesPanel(kc);
        
        // 创建设置面板
        createSettingsPanel();

        // 创建菜单栏
        createMenuBar();

        // 设置窗口属性
        setTitle(title);
        setSize(1200, 780);
        setLocationRelativeTo(null);
    }
    /**
     * 创建仪表盘面板
     */
    private void createDashboardPanel(KLALBController kc) {
    	 JPanel panel_3 = new JPanel();
         panel_3.setBackground(Color.WHITE);
         panel_3.setOpaque(false);
         // 创建图标
         Icon icon = createIcon("/assets/dashboard.png", 15, 15);
         tabbedPane.addTab(UIEnv.getRsb().getString("dashboard"), icon, panel_3, null, false);
         panel_3.setLayout(new BorderLayout());

         // 添加时间显示
         createTimeInfoPanel(panel_3);
         
         JPanel panel_4=new JPanel();
         panel_4.setOpaque(false);
         panel_4.setLayout(new FlowLayout(FlowLayout.LEADING));
         panel_3.add(panel_4,BorderLayout.CENTER);
         
         // 添加上行下行速度仪表盘
         createSpeedDials(panel_4);
         
         // 添加上行下行包速率仪表盘
         createPPSDials(panel_4);
         
         //添加背板仪表盘
         createBackplaneDials(panel_4);
    }
    /**
     * 创建网络图面板
     */
    private void createNetworkGraphPanel(KLALBController kc) {
        JPanel panel_3 = new JPanel();
        panel_3.setBackground(Color.WHITE);
        
        // 创建图标
        Icon icon = createIcon("/assets/graph.png", 15, 15);
        tabbedPane.addTab(UIEnv.getRsb().getString("networkgraph"), icon, panel_3, null, false);
        panel_3.setLayout(new BorderLayout(0, 0));

        // 创建顶部控制面板
        JPanel panel_4 = new JPanel();
        panel_3.add(panel_4, BorderLayout.NORTH);
        panel_4.setLayout(new BorderLayout(0, 0));

        // 地址定位输入框
        textFieldLocate = new JTextField();
        panel_4.add(textFieldLocate, BorderLayout.CENTER);
        textFieldLocate.setColumns(10);

        // 创建网络图面板
        graph = new NetworkGraphPanel(kc, this);
        graph.setOpaque(false);
        JScrollPane jsp = new JScrollPane();
        jsp.setWheelScrollingEnabled(false);
        jsp.setViewportView(graph);
        initEventListeners(kc,jsp);

        // 添加鼠标滚轮缩放支持
        addGraphZoomSupport(jsp);

        // 创建定位按钮
        JButton btnLocate = new JButton(UIEnv.getRsb().getString("find"));
        btnLocate.addActionListener(e -> locateAddressInGraph(jsp));
        panel_4.add(btnLocate, BorderLayout.EAST);

        // 创建首页按钮
        JButton btnHome = new JButton(UIEnv.getRsb().getString("home"));
        btnHome.addActionListener(e -> {
            textFieldLocate.setText(addressField.getText());
            btnLocate.doClick();
        });
        panel_4.add(btnHome, BorderLayout.WEST);

        // 添加网络图到面板
        panel_3.add(jsp, BorderLayout.CENTER);

        // 创建底部面板
        JPanel panel_4_1 = new JPanel();
        panel_3.add(panel_4_1, BorderLayout.SOUTH);
        panel_4_1.setLayout(new BorderLayout(0, 0));

        // 添加回车键监听
        textFieldLocate.addKeyListener(createEnterKeyListener(btnLocate));

        

        // 创建信息面板
        JPanel panelp = new JPanel();
        panelp.setOpaque(false);
        panel_4_1.add(panelp, BorderLayout.CENTER);
        panelp.setLayout(new GridLayout(1, 2, 0, 0));

        // 添加在线设备显示
        createOnlineDevicesPanel(panelp);
        // 添加IP地址显示
        createAddressInfoPanel(panelp);
        
        
       
    }

    /**
     * 为网络图添加缩放支持
     */
    private void addGraphZoomSupport(JScrollPane jsp) {
        graph.addMouseWheelListener(new MouseWheelListener() {
            private double scaleidx = 1;

            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                int val = e.getWheelRotation();
                double scaleidxold = scaleidx;
                scaleidx *= Math.pow(1.1, val);
                
                // 限制缩放范围
                scaleidx = Math.max(0.1, Math.min(5, scaleidx));
                
                double pow = scaleidx / scaleidxold;
                Point pos = jsp.getViewport().getViewPosition();
                double canvasX = e.getX();
                double canvasY = e.getY();
                double w = graph.getWidth();
                double h = graph.getHeight();
                
                // 计算缩放中心点
                double percentX = canvasX / w;
                double percentY = canvasY / h;
                graph.setScale(scaleidx);
                graph.updateBounds();
                
                // 调整视图位置以保持缩放中心
                double newcanvasX = percentX * w * pow;
                double newcanvasY = percentY * h * pow;
                double dx = newcanvasX - canvasX;
                double dy = newcanvasY - canvasY;
                pos.x += dx;
                pos.y += dy;
                jsp.getViewport().setViewPosition(pos);
            }
        });
    }

    /**
     * 在网络图中定位地址
     */
    private void locateAddressInGraph(JScrollPane jsp) {
        String text = textFieldLocate.getText();
        try {
            GraphNode node = graph.getNodes().get(new IPv6Address((Inet6Address) InetAddress.getByName(text)));
            if (node == null) {
                JOptionPane.showMessageDialog(KLALBStateGUI3.this, "Address not found", 
                    UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
            } else {
                Point pos = new Point();
                graph.updateBounds();
                Dimension dim = jsp.getViewport().getExtentSize();
                // 计算节点在视口中的位置
                pos.x = (int) ((node.getX() + graph.getTranslateX()) * graph.getScale() - dim.width / 2);
                pos.y = (int) ((node.getY() + graph.getTranslateY()) * graph.getScale() - dim.height / 2);
                jsp.getViewport().setViewPosition(pos);
            }
        } catch (UnknownHostException e1) {
            JOptionPane.showMessageDialog(KLALBStateGUI3.this, "Input format error", 
                UIEnv.getRsb().getString("error"), JOptionPane.ERROR_MESSAGE);
            e1.printStackTrace();
        }
    }

    /**
     * 创建速度仪表盘
     */
    private void createSpeedDials(JPanel dashs) {
        // 上行速度仪表盘
        upSpeed = new DefaultValueDataset(0);
        upDataSpeed = new DefaultValueDataset(0);
        DialPanel dialup=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("uploadspeed"), upSpeed, upDataSpeed, Color.RED, new Color(127, 0, 0));
        dialup.addGradientRanges(UIEnv.RANGE_1);
        upSpeedText =dialup.getTextAnnotation();

       
        dashs.add(dialup);

        // 下行速度仪表盘
        downSpeed = new DefaultValueDataset(0);
        downDataSpeed = new DefaultValueDataset(0);
        DialPanel dialdown=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("downloadspeed"), downSpeed, downDataSpeed, Color.GREEN,  new Color(0, 127, 0));
        dialdown.addGradientRanges(UIEnv.RANGE_1);
        downSpeedText =dialdown.getTextAnnotation();
        
        dashs.add(dialdown);
    }

    /**
     * 创建包速率仪表盘
     */
    private void createPPSDials(JPanel dashs) {
        // 上行包速率仪表盘
        upPPS = new DefaultValueDataset(0);
        upDataPPS = new DefaultValueDataset(0);
        DialPanel dialupPPS=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("uploadpps"), upPPS, upDataPPS, Color.RED, new Color(127, 0, 0));
        dialupPPS.addGradientRanges(UIEnv.RANGE_1);
        upPPSText = dialupPPS.getTextAnnotation();

        dashs.add(dialupPPS);

        // 下行包速率仪表盘
        downPPS = new DefaultValueDataset(0);
        downDataPPS = new DefaultValueDataset(0);
        DialPanel dialdownPPS=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("downloadpps"), downPPS, downDataPPS, Color.GREEN,  new Color(0, 127, 0));
        dialdownPPS.addGradientRanges(UIEnv.RANGE_1);
        downPPSText = dialdownPPS.getTextAnnotation();

        dashs.add(dialdownPPS);
    }

    /**
     * 创建背板仪表盘
     */
    private void createBackplaneDials(JPanel dashs) {
        // 背板转发延迟仪表盘
        backplaneDelay = new DefaultValueDataset(0);
        DialPanel dialupPPS=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("backplanedelay"), backplaneDelay, null, Color.BLUE, new Color(0, 0, 127));

        dialupPPS.addGradientRanges(UIEnv.RANGE_2);
        backplaneDelayText = dialupPPS.getTextAnnotation();

        dashs.add(dialupPPS);

        // 背板PPS仪表盘
        backplanePPS = new DefaultValueDataset(0);
        DialPanel backPPS=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("backplanepps"), backplanePPS, null, Color.BLUE,  new Color(0, 0, 127));
        backPPS.addGradientRanges(UIEnv.RANGE_1);
        backplanePPSText = backPPS.getTextAnnotation();

        dashs.add(backPPS);
        
        
        backplaneECNRate = new DefaultValueDataset(0);
        DialPanel ecnRate=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("backplaneecnrate"), backplaneECNRate, null, Color.BLUE, new Color(0, 0, 127));

        ecnRate.addGradientRanges(UIEnv.RANGE_3);

		backplaneECNRateText = ecnRate.getTextAnnotation();
        dashs.add(ecnRate);
        
        
		  backplaneLossRate = new DefaultValueDataset(0);
	        DialPanel lossRate1=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("backplanelossrate"), backplaneLossRate, null, Color.BLUE, new Color(0, 0, 127));

	        lossRate1.addGradientRanges(UIEnv.RANGE_4);
			backplaneLossRateText = lossRate1.getTextAnnotation();

        dashs.add(lossRate1);
    }

   

    

   

    /**
     * 创建地址信息面板
     */
    private void createAddressInfoPanel(JPanel parent) {
        JPanel panel_2x = new JPanel();
        panel_2x.setOpaque(false);
        parent.add(panel_2x);
        panel_2x.setLayout(new BorderLayout(0, 0));
        
        JLabel lblNewLabel = new JLabel(UIEnv.getRsb().getString("ipv6addr"));
        lblNewLabel.setFont(UIEnv.getFont().deriveFont(18.0f));
        lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
        panel_2x.add(lblNewLabel, BorderLayout.WEST);
        
        JPanel panel_2 = new JPanel();
        panel_2.setOpaque(false);
        panel_2x.add(panel_2, BorderLayout.CENTER);
        panel_2.setLayout(new BorderLayout(0, 0));
        
        addressField = new JTextField();
        addressField.setEditable(false);
        addressField.setHorizontalAlignment(SwingConstants.CENTER);
        addressField.setOpaque(false);
        addressField.setFont(UIEnv.getFont().deriveFont(18.0f));
        panel_2.add(addressField, BorderLayout.CENTER);
        addressField.setColumns(10);
        
        // 添加复制按钮
        JButton btnCopyAddress = new JButton(UIEnv.getRsb().getString("copy"));
        btnCopyAddress.addActionListener(e -> {
            Toolkit.getDefaultToolkit().getSystemClipboard()
                .setContents(new StringSelection(addressField.getText()), null);
        });
        panel_2.add(btnCopyAddress, BorderLayout.EAST);
    }

    /**
     * 创建ASN信息面板
     */
    private void createASNInfoPanel(JPanel parent) {
        JPanel panel_2x_1 = new JPanel();
        panel_2x_1.setOpaque(false);
        parent.add(panel_2x_1);
        panel_2x_1.setLayout(new BorderLayout(0, 0));
        
        JLabel lblNewLabel_1 = new JLabel(UIEnv.getRsb().getString("asnumber"));
        lblNewLabel_1.setFont(UIEnv.getFont().deriveFont(18.0f));
        panel_2x_1.add(lblNewLabel_1, BorderLayout.WEST);
        
        asnField2 = new JTextField();
        asnField2.setFont(UIEnv.getFont().deriveFont(18.0f));
        asnField2.setHorizontalAlignment(SwingConstants.CENTER);
        asnField2.setEditable(false);
        panel_2x_1.add(asnField2, BorderLayout.CENTER);
        asnField2.setColumns(10);
        
        // 添加复制按钮
        JButton btnCopyASN = new JButton(UIEnv.getRsb().getString("copy"));
        btnCopyASN.addActionListener(e -> {
            Toolkit.getDefaultToolkit().getSystemClipboard()
                .setContents(new StringSelection(asnField2.getText()), null);
        });
        panel_2x_1.add(btnCopyASN, BorderLayout.EAST);
    }

    /**
     * 创建在线设备面板
     */
    private void createOnlineDevicesPanel(JPanel parent) {
        JPanel panel = new JPanel();
        panel.setOpaque(false);
        panel.setBorder(new LineBorder(Color.GRAY));
        parent.add(panel);
        panel.setLayout(new BorderLayout(0, 0));
        
        JLabel jlb = new JLabel(UIEnv.getRsb().getString("onlinedevices"));
        jlb.setHorizontalAlignment(SwingConstants.CENTER);
        jlb.setFont(UIEnv.getFont().deriveFont(18.0f));
        panel.add(jlb, BorderLayout.WEST);
        
        devicesOnline = new JTextField();
        devicesOnline.setOpaque(false);
        devicesOnline.setHorizontalAlignment(SwingConstants.CENTER);
        devicesOnline.setFont(UIEnv.getFont().deriveFont(18.0f));
        devicesOnline.setEditable(false);
        panel.add(devicesOnline, BorderLayout.CENTER);
        devicesOnline.setColumns(10);
    }

    /**
     * 创建时间信息面板
     */
    private void createTimeInfoPanel(JPanel parent) {
        JPanel panel_5 = new JPanel();
        panel_5.setOpaque(false);
        panel_5.setBorder(new LineBorder(Color.GRAY));
        parent.add(panel_5,BorderLayout.NORTH);
        panel_5.setLayout(new BorderLayout(0, 0));
        
        JLabel jlb_1 = new JLabel(UIEnv.getRsb().getString("currenttime"));
        jlb_1.setHorizontalAlignment(SwingConstants.CENTER);
        jlb_1.setFont(jlb_1.getFont().deriveFont(18.0f));
        panel_5.add(jlb_1, BorderLayout.WEST);
        
        textFieldTime = new JTextField();
        textFieldTime.setOpaque(false);
        textFieldTime.setHorizontalAlignment(SwingConstants.CENTER);
        textFieldTime.setFont(textFieldTime.getFont().deriveFont(18.0f));
        textFieldTime.setEditable(false);
        textFieldTime.setColumns(10);
        panel_5.add(textFieldTime, BorderLayout.CENTER);
    }

    /**
     * 创建远程线路面板
     */
    private void createRemoteLinesPanel(KLALBController kc) {
        JPanel linesPanel = new JPanel();
        linesPanel.setOpaque(false);
        
        Icon icon2 = createIcon("/assets/ethnet.png", 15, 15);
        tabbedPane.addTab(UIEnv.getRsb().getString("remotelines"), icon2, linesPanel, null, false);
        linesPanel.setLayout(new BorderLayout());

        // 创建滚动面板
        ysp = new YScrollPane(CONST.itemwidth + 5);
        ysp.setOpaque(false);
        JPanel wv = ysp.getView();
        linesPanel.add(ysp, BorderLayout.CENTER);
        
        // 添加组件监听器
        wv.addComponentListener(new ComponentListener() {
            @Override
            public void componentShown(ComponentEvent e) {}

            @Override
            public void componentResized(ComponentEvent e) {}

            @Override
            public void componentMoved(ComponentEvent e) {
                repaint();
            }

            @Override
            public void componentHidden(ComponentEvent e) {}
        });

        // 创建顶部控制面板
        JPanel panel_1 = new JPanel();
        panel_1.setOpaque(false);
        linesPanel.add(panel_1, BorderLayout.NORTH);
        panel_1.setLayout(new BorderLayout(0, 0));

        // 线路地址输入框
        textField = new JTextField();
        panel_1.add(textField, BorderLayout.CENTER);
        textField.setColumns(10);
        textField.setToolTipText(UIEnv.getRsb().getString("lineaddressport"));

        // 添加线路按钮
        JButton btnNewButton = new JButton(UIEnv.getRsb().getString("addline"));
        btnNewButton.addActionListener(e -> {
            try {
              MultiProtocolSocketAddress mpsa=  new MultiProtocolSocketAddress(textField.getText());
              Thread t=new Thread(()->{
                  kc.addRemoteLines(mpsa);
              });
              t.start();
            } catch (RuntimeException ex) {
                JOptionPane.showMessageDialog(KLALBStateGUI3.this, "Input format error", "Error",
                        JOptionPane.ERROR_MESSAGE);
                ex.printStackTrace();
            }
        });
        panel_1.add(btnNewButton, BorderLayout.EAST);

        // 重连所有按钮
        JButton btnReconnect = new JButton(UIEnv.getRsb().getString("reconnectall"));
        btnReconnect.addActionListener(e -> kc.reconnectImmediately());
        panel_1.add(btnReconnect, BorderLayout.WEST);

        // 添加回车键监听
        textField.addKeyListener(createEnterKeyListener(btnNewButton));
    }

    /**
     * 创建设置面板
     */
    private void createSettingsPanel() {
        yspc = new YScrollPane(CONST.itemwidth + 5);
        yspc.setOpaque(false);
        JPanel configsPanel = new JPanel();
        configsPanel.setLayout(new BorderLayout(0, 0));
        configsPanel.add(yspc);
        
        // 添加设置项
        addSettingItems(yspc);
        
        // 添加保存按钮
        JButton btnSave = new JButton(UIEnv.getRsb().getString("savesettings"));
        btnSave.addActionListener(e -> saveConfig());
        yspc.add(btnSave, BorderLayout.SOUTH);
        
        Icon icon3 = createIcon("/assets/settings.png", 15, 15);
        tabbedPane.addTab(UIEnv.getRsb().getString("settings"), icon3, configsPanel, null, false);
        configsPanel.setOpaque(false);
    }

    /**
     * 创建菜单栏
     */
    private void createMenuBar() {
        JMenuBar menuBar = new JMenuBar();
        getContentPane().add(menuBar, BorderLayout.NORTH);

        JMenu mnNewMenu = new JMenu(UIEnv.getRsb().getString("monitor"));
        menuBar.add(mnNewMenu);

        showoffline = new JCheckBoxMenuItem(UIEnv.getRsb().getString("showofflines"));
        mnNewMenu.add(showoffline);
    }

    // ==================== 系统托盘初始化 ====================
    /**
     * 初始化系统托盘
     */
    private void initSystemTray() {
        if (SystemTray.isSupported()) {
            st = SystemTray.getSystemTray();
            ti = new TrayIcon(UIEnv.getIcon());
            ti.setImageAutoSize(true);
            
            // 创建弹出菜单
            PopupMenu jpm = new PopupMenu();
            
            // 打开菜单项
            MenuItem mix = new MenuItem("open");
            mix.addActionListener(e -> setVisible(true));
            jpm.add(mix);
            
            // 退出菜单项
            MenuItem mi = new MenuItem("exit");
            mi.addActionListener(e -> close());
            jpm.add(mi);
            
            ti.setPopupMenu(jpm);
            
            try {
                st.add(ti);
            } catch (AWTException e1) {
                e1.printStackTrace();
            }
            
            // 添加托盘图标点击事件
            ti.addActionListener(x -> setVisible(true));
        }
    }

    // ==================== 定时器初始化 ====================
    /**
     * 初始化定时器
     */
    private void initTimers(KLALBController kc) {
        t3 = new Timer("监视器刷新线程", true);
        t2 = new Timer("仪表盘刷新线程", true);
        t = new Timer("状态刷新线程", true);
        
        // 创建刷新任务
        createRefreshTask(kc, ysp);
    }

    // ==================== 事件监听器初始化 ====================
    /**
     * 初始化事件监听器
     */
    private void initEventListeners(KLALBController kc,JScrollPane jsp) {
        // 创建鼠标拖拽监听器
        MouseAdapter ma = new MouseAdapter() {
            private Point origin;

            @Override
            public void mousePressed(MouseEvent e) {
                origin = new Point(e.getPoint());
            }

            @Override
            public void mouseReleased(MouseEvent e) {}

            @Override
            public void mouseDragged(MouseEvent e) {
                if (origin != null) {
                    int deltaX = origin.x - e.getX();
                    int deltaY = origin.y - e.getY();

                    Rectangle view = jsp.getViewport().getVisibleRect();
					view.x += deltaX;
					view.y += deltaY;

					jsp.getViewport().scrollRectToVisible(view);
                }
            }
        };
        
        // 为网络图添加鼠标监听器
        graph.addMouseListener(ma);
        graph.addMouseMotionListener(ma);
    }

    // ==================== 设置项添加 ====================
    /**
     * 添加设置项到设置面板
     */
    private void addSettingItems(YScrollPane settings) {
    	  // UI设置标题
        SettingItem siui = new SettingItem(UIEnv.getRsb().getString("uisettings"), 
            UIEnv.getFont().deriveFont(20.0f).deriveFont(Font.BOLD), CONST.itemwidth, CONST.settingheight);
        settings.getView().add(siui);
    	
        // 语言设置
        ComboSettingItem lang = new ComboSettingItem(UIEnv.getRsb().getString("language"), 
            CONST.itemwidth, CONST.settingheight);
        comboLang = lang.getComboBox();
        comboLang.addItem(Language.EN_US);
        comboLang.addItem(Language.ZH_CN);
        settings.getView().add(lang);
        settings.updateScrool();
        
        CheckBoxSettingItem noguic = new CheckBoxSettingItem(UIEnv.getRsb().getString("nogui"), 
                CONST.itemwidth, CONST.settingheight);
        nogui=noguic.getCheckBox();
        settings.getView().add(noguic);
        
        // 虚拟网络设置标题
        SettingItem si = new SettingItem(UIEnv.getRsb().getString("virtualnetsettings"), 
            UIEnv.getFont().deriveFont(20.0f).deriveFont(Font.BOLD), CONST.itemwidth, CONST.settingheight);
        settings.getView().add(si);

        // IPv6地址设置
        TextButtonSettingItem addr6 = new TextButtonSettingItem(UIEnv.getRsb().getString("ipv6addr"), 
            CONST.itemwidth, CONST.settingheight);
        addr6.getButton().setText(UIEnv.getRsb().getString("random"));;
        addr6.getButton().addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				addr6.getTextField().setText(KLALBUtils.randomKLALBIPv6Address().toString());
			}
		});
        addressFieldSet = addr6.getTextField();
        settings.getView().add(addr6);

        // DNS服务器设置
        TextAreaSettingItem dns = new TextAreaSettingItem(UIEnv.getRsb().getString("dnsserver"), 
            CONST.itemwidth, CONST.settingheight * 5);
        dnsAreaSet = dns.getTextArea();
        settings.getView().add(dns);

        // ASN设置
        TextSettingItem asn = new TextSettingItem(UIEnv.getRsb().getString("asnumber"), 
            CONST.itemwidth, CONST.settingheight);
        asnFieldSet = asn.getTextField();
        settings.getView().add(asn);
        
        TextSettingItem tunName = new TextSettingItem(UIEnv.getRsb().getString("tunname"), 
                CONST.itemwidth, CONST.settingheight);
        tunDeviceName = tunName.getTextField();
            settings.getView().add(tunName);
        
        // 链接设置标题
        SettingItem six = new SettingItem(UIEnv.getRsb().getString("linksettings"), 
            UIEnv.getFont().deriveFont(20.0f).deriveFont(Font.BOLD), CONST.itemwidth, CONST.settingheight);
        settings.getView().add(six);
        
        // TCP监听设置
        TextSettingItem tcpl = new TextSettingItem(UIEnv.getRsb().getString("tcplistening"), 
            CONST.itemwidth, CONST.settingheight);
        tcpListeningSet = tcpl.getTextField();
        settings.getView().add(tcpl);

        // UDP监听设置
        TextSettingItem udpl = new TextSettingItem(UIEnv.getRsb().getString("udplistening"), 
            CONST.itemwidth, CONST.settingheight);
        udpListeningSet = udpl.getTextField();
        settings.getView().add(udpl);

        // 开放线路表设置
        TextAreaSettingItem olinet = new TextAreaSettingItem(UIEnv.getRsb().getString("openlinetable"), 
            CONST.itemwidth, CONST.settingheight * 5);
        openLineTabelSet = olinet.getTextArea();
        settings.getView().add(olinet);

        // 自动连接线路表设置
        TextAreaSettingItem clinet = new TextAreaSettingItem(UIEnv.getRsb().getString("autoconnectlinetable"), 
            CONST.itemwidth, CONST.settingheight * 5);
        connectLineTabelSet = clinet.getTextArea();
        settings.getView().add(clinet);

        // 网络接口排除设置
        nilsimdl = new XDefaultListModel<>();
        NetworkInterfaceListSettingItem nilsi = new NetworkInterfaceListSettingItem(
            UIEnv.getRsb().getString("networkinterfaceexcept"), CONST.itemwidth,
            CONST.settingheight * 5, nilsimdl);
        settings.getView().add(nilsi);
        
        linkConnectionsCount = new SliderSettingItem(UIEnv.getRsb().getString("linkconnectionscount"), 
                CONST.itemwidth, CONST.settingheight);
        linkConnectionsCount.getSlider().setMaximum(10);
        linkConnectionsCount.getSlider().setValue(1);
        linkConnectionsCount.getSlider().setMinimum(1);
        settings.getView().add(linkConnectionsCount);
        ChangeListener cons= new ChangeListener() {
			
			@Override
			public void stateChanged(ChangeEvent e) {
				int val=linkConnectionsCount.getSlider().getValue();
				linkConnectionsCount.getLabelx().setText(Integer.toString( val));
			}
		};
		cons.stateChanged(null);
		linkConnectionsCount.getSlider().addChangeListener(cons);
        
        // 时间同步设置标题
        SettingItem hit = new SettingItem(UIEnv.getRsb().getString("timesyncsettings"), 
            UIEnv.getFont().deriveFont(20.0f).deriveFont(Font.BOLD), CONST.itemwidth, CONST.settingheight);
        settings.getView().add(hit);
        
        // NTP服务器设置
        TextAreaSettingItem ntps = new TextAreaSettingItem(UIEnv.getRsb().getString("ntpservers"), 
            CONST.itemwidth, CONST.settingheight * 5);
        ntpServerSet = ntps.getTextArea();
        settings.getView().add(ntps);
        
        // 安全设置标题
        SettingItem shi = new SettingItem(UIEnv.getRsb().getString("securitysettings"), 
            UIEnv.getFont().deriveFont(20.0f).deriveFont(Font.BOLD), CONST.itemwidth, CONST.settingheight);
        settings.getView().add(shi);
        
        CheckBoxSettingItem denyQueryc = new CheckBoxSettingItem(UIEnv.getRsb().getString("denyaddrquery"), 
                CONST.itemwidth, CONST.settingheight);
        denyQuery=denyQueryc.getCheckBox();
        settings.getView().add(denyQueryc);
        

        CheckBoxSettingItem denyBroadcastc = new CheckBoxSettingItem(UIEnv.getRsb().getString("denyaddrbroadcast"), 
                CONST.itemwidth, CONST.settingheight);
        denyBroadcast=denyBroadcastc.getCheckBox();
        settings.getView().add(denyBroadcastc);
        
        //性能设置标题

        SettingItem pshi = new SettingItem(UIEnv.getRsb().getString("performancesettings"), 
            UIEnv.getFont().deriveFont(20.0f).deriveFont(Font.BOLD), CONST.itemwidth, CONST.settingheight);
        settings.getView().add(pshi);
        
        
        performanceStrategy = new ComboSettingItem(UIEnv.getRsb().getString("performancestrategy"), 
                CONST.itemwidth, CONST.settingheight);
        comboPerformance = performanceStrategy.getComboBox();
        comboPerformance.addItem(new PerformanceStrategyItem(PerformanceStrategy.SINGLE_CORE));
        comboPerformance.addItem(new PerformanceStrategyItem(PerformanceStrategy.MULTI_FILL));
        comboPerformance.addItem(new PerformanceStrategyItem(PerformanceStrategy.MULTI_SCATTER));
        comboPerformance.setSelectedIndex(1);
            settings.getView().add(performanceStrategy);
        
        
        // 高级设置标题
        SettingItem hi = new SettingItem(UIEnv.getRsb().getString("advancedsettings"), 
            UIEnv.getFont().deriveFont(20.0f).deriveFont(Font.BOLD), CONST.itemwidth, CONST.settingheight);
        settings.getView().add(hi);

        nagleDelayTime = new SliderSettingItem(UIEnv.getRsb().getString("transmitnagledelaytime"), 
                CONST.itemwidth, CONST.settingheight);
        nagleDelayTime.getSlider().setMaximum(100);
        nagleDelayTime.getSlider().setValue(10);
        settings.getView().add(nagleDelayTime);
        ChangeListener clhs= new ChangeListener() {
			
			@Override
			public void stateChanged(ChangeEvent e) {
				int val=nagleDelayTime.getSlider().getValue();
				nagleDelayTime.getLabelx().setText(String.format("%.2f",val/10.0));
			}
		};
		clhs.stateChanged(null);
		nagleDelayTime.getSlider().addChangeListener(clhs);
		
		
		linkNagleDelayTime = new SliderSettingItem(UIEnv.getRsb().getString("linknagledelaytime"), 
                CONST.itemwidth, CONST.settingheight);
		linkNagleDelayTime.getSlider().setMaximum(100);
		linkNagleDelayTime.getSlider().setValue(10);
        settings.getView().add(linkNagleDelayTime);
        ChangeListener clhse= new ChangeListener() {
			
			@Override
			public void stateChanged(ChangeEvent e) {
				int val=linkNagleDelayTime.getSlider().getValue();
				linkNagleDelayTime.getLabelx().setText(String.format("%.2f",val/10.0));
			}
		};
		clhse.stateChanged(null);
		linkNagleDelayTime.getSlider().addChangeListener(clhse);
        
        congestions = new ComboSettingItem(UIEnv.getRsb().getString("congresscontrolalgorithm"), 
            CONST.itemwidth, CONST.settingheight);
        comboCongestion = congestions.getComboBox();
        comboCongestion.addItem("BBR");
        comboCongestion.addItem("Vegas2");
        settings.getView().add(congestions);
        settings.updateScrool();
        
        burstLimit= new SliderSettingItem(UIEnv.getRsb().getString("burstlimit"), 
                CONST.itemwidth, CONST.settingheight);
        burstLimit.getSlider().setMaximum(1000);
        burstLimit.getSlider().setValue(200);
        settings.getView().add(burstLimit);
        
        delayHbound = new SliderSettingItem(UIEnv.getRsb().getString("delayupperbound"), 
                CONST.itemwidth, CONST.settingheight);
        delayHbound.getSlider().setMaximum(300);
        delayHbound.getSlider().setValue(200);
        settings.getView().add(delayHbound);
        

        delayLbound = new SliderSettingItem(UIEnv.getRsb().getString("delaylowerbound"), 
                CONST.itemwidth, CONST.settingheight);
        delayLbound.getSlider().setMaximum(300);
        delayLbound.getSlider().setValue(150);
        settings.getView().add(delayLbound);
        
        ChangeListener clb= new ChangeListener() {
			
			@Override
			public void stateChanged(ChangeEvent e) {
				int val=burstLimit.getSlider().getValue();
				burstLimit.getLabelx().setText(String.format("%.3f",1.0+val/1000.0));
			}
		};
		clb.stateChanged(null);
		burstLimit.getSlider().addChangeListener(clb);
        
        ChangeListener clh= new ChangeListener() {
			
			@Override
			public void stateChanged(ChangeEvent e) {
				int val=delayHbound.getSlider().getValue();
				if(val<delayLbound.getSlider().getValue()) {
					delayLbound.getSlider().setValue(val);
				}
				delayHbound.getLabelx().setText(String.format("%.3f",1.0+val/1000.0));
			}
		};
		clh.stateChanged(null);
        delayHbound.getSlider().addChangeListener(clh);
        ChangeListener cll=new ChangeListener() {
			
			@Override
			public void stateChanged(ChangeEvent e) {
				int val=delayLbound.getSlider().getValue();
				if(val>delayHbound.getSlider().getValue()) {
					delayHbound.getSlider().setValue(val);
				}
				delayLbound.getLabelx().setText(String.format("%.3f",1.0+val/1000.0));
			}
		};
		cll.stateChanged(null);
        delayLbound.getSlider().addChangeListener(cll);
    }

    // ==================== 配置保存方法 ====================
    /**
     * 保存配置到文件
     */
    private void saveConfig() {
        if (config == null) {
            config = new KLALBConfig();
            config.add(new KLALBControllerConfigItem());
        }
        
        for (KLALBConfigItem item : config) {
            if (item instanceof KLALBControllerConfigItem) {
                KLALBControllerConfigItem kck = (KLALBControllerConfigItem) item;
                
                // 保存语言设置
                kck.setLanguage(((Language) comboLang.getSelectedItem()).name());
                
                kck.setNogui(nogui.isSelected());
                
                // 保存IPv6地址
                String ttext = addressFieldSet.getText().trim();
                if (ttext.equals("")) {
                    kck.setVirtualAddress(null);
                } else {
                    try {
                        kck.setVirtualAddress(Inet6Address.getByName(ttext).getHostAddress());
                    } catch (UnknownHostException e1) {
                        e1.printStackTrace();
                        JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("invaildipv6addr"), 
                            UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
                        return;
                    }
                }
                
                // 保存DNS服务器列表
                String[] splt = dnsAreaSet.getText().split("\n");
                List<InetAddress> iaddr = new ArrayList<>();
                boolean show = true;
                for (String str : splt) {
                    try {
                        str = str.trim();
                        if (!str.isEmpty())
                            iaddr.add(Inet6Address.getByName(str));
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                        if (show) {
                            show = false;
                            JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("invailddnsserver"), 
                                UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
                            return;
                        }
                    }
                }
                kck.setDNS(iaddr);
                
                // 保存ASN
                String asntext = asnFieldSet.getText();
                if (asntext.equals("")) {
                    kck.setVirtualASN(null);
                } else {
                    try {
                        kck.setVirtualASN(Long.parseLong(asntext));
                    } catch (NumberFormatException e) {
                        e.printStackTrace();
                        JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("invaildasnumber"), 
                            UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
                        return;
                    }
                }
                
                String tunNameText=tunDeviceName.getText();
                if(tunNameText.equals("")) {
                	kck.setTUNName(null);
                }else {
                	kck.setTUNName(tunNameText);
                }
                
                // 保存TCP监听设置
                String tcptext = tcpListeningSet.getText();
                if (tcptext.equals("")) {
                    kck.setTCPListen(null);
                } else {
                    try {
                        kck.setTCPListen(new MultiProtocolSocketAddress(tcptext));
                    } catch (RuntimeException e) {
                        e.printStackTrace();
                        JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("invaildtcplisten"), 
                            UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
                        return;
                    }
                }
                
                // 保存UDP监听设置
                String udptext = udpListeningSet.getText();
                if (udptext.equals("")) {
                    kck.setUDPListen(null);
                } else {
                    try {
                        kck.setUDPListen(new MultiProtocolSocketAddress(udptext,"udp"));
                    } catch (RuntimeException e) {
                        e.printStackTrace();
                        JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("invaildudplisten"), 
                            UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
                        return;
                    }
                }
                
                // 保存开放线路表
                String[] splt1 = openLineTabelSet.getText().split("\n");
                List<MultiProtocolSocketAddress> iaddr1 = new ArrayList<>();
                boolean show1 = true;
                for (String str : splt1) {
                    try {
                        str = str.trim();
                        if (!str.isEmpty())
                            iaddr1.add(new MultiProtocolSocketAddress(str));
                    } catch (RuntimeException e) {
                        e.printStackTrace();
                        if (show1) {
                            show1 = false;
                            JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("invaildopenlinetable"), 
                                UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
                            return;
                        }
                    }
                }
                kck.setLineTable(iaddr1);
                
                // 保存自动连接线路表
                String[] splt11 = connectLineTabelSet.getText().split("\n");
                List<MultiProtocolSocketAddress> iaddr11 = new ArrayList<>();
                boolean show11 = true;
                for (String str : splt11) {
                    try {
                        str = str.trim();
                        if (!str.isEmpty())
                            iaddr11.add(new MultiProtocolSocketAddress(str));
                    } catch (RuntimeException e) {
                        e.printStackTrace();
                        if (show11) {
                            show11 = false;
                            JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("invaildconnectlinetable"), 
                                UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
                            return;
                        }
                    }
                }
                kck.setConnectLineTable(iaddr11);
                
                // 保存NTP服务器表
                String[] splt111 = ntpServerSet.getText().split("\n");
                List<MultiProtocolSocketAddress> iaddr111 = new ArrayList<>();
                boolean show111 = true;
                for (String str : splt111) {
                    try {
                        str = str.trim();
                        if (!str.isEmpty())
                            iaddr111.add(new MultiProtocolSocketAddress(str,"ntp"));
                    } catch (RuntimeException e) {
                        e.printStackTrace();
                        if (show111) {
                            show111 = false;
                            JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("invaildntpservertable"), 
                                UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
                            return;
                        }
                    }
                }
                kck.setNtpServerTable(iaddr111);
                
                // 保存网络接口排除列表
                List<String> nie = new ArrayList<>();
                for (int i = 0; i < nilsimdl.getSize(); i++) {
                    nie.add(nilsimdl.getElementAt(i).getName());
                }
                kck.setNetworkInterfaceExcepts(nie);

                kck.setLinkConnectionsCount(linkConnectionsCount.getSlider().getValue());
                
                kck.setDenyLineTableQuery(denyQuery.isSelected());
                
                kck.setDenyLineTableBroadcast(denyBroadcast.isSelected());

                PerformanceStrategyItem psi=((PerformanceStrategyItem)comboPerformance.getSelectedItem());
                if(psi!=null) {
                    kck.setPerformanceStrategy(psi.getStrategy().toString());
                }

                kck.setCongestionAlgorithm((String) congestions.getComboBox().getSelectedItem());

                kck.setBurstLimit(1.0+burstLimit.getSlider().getValue()/1000.0);
                
                kck.setDelayUpperBound(1.0+delayHbound.getSlider().getValue()/1000.0);

                kck.setDelayLowerBound(1.0+delayLbound.getSlider().getValue()/1000.0);
                
                kck.setNagleDelayTime(nagleDelayTime.getSlider().getValue()*100000L);
                
                kck.setLinkNagleDelayTime(linkNagleDelayTime.getSlider().getValue()*100000L);
            }
        }
        
        // 调用保存回调
        if (saveComsumer != null) {
            saveComsumer.accept(config);
            JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("saveconfigsuccess"));
        }
    }

    // ==================== 刷新任务创建 ====================
    /**
     * 创建刷新任务
     */
    private void createRefreshTask(KLALBController kc, YScrollPane ysp) {
        // 线路状态刷新任务
        if (tsk != null) {
            tsk.cancel();
        }
        tsk = new TimerTask() {
            @Override
            public void run() {
                if (isVisible()) {
                    Object[] kll = kc.getLines().toArray();

                    // 遍历所有线路，更新或添加TPanel2
                    for (Object obj : kll) {
                        IPv6NetworkLink link = (IPv6NetworkLink) obj;
                        if (!(link instanceof KLALBRemoteLink)) {
                            continue;
                        }
                        KLALBRemoteLink ent = (KLALBRemoteLink) link;

                        Component[] count = ysp.getView().getComponents();
                        boolean found = false;

                        // 查找是否已有对应线路的面板
                        for (Component tp : count) {
                            if (tp instanceof TPanel2) {
                                if (((TPanel2) tp).getTunnel().equals(ent)) {
                                    tp.setVisible(showoffline.isSelected() || (
                                            ent.getState() != LinkStatus.DOWN));
                                    found = true;
                                    break;
                                }
                            }
                        }

                        // 如果没有找到，创建新面板
                        if (!found) {
                            TPanel2 tp = new TPanel2(ent, kc);
                            tp.setVisible(showoffline.isSelected() || (
                                    ent.getState() != LinkStatus.DOWN));
                            ysp.getView().add(tp);
                        }
                    }

                    // 更新所有面板并移除不存在的线路
                    Component[] count = ysp.getView().getComponents();
                    for (Component tp : count) {
                        if (tp instanceof TPanel2) {
                            if (kc.getLines().contains(((TPanel2) tp).getTunnel())) {
                                try {
                                    if (tp.isVisible())
                                        ((TPanel2) tp).updateTraffic();
                                } catch (RuntimeException e) {
                                    e.printStackTrace();
                                }
                            } else {
                                ysp.getView().remove(tp);
                            }
                        }
                    }

                    ysp.updateScrool();
                }
            }
        };
        t.scheduleAtFixedRate(tsk, 1000, 1000);

        // 仪表盘数据刷新任务
        if (tsk2 != null) {
            tsk2.cancel();
        }
        tsk2 = new TimerTask() {
            @Override
            public void run() {
                if (isVisible()) {
                    updateDashboardData(kc);
                }
            }
        };
        t2.scheduleAtFixedRate(tsk2, 100, 100);

        // 网络图刷新任务
        if (tsk5 != null) {
            tsk5.cancel();
        }
        tsk5 = new TimerTask() {
            @Override
            public void run() {
                if (isVisible()) {
                    graph.loadNodes();
                    for (int i = 0; i < 100; i++) {
                        graph.runPhy();
                    }
                    graph.repaint();
                    graph.revalidate();
                }
            }
        };
        t.scheduleAtFixedRate(tsk5, 1000, 1000);
    }

    /**
     * 更新仪表盘数据
     */
    private void updateDashboardData(KLALBController kc) {
        // 更新上行速度
        double outload = kc.getLinkMonitor().getOutSpeed() * 100.0 / kc.getLinkMonitor().getOutSpeedMax();
        if (Double.isFinite(outload)) {
            upSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getOutSpeed()) + "/s");
            upSpeed.setValue(Math.min(upSpeed.getValue().doubleValue() * 0.98 + outload * 0.02, 101.0));
        }

        // 更新下行速度
        double inload = kc.getLinkMonitor().getInSpeed() * 100.0 / kc.getLinkMonitor().getInSpeedMax();
        if (Double.isFinite(inload)) {
            downSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getInSpeed()) + "/s");
            downSpeed.setValue(Math.min(downSpeed.getValue().doubleValue() * 0.98 + inload * 0.02, 101.0));
        }

        // 更新上行包速率
        double outPPSload = kc.getLinkMonitor().getOutPPS() * 100.0 / kc.getLinkMonitor().getOutPPSMax();
        if (Double.isFinite(outPPSload)) {
            upPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getOutPPS()) + "PPS");
            upPPS.setValue(Math.min(upPPS.getValue().doubleValue() * 0.98 + outPPSload * 0.02, 101.0));
        }

        // 更新下行包速率
        double inPPSload = kc.getLinkMonitor().getInPPS() * 100.0 / kc.getLinkMonitor().getInPPSMax();
        if (Double.isFinite(inPPSload)) {
            downPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getInPPS()) + "PPS");
            downPPS.setValue(Math.min(downPPS.getValue().doubleValue() * 0.98 + inPPSload * 0.02, 101.0));
        }

        // 更新上行数据速度
        double outload1 = kc.getDatatMonitor().getOutSpeed() * 100.0 / kc.getLinkMonitor().getOutSpeedMax();
        if (Double.isFinite(outload1)) {
            upDataSpeed.setValue(Math.min(upDataSpeed.getValue().doubleValue() * 0.98 + outload1 * 0.02, 101.0));
        }

        // 更新下行数据速度
        double inload1 = kc.getDatatMonitor().getInSpeed() * 100.0 / kc.getLinkMonitor().getInSpeedMax();
        if (Double.isFinite(inload1)) {
            downDataSpeed.setValue(Math.min(downDataSpeed.getValue().doubleValue() * 0.98 + inload1 * 0.02, 101.0));
        }

        // 更新上行数据包速率
        double outPPSload1 = kc.getDatatMonitor().getOutPPS() * 100.0 / kc.getLinkMonitor().getOutPPSMax();
        if (Double.isFinite(outPPSload1)) {
            upDataPPS.setValue(Math.min(upDataPPS.getValue().doubleValue() * 0.98 + outPPSload1 * 0.02, 101.0));
        }

        // 更新下行数据包速率
        double inPPSload1 = kc.getDatatMonitor().getInPPS() * 100.0 / kc.getLinkMonitor().getInPPSMax();
        if (Double.isFinite(inPPSload1)) {
            downDataPPS.setValue(Math.min(downDataPPS.getValue().doubleValue() * 0.98 + inPPSload1 * 0.02, 101.0));
        }

       SRv6Router router=  kc.getIpv6Router();
       if(router!=null) {
    	   // 更新背板延迟
           double backplaneTimev = router.getBackplaneTime()* 100.0/100000.0;
           if (Double.isFinite(backplaneTimev)) {
               backplaneDelayText.setLabel(KLALBUtils.convertUintNanoDefalut(router.getBackplaneTime()) + "s");
               backplaneDelay.setValue(Math.min(backplaneDelay.getValue().doubleValue() * 0.98 + backplaneTimev * 0.02, 101.0));
           }

           // 更新背板转发率
           double backplanePPSv = router.getBackplanePPS() * 100.0 / router.getBackplanePPSMax();
           if (Double.isFinite(backplanePPSv)) {
               backplanePPSText.setLabel(KLALBUtils.convertUintDefalut(router.getBackplanePPS()) + "PPS");
               backplanePPS.setValue(Math.min(backplanePPS.getValue().doubleValue() * 0.98 + backplanePPSv * 0.02, 101.0));
           }
           
           // 更新背板ECN率
           double backplaneECNv = router.getECNRate() * 100.0 ;
           if (Double.isFinite(backplaneECNv)) {
               backplaneECNRateText.setLabel(String.format("%.1f",backplaneECNv) + "%");
               backplaneECNRate.setValue(Math.min(backplaneECNRate.getValue().doubleValue() * 0.98 + backplaneECNv * 0.02, 101.0));
           }
           
        // 更新背板ECN率
           double backplaneLossv = router.getLossRate() * 100.0 ;
           if (Double.isFinite(backplaneLossv)) {
               backplaneLossRateText.setLabel(String.format("%.1f",backplaneLossv) + "%");
               backplaneLossRate.setValue(Math.min(backplaneLossRate.getValue().doubleValue() * 0.98 + backplaneLossv * 0.02, 101.0));
           }
       }
        
        // 更新在线设备数
        String contt = Long.toString(kc.getIpv6Router().getKlalbRouteProtol().getDevicesFound());
        if (!contt.equals(devicesOnline.getText())) {
            devicesOnline.setText(contt);
        }

        // 更新IP地址显示
        String address = kc.getSelf().getAddress().toString();
        if (!address.equals(addressField.getText())) {
            addressField.setText(address);
        }
/*
        // 更新ASN显示
        String asnstr = Long.toString(kc.getIpv6Router().getASN());
        if (!asnstr.equals(asnField2.getText())) {
            asnField2.setText(asnstr);
        }
*/
        // 更新时间显示
        HighAccuracyClock hac = kc.getClock();
        long delta = hac.getFrequency() - 1000000000;
        double ppm = delta / 1000.0;
        String ppmstr = String.format("%.2f", ppm);
        if (delta > 0) {
            ppmstr = "+" + ppmstr;
        }
        textFieldTime.setText(hac.toString2() + " " + ppmstr + "ppm");
    }

    // ==================== 配置加载方法 ====================
    /**
     * 加载配置文件
     */
    public void loadConfig(KLALBConfig config) {
        this.config = config;
        for (KLALBConfigItem item : config) {
            if (item instanceof KLALBControllerConfigItem) {
                KLALBControllerConfigItem kck = (KLALBControllerConfigItem) item;
                
                // 加载语言设置
                String lg = kck.getLanguage();
                if (lg != null) {
                    Language l = Language.valueOf(lg);
                    if (l != null) {
                        comboLang.setSelectedItem(l);
                    }
                }
                
                nogui.setSelected( kck.isNogui());
                
                // 加载IPv6地址
                String vaddr = kck.getVirtualAddress();
                addressFieldSet.setText(vaddr != null ? vaddr : "");
                
                // 加载DNS服务器
                List<InetAddress> dns = kck.getDNS();
                dnsAreaSet.setText(listToStr(dns));
                
                // 加载ASN
                Long vasn = kck.getVirtualASN();
                asnFieldSet.setText(vasn != null ? vasn.toString() : "");
                
                String tunname=kck.getTUNName();
                tunDeviceName.setText(tunname!=null?tunname:"");
                
                // 加载TCP监听
                MultiProtocolSocketAddress mpat = kck.getTCPListen();
                tcpListeningSet.setText(mpat != null ? mpat.toString() : "");
                
                // 加载UDP监听
                MultiProtocolSocketAddress mpau = kck.getUDPListen();
                udpListeningSet.setText(mpau != null ? mpau.toString() : "");
                
                // 加载开放线路表
                List<MultiProtocolSocketAddress> linet = kck.getLineTable();
                openLineTabelSet.setText(listToStr2(linet));
                
                // 加载自动连接线路表
                List<MultiProtocolSocketAddress> clinet = kck.getConnectLineTable();
                connectLineTabelSet.setText(listToStr2(clinet));
                
                // 加载NTP服务器表
                List<MultiProtocolSocketAddress> ntps = kck.getNtpServerTable();
                ntpServerSet.setText(listToStr2(ntps));
                
                // 加载网络接口排除列表
                List<String> strexc = kck.getNetworkInterfaceExcepts();
                nilsimdl.clear();
                if (strexc != null) {
                    for (String strexci : strexc) {
                        try {
                            nilsimdl.addElement(NetworkInterface.getByName(strexci));
                        } catch (SocketException e) {
                            e.printStackTrace();
                        }
                    }
                }
                int conc=kck.getLinkConnectionsCount();
                if(conc<=0) {
                	conc=1;
                }
                linkConnectionsCount.getSlider().setValue(conc);
                
                denyQuery.setSelected( kck.isDenyLineTableQuery());

                denyBroadcast.setSelected( kck.isDenyLineTableBroadcast());

               String stategy= kck.getPerformanceStrategy();
               PerformanceStrategy pfs=PerformanceStrategy.fromDescription(stategy);
            if(pfs!=null) {
                for (int i=0;i<comboPerformance.getItemCount();i++){
                    if(((PerformanceStrategyItem)comboPerformance.getModel().getElementAt(i)).getStrategy().equals(pfs)) {
                        comboPerformance.setSelectedIndex(i);
                        break;
                    }
                }
                }

                String con=kck.getCongestionAlgorithm();
                if(con==null) {
                congestions.getComboBox().setSelectedItem("BBR");
                }else {
                    congestions.getComboBox().setSelectedItem(con);
                }
                double ubb=kck.getBurstLimit();
                if(ubb!=0)
                    burstLimit.getSlider().setValue((int) Math.round((ubb-1.0)*1000));
                
                double ub=kck.getDelayUpperBound();
                if(ub!=0)
                delayHbound.getSlider().setValue((int) Math.round((ub-1.0)*1000));
                
                double lb=kck.getDelayLowerBound();
                if(lb!=0)
                delayLbound.getSlider().setValue((int) Math.round ((lb-1.0)*1000));
                
                long del=kck.getNagleDelayTime();
                nagleDelayTime.getSlider().setValue((int)(del/100000L));
                
                long delr=kck.getLinkNagleDelayTime();
                linkNagleDelayTime.getSlider().setValue((int)(delr/100000L));
            }
        }
    }

    // ==================== 辅助方法 ====================
    /**
     * 创建图标
     */
    private Icon createIcon(String path, int width, int height) {
        try {
            Image img = ImageIO.read(KLALBStateGUI3.class.getResourceAsStream(path));
            return new ImageIcon(img.getScaledInstance(width, height, Image.SCALE_SMOOTH));
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 创建回车键监听器
     */
    private KeyListener createEnterKeyListener(JButton button) {
        return new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {}

            @Override
            public void keyReleased(KeyEvent e) {}

            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    button.doClick();
                }
            }
        };
    }

    /**
     * 将InetAddress列表转换为字符串
     */
    private String listToStr(List<InetAddress> list) {
        StringBuilder sbdr = new StringBuilder();
        if (list != null) {
            for (InetAddress addr : list) {
                sbdr.append(addr.getHostAddress());
                sbdr.append('\n');
            }
        }
        return sbdr.toString();
    }

    /**
     * 将对象列表转换为字符串
     */
    private String listToStr2(List<?> list) {
        StringBuilder sbdr = new StringBuilder();
        if (list != null) {
            for (Object obj : list) {
                sbdr.append(obj);
                sbdr.append('\n');
            }
        }
        return sbdr.toString();
    }

    // ==================== 公开方法 ====================
    /**
     * 获取保存配置的回调函数
     */
    public Consumer<KLALBConfig> getSaveComsumer() {
        return saveComsumer;
    }

    /**
     * 设置保存配置的回调函数
     */
    public void setSaveComsumer(Consumer<KLALBConfig> saveComsumer) {
        this.saveComsumer = saveComsumer;
    }

    /**
     * 添加节点信息面板到标签页
     */
    public void addNodeInformationPanel(NodeInformationPanel panel) {
        tabbedPane.addTab(panel.getAddress().toString(), panel.getIcon(), panel, null, true);
        tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
    }

    /**
     * 关闭窗口并清理资源
     */
    public void close() {
        setVisible(false);
        if (tsk != null) {
            tsk.cancel();
        }
        if (st != null) {
            st.remove(ti);
        }
    }

    // ==================== 主方法（测试用） ====================
    /**
     * 主方法，用于测试
     */
    public static void main(String[] args) throws IOException, InterruptedException {
        KLALBStateGUI3 kcg = new KLALBStateGUI3(new KLALBController());
        kcg.setVisible(true);
    }
}