using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WpfApp1.Structure;
using WpfApp1.Tools;
using static System.Formats.Asn1.AsnWriter;
using System.Xml.Linq;
using Emgu.CV.Structure;
using Emgu.CV;
using Emgu.CV.Util;
//using System.Drawing;
using Microsoft.Win32;
using System.IO;
using System.Text.Json;
using System.Windows.Media.Media3D;
using System.Diagnostics;
using System.Security.Cryptography.Xml;
using System.Windows.Controls.Primitives;
using static Emgu.Util.Platform;
using static System.Net.Mime.MediaTypeNames;
using System.Windows.Threading;
using System.Text.RegularExpressions;
using Emgu.CV.CvEnum;
using PDollarGestureRecognizer;
using System.Threading;
using System.Data;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private void SendTest()
        {
            string text0 = tb_input.Text;
            if (cb_model.SelectedItem is ComboBoxItem selectedItem)
            {
                string text = tb_input.Text;
                int index = text.IndexOf("[file:");
                if (index != -1)
                {
                    text = text.Substring(0, index - 1);
                }
                tb_input.Text = "";

                StackPanel stackPanel = new StackPanel
                {
                    Orientation = System.Windows.Controls.Orientation.Horizontal,
                    HorizontalAlignment = HorizontalAlignment.Right,
                    Margin = new Thickness(5),
                };
                ContentControl contentControl = new ContentControl
                {
                    MaxWidth = 300,
                    Template = (ControlTemplate)FindResource("RightBubble")
                };
                TextBlock textBlock = new TextBlock
                {
                    TextWrapping = TextWrapping.Wrap,
                    Padding = new Thickness(10, 5, 10, 5),
                    Text = text
                };
                contentControl.Content = textBlock;
                var symbolIcon = new Wpf.Ui.Controls.SymbolIcon
                {
                    Symbol = Wpf.Ui.Controls.SymbolRegular.Person20,
                    Filled = true,
                    VerticalAlignment = VerticalAlignment.Top,
                    Margin = new Thickness(0, 6, 0, 0),
                };
                stackPanel.Children.Add(contentControl);
                stackPanel.Children.Add(symbolIcon);

                sp_dialog.Children.Add(stackPanel);
                //sp_dialog.Dispatcher.Invoke(() => { }, DispatcherPriority.ContextIdle);
            }

            if (text0.StartsWith("This"))
            {
                sp_dialog.Dispatcher.Invoke(() => { }, DispatcherPriority.ContextIdle);
                Thread.Sleep(1056);
                StackPanel stackPanel = new StackPanel
                {
                    Orientation = System.Windows.Controls.Orientation.Horizontal,
                    HorizontalAlignment = HorizontalAlignment.Right,
                    Margin = new Thickness(5),
                };
                ContentControl contentControl = new ContentControl
                {
                    //MaxWidth = 300,
                    Template = (ControlTemplate)FindResource("RightBubble"),
                };
                System.Windows.Controls.Image image = new System.Windows.Controls.Image
                {
                    Width = 280,
                    Height = 227,
                    Margin = new Thickness(10),
                    VerticalAlignment = VerticalAlignment.Center,
                    Source = new BitmapImage(new Uri(basePath + "Jeju.png"))
                };
                contentControl.Content = image;
                stackPanel.Children.Add(contentControl);
                sp_dialog.Children.Add(stackPanel);

                //sp_dialog.Dispatcher.Invoke(() => { }, DispatcherPriority.ContextIdle);
            }
            if (text0.StartsWith("This"))
            {
                sp_dialog.Dispatcher.Invoke(() => { }, DispatcherPriority.ContextIdle);
                Thread.Sleep(3756);

                StackPanel stackPanel = new StackPanel
                {
                    Orientation = System.Windows.Controls.Orientation.Horizontal,
                    HorizontalAlignment = HorizontalAlignment.Left,
                    Margin = new Thickness(5),
                };
                ContentControl contentControl = new ContentControl
                {
                    MaxWidth = 300,
                    Template = (ControlTemplate)FindResource("LeftBubble")
                };
                TextBlock textBlock = new TextBlock
                {
                    TextWrapping = TextWrapping.Wrap,
                    Padding = new Thickness(10, 5, 10, 5),
                };
                textBlock.Inlines.Add(new Run("Certainly! Here's a set of itineraries starting and ending at Jeju Airport, focusing on parks, waterfalls, museums, and beaches."));
                textBlock.Inlines.Add(new LineBreak());
                textBlock.Inlines.Add(new Run { Text = "Short Route", FontWeight = FontWeights.Bold });
                textBlock.Inlines.Add(new LineBreak());
                textBlock.Inlines.Add(new Run("Jeju Airport-->Mt. Hallasan National Park-->Jeongbang Falls-->Jungmun Beach-->O'sulloc Tea Museum-->Jeju Airport"));
                textBlock.Inlines.Add(new LineBreak());
                textBlock.Inlines.Add(new Run { Text = "Medium Route", FontWeight = FontWeights.Bold });
                textBlock.Inlines.Add(new LineBreak());
                textBlock.Inlines.Add(new Run("Jeju Airport-->Mt. Hallasan National Park-->Jeongbang Falls-->Jeju Folk Village Museum-->Seongeup Folk Village-->Shinyang Beach-->Jeju Airport"));
                textBlock.Inlines.Add(new LineBreak());
                textBlock.Inlines.Add(new Run { Text = "Medium Route", FontWeight = FontWeights.Bold });
                textBlock.Inlines.Add(new LineBreak());
                textBlock.Inlines.Add(new Run("Jeju Airport-->Mt. Hallasan National Park-->Jeongbang Falls-->Jungmun Beach-->O'sulloc Tea Museum-->Bunjae Artpia-->Biyangdo Is.-->Hallim Park-->Jeju Airport"));
                contentControl.Content = textBlock;
                var symbolIcon = new Wpf.Ui.Controls.SymbolIcon
                {
                    Symbol = Wpf.Ui.Controls.SymbolRegular.Bot20,
                    Filled = true,
                    VerticalAlignment = VerticalAlignment.Top,
                    Margin = new Thickness(0, 6, 0, 0),
                };
                stackPanel.Children.Add(symbolIcon);
                stackPanel.Children.Add(contentControl);

                sp_dialog.Children.Add(stackPanel);
            }
            if (text0.StartsWith("This"))
            {
                StackPanel stackPanel = new StackPanel
                {
                    Orientation = System.Windows.Controls.Orientation.Horizontal,
                    HorizontalAlignment = HorizontalAlignment.Left,
                    Margin = new Thickness(5),
                };
                ContentControl contentControl = new ContentControl
                {
                    //MaxWidth = 300,
                    Template = (ControlTemplate)FindResource("LeftBubble"),
                };
                System.Windows.Controls.Image image = new System.Windows.Controls.Image
                {
                    Width = 280,
                    Height = 227,
                    Margin = new Thickness(10),
                    VerticalAlignment = VerticalAlignment.Center,
                    Source = new BitmapImage(new Uri(basePath + "Jeju2.png"))
                };
                contentControl.Content = image;
                stackPanel.Children.Add(contentControl);
                sp_dialog.Children.Add(stackPanel);
            }
            if (text0.StartsWith("I"))
            {
                sp_dialog.Dispatcher.Invoke(() => { }, DispatcherPriority.ContextIdle);
                Thread.Sleep(3256);

                StackPanel stackPanel = new StackPanel
                {
                    Orientation = System.Windows.Controls.Orientation.Horizontal,
                    HorizontalAlignment = HorizontalAlignment.Left,
                    Margin = new Thickness(5),
                };
                ContentControl contentControl = new ContentControl
                {
                    MaxWidth = 300,
                    Template = (ControlTemplate)FindResource("LeftBubble")
                };
                TextBlock textBlock = new TextBlock
                {
                    TextWrapping = TextWrapping.Wrap,
                    Padding = new Thickness(10, 5, 10, 5),
                };
                textBlock.Inlines.Add(new Run("Sure! Here's a simple travel guide for the attractions on Jeju Island."));
                contentControl.Content = textBlock;
                var symbolIcon = new Wpf.Ui.Controls.SymbolIcon
                {
                    Symbol = Wpf.Ui.Controls.SymbolRegular.Bot20,
                    Filled = true,
                    VerticalAlignment = VerticalAlignment.Top,
                    Margin = new Thickness(0, 6, 0, 0),
                };
                stackPanel.Children.Add(symbolIcon);
                stackPanel.Children.Add(contentControl);

                sp_dialog.Children.Add(stackPanel);
            }
            if (text0.StartsWith("I"))
            {
                StackPanel stackPanel = sp_test;
                sp_dialog.Children.RemoveAt(4);
                sp_test.Visibility = Visibility.Visible;
                sp_dialog.Children.Add(stackPanel);
            }
            if (text0.StartsWith("I"))
            {
                List<Symbol> symbols = LoadSymbols("flow1");
                foreach (Symbol symbol in symbols)
                {
                    symbol.Resized();
                    video_sketch.Strokes.Add(symbol.strokes);
                }
                Line dashedLine = new Line
                {
                    X1 = 640,
                    Y1 = 0,
                    X2 = 640,
                    Y2 = video_text.ActualHeight, // 使用窗口的高度
                    Stroke = Brushes.Black,
                    StrokeThickness = 2,
                    StrokeDashArray = new DoubleCollection { 4, 2 } // 设定虚线的模式
                };
                Line dashedLine2 = new Line
                {
                    X1 = 1395,
                    Y1 = 0,
                    X2 = 1395,
                    Y2 = video_text.ActualHeight, // 使用窗口的高度
                    Stroke = Brushes.Black,
                    StrokeThickness = 2,
                    StrokeDashArray = new DoubleCollection { 4, 2 } // 设定虚线的模式
                };
                video_text.Children.Add(dashedLine);
                video_text.Children.Add(dashedLine2);

                tsymbols1 = LoadSymbols("save1_1");
                tsymbols2 = LoadSymbols("save1_2");
                Rect rect = tsymbols1[0].strokes.GetBounds();
                Rect rect2 = tsymbols2[0].strokes.GetBounds();
                Matrix tmatrix = new Matrix();
                tmatrix.Translate(rect.X - rect2.X, rect.Y - rect2.Y);
                foreach (Symbol tsymbol in tsymbols1)
                {
                    tsymbol.text_thumb.Visibility = Visibility.Hidden;
                }
                foreach (Symbol tsymbol in tsymbols2)
                {
                    tsymbol.text_thumb.Visibility = Visibility.Hidden;
                    tsymbol.strokes.Transform(tmatrix, false);
                    tsymbol.Resized();
                }

                img_test.Source = new BitmapImage(new Uri(basePath + "Jeju2.png"));
                img_test2.Source = new BitmapImage(new Uri(basePath + "Jeju2.png"));
            }
            if (text0.StartsWith("There"))
            {
                sp_dialog.Dispatcher.Invoke(() => { }, DispatcherPriority.ContextIdle);
                Thread.Sleep(2256);

                StackPanel stackPanel = new StackPanel
                {
                    Orientation = System.Windows.Controls.Orientation.Horizontal,
                    HorizontalAlignment = HorizontalAlignment.Left,
                    Margin = new Thickness(5),
                };
                ContentControl contentControl = new ContentControl
                {
                    MaxWidth = 300,
                    Template = (ControlTemplate)FindResource("LeftBubble")
                };
                TextBlock textBlock = new TextBlock
                {
                    TextWrapping = TextWrapping.Wrap,
                    Padding = new Thickness(10, 5, 10, 5),
                };
                textBlock.Inlines.Add(new Run("Sure! I'll simplify the itinerary recommendations by reducing redundant attractions."));
                contentControl.Content = textBlock;
                var symbolIcon = new Wpf.Ui.Controls.SymbolIcon
                {
                    Symbol = Wpf.Ui.Controls.SymbolRegular.Bot20,
                    Filled = true,
                    VerticalAlignment = VerticalAlignment.Top,
                    Margin = new Thickness(0, 6, 0, 0),
                };
                stackPanel.Children.Add(symbolIcon);
                stackPanel.Children.Add(contentControl);

                sp_dialog.Children.Add(stackPanel);
            }
            if (text0.StartsWith("There"))
            {
                StackPanel stackPanel = sp_test2;
                sp_dialog.Children.RemoveAt(4);
                sp_test2.Visibility = Visibility.Visible;
                sp_dialog.Children.Add(stackPanel);
            }
            if (text0.StartsWith("There"))
            {
                List<Symbol> symbols = LoadSymbols("flow5");
                Rect rect = currentSymbols[0].strokes.GetBounds();
                Rect rect2 = symbols[0].strokes.GetBounds();
                Matrix matrix = new Matrix();
                matrix.Translate(rect.X - rect2.X, rect.Y - rect2.Y);
                foreach (Symbol symbol in currentSymbols)
                {
                    symbol.text_thumb.Visibility = Visibility.Hidden;
                }
                video_sketch.Strokes.Clear();
                foreach (Symbol symbol in symbols)
                {
                    symbol.strokes.Transform(matrix, false);
                    symbol.Resized();
                    video_sketch.Strokes.Add(symbol.strokes);
                    symbol.text_thumb.Visibility = Visibility.Visible;
                }
            }

            sv_dialog.ScrollToBottom();
        }

        private void SendTalk()
        {
            SendTest();
            return;
            if (cb_model.SelectedItem is ComboBoxItem selectedItem)
            {
                string model = selectedItem.Content.ToString();
                string text = tb_input.Text;
                tb_input.Text = "";

                // 创建一个 Image 控件用于显示用户头像
                System.Windows.Controls.Image youName = new System.Windows.Controls.Image
                {
                    Width = 20,
                    Height = 20,
                    Margin = new Thickness(0, 0, 5, 0),
                    VerticalAlignment = VerticalAlignment.Center,
                    Source = new BitmapImage(new Uri("D:\\GptDiagram\\WpfApp1\\user.jpeg"))
                };

                // 创建用户的对话内容控件
                ContentControl youWords = new ContentControl
                {
                    Style = Resources["RightWords"] as Style,
                    Content = text
                };

                // 创建一个 StackPanel 来垂直排列头像和文本
                StackPanel youMessagePanel = new StackPanel
                {
                    Orientation = System.Windows.Controls.Orientation.Horizontal,
                    HorizontalAlignment = HorizontalAlignment.Right,
                    Margin = new Thickness(0, 5, 0, 0)
                };
                youMessagePanel.Children.Add(youWords);
                youMessagePanel.Children.Add(youName);

                // 添加用户的消息到对话框
                sp_dialog.Children.Add(youMessagePanel);

                // 强制刷新 UI 线程
                sp_dialog.Dispatcher.Invoke(() => { }, DispatcherPriority.ContextIdle);

                // 调用 GPT 模型进行对话
                string content = GptTools.Talk(model, text);

                // 创建一个 Image 控件用于显示 GPT 头像
                System.Windows.Controls.Image gptName = new System.Windows.Controls.Image
                {
                    Width = 30,
                    Height = 30,
                    Margin = new Thickness(0, 0, 5, 0),
                    VerticalAlignment = VerticalAlignment.Center,
                    Source = new BitmapImage(new Uri("D:\\GptDiagram\\WpfApp1\\robot.jpg"))
                };

                // 创建 GPT 的对话内容按钮控件，并绑定点击事件
                Button gptWords = new Button
                {
                    Style = Resources["ClickableLeftWords"] as Style,
                    Content = content
                };
                gptWords.Click += LeftWords_Click;  // 绑定点击事件处理程序

                // 创建一个 StackPanel 来垂直排列头像和文本
                StackPanel gptMessagePanel = new StackPanel
                {
                    Orientation = System.Windows.Controls.Orientation.Horizontal,
                    HorizontalAlignment = HorizontalAlignment.Right,
                    Margin = new Thickness(0, 10, 0, 0),
                    Width = 260
                };
                gptMessagePanel.Children.Add(gptName);
                gptMessagePanel.Children.Add(gptWords);

                // 添加 GPT 的消息到对话框
                sp_dialog.Children.Add(gptMessagePanel);

                // 滚动到底部以显示最新消息
                sv_dialog.ScrollToBottom();
            }
            else
            {
                System.Windows.MessageBox.Show("请选择模型");
            }
        }

        private void CheckCode()
        {
            string code = tb_code.Text;

            try
            {
                ParseCode(code);
            }
            catch
            {
                System.Windows.MessageBox.Show("please check your command");
            }
        }

        private void ParseCode(string code)
        {
            foreach (string line in Regex.Split(code, @"\r\n|\n|\r"))
            {
                string[] words = Regex.Split(line, @"\s+");
                words = words.Where(w => !string.IsNullOrEmpty(w)).ToArray();
                if (words.Length == 0)
                {
                    continue;
                }
                switch (words[0])
                {
                    case "add":
                        if (words[1] == "node")
                        {
                            if (words[2] == "between")
                            {
                                Node n1 = d_idSymbol[int.Parse(words[4])] as Node;
                                Node n2 = d_idSymbol[int.Parse(words[7])] as Node;
                                Edge e = AddEdgeBetweenNodes(n1, n2);
                                AddNodeOnEdge(e);
                            }
                            else if (words[3] == "node")
                            {
                                Node n = d_idSymbol[int.Parse(words[4])] as Node;
                                AddNodeOfNode(n, "Process");
                            }
                            else if (words[3] == "edge")
                            {
                                Edge e = d_idSymbol[int.Parse(words[4])] as Edge;
                                AddNodeOnEdge(e);
                            }
                            else if (words.Length == 3)
                            {
                                AddNode(words[2], "Process", "", video_sketch.ActualWidth / 2, video_sketch.ActualHeight / 2, 160 * 80);
                            }
                        }
                        else if (words[1] == "edge")
                        {
                            if (words[2] == "from" || words[2] == "between")
                            {
                                Node n1 = d_idSymbol[int.Parse(words[4])] as Node;
                                Node n2 = d_idSymbol[int.Parse(words[7])] as Node;
                                AddEdgeBetweenNodes(n1, n2);
                                break;
                            }
                        }
                        else if (nodeClassList.Contains(words[1]))
                        {
                            if (words.Length == 3)
                            {
                                AddNode(words[2], words[1], "", video_sketch.ActualWidth / 2, video_sketch.ActualHeight / 2, 160 * 80);
                            }
                            else
                            {
                                AddNode("", words[1], "", video_sketch.ActualWidth / 2, video_sketch.ActualHeight / 2, 160 * 80);
                            }
                        }
                        break;
                    case "set":
                    case "change":
                        if (words[1] == "node")
                        {
                            if (words[4] == "to")
                            {
                                Node n = d_idSymbol[int.Parse(words[2])] as Node;
                                SetParam(n, words[3], words[5]);
                            }
                        }
                        else if (words[1] == "edge")
                        {
                            if (words[3] == "from")
                            {
                                Edge e = d_idSymbol[int.Parse(words[2])] as Edge;
                                Node n1 = d_idSymbol[int.Parse(words[5])] as Node;
                                Node n2 = d_idSymbol[int.Parse(words[8])] as Node;
                                ChangeLink(e, n1, n2);
                            }
                            else if (words[3] == "direction")
                            {
                                Edge e = d_idSymbol[int.Parse(words[2])] as Edge;
                                ReverseEdge(e);
                            }
                            else if (words[4] == "to")
                            {
                                Edge e = d_idSymbol[int.Parse(words[2])] as Edge;
                                SetParam(e, words[3], words[5]);
                            }
                        }
                        break;
                    case "delete":
                        Symbol s = d_idSymbol[int.Parse(words[2])];
                        DeleteSymbol(s);
                        break;
                    case "select":
                        //Symbol s = d_idSymbol[int.Parse(words[2])];
                        break;
                    case "move":
                        if (words[3] == "by")
                        {
                            MoveSymbol(d_idSymbol[int.Parse(words[2])], double.Parse(words[4]),double.Parse(words[5]));
                        }
                        break;
                    case "new":
                        if (words[1] == "node")
                        {
                            StrokeCollection strokes = video_sketch.GetSelectedStrokes();
                            AddNode("", words[2], "", strokes.Clone());
                            video_sketch.Strokes.Remove(strokes);
                        }
                        else if (words[1] == "edge")
                        {
                            foreach (Stroke stroke in video_sketch.GetSelectedStrokes())
                            {
                                stroke.DrawingAttributes.Color = Colors.DarkGreen;
                            }
                        }
                        break;
                    case "To":
                        switch (words[1])
                        {
                            case "red":
                                foreach (Stroke stroke in video_sketch.GetSelectedStrokes())
                                {
                                    stroke.DrawingAttributes.Color = Colors.Red;
                                }
                                break;
                            case "blue":
                                foreach (Stroke stroke in video_sketch.GetSelectedStrokes())
                                {
                                    stroke.DrawingAttributes.Color = Colors.RoyalBlue;
                                }
                                break;
                            case "green":
                                foreach (Stroke stroke in video_sketch.GetSelectedStrokes())
                                {
                                    stroke.DrawingAttributes.Color = Colors.DarkGreen;
                                }
                                break;
                            case "purple":
                                foreach (Stroke stroke in video_sketch.GetSelectedStrokes())
                                {
                                    stroke.DrawingAttributes.Color = Colors.MediumOrchid;
                                }
                                break;
                            case "orange":
                                foreach (Stroke stroke in video_sketch.GetSelectedStrokes())
                                {
                                    stroke.DrawingAttributes.Color = Colors.Tomato;
                                }
                                break;
                            case "yellow":
                                foreach (Stroke stroke in video_sketch.GetSelectedStrokes())
                                {
                                    stroke.DrawingAttributes.Color = Colors.Yellow;
                                }
                                break;
                            case "darkorange":
                                foreach (Stroke stroke in video_sketch.GetSelectedStrokes())
                                {
                                    stroke.DrawingAttributes.Color = Colors.DarkOrange;
                                }
                                break;
                            case "crimson":
                                foreach (Stroke stroke in video_sketch.GetSelectedStrokes())
                                {
                                    stroke.DrawingAttributes.Color = Colors.Crimson;
                                }
                                break;
                            case "brown":
                                foreach (Stroke stroke in video_sketch.GetSelectedStrokes())
                                {
                                    stroke.DrawingAttributes.Color = Colors.Brown;
                                }
                                break;
                        }
                        break;
                    default:
                        System.Windows.MessageBox.Show("error code");
                        break;
                }
            }
        }

        private void PutCode(string code)
        {
            if (string.IsNullOrEmpty(code))
            {
                return;
            }
            foreach (string line in Regex.Split(code, @"\r\n|\n|\r"))
            {
                StackPanel stackPanel = new StackPanel
                {
                    Orientation = System.Windows.Controls.Orientation.Horizontal,
                    HorizontalAlignment = HorizontalAlignment.Left,
                    Margin = new Thickness(2)
                };
                string[] words = Regex.Split(line, @"\s+");
                foreach (string word in words)
                {
                    if (opList.Contains(word))
                    {
                        Button button = new Button
                        {
                            Content = word,
                            Height = 25,
                            Padding = new Thickness(4, 0, 4, 0),
                            Background = new SolidColorBrush(Colors.LightGreen)
                        };
                        button.Click += OpButton_Clicked;
                        stackPanel.Children.Add(button);
                    }
                    else if (sbList.Contains(word))
                    {
                        Button button = new Button
                        {
                            Content = word,
                            Height = 25,
                            Padding = new Thickness(4, 0, 4, 0),
                            Background = new SolidColorBrush(Colors.LightCoral)
                        };
                        button.Click += SbButton_Clicked;
                        stackPanel.Children.Add(button);
                    }
                    else if(int.TryParse(word, out int result))
                    {
                        Button button = new Button
                        {
                            Content = word,
                            Height = 25,
                            Padding = new Thickness(4, 0, 4, 0),
                        };
                        button.Click += IdButton_Clicked;
                        stackPanel.Children.Add(button);
                    }
                    else
                    {
                        TextBox textBox = new TextBox
                        {
                            Text = word,
                            Height = 25,
                            Padding = new Thickness(4, 0, 4, 0),
                        };
                        stackPanel.Children.Add(textBox);
                    }
                }
                lb_code.Items.Add(new ListBoxItem { Padding = new Thickness(0), Content = stackPanel });
            }
        }

        private string GetCode()
        {
            string code = "";
            foreach (ListBoxItem listBoxItem in lb_code.Items)
            {
                StackPanel stackPanel = listBoxItem.Content as StackPanel;
                foreach (var item in stackPanel.Children)
                {
                    if (item is Button button)
                    {
                        if (button.Content is string)
                        {
                            code += button.Content;
                        }
                    }
                    else if (item is TextBox textBox)
                    {
                        code += textBox.Text;
                    }
                    code += " ";
                }
                code += "\n";
            }
            return code;
        }

        private void GetIdList()
        {
            IdListBox.Items.Clear();
            foreach (Symbol symbol in currentSymbols)
            {
                ListBoxItem item = new ListBoxItem();
                item.Content = "id: " + symbol.id.ToString() + "  " + symbol.text;
                //item.Background = new SolidColorBrush(SymbolColor.d_Colors[symbol.color]);
                item.Background = new SolidColorBrush(LightColor(SymbolColor.d_Colors[symbol.color], 0.3, 0.3));
                item.Tag = symbol.id;
                item.BorderBrush = Brushes.White;
                item.BorderThickness = new Thickness(2);
                item.Padding = new Thickness(5);
                IdListBox.Items.Add(item);
            }
        }

        private void InsertNewCode(int index)
        {
            // 创建新的 ListBoxItem
            StackPanel stackPanel = new StackPanel
            {
                Orientation = System.Windows.Controls.Orientation.Horizontal,
                HorizontalAlignment = HorizontalAlignment.Left,
                Margin = new Thickness(2)
            };
            Button button_drag = new Button
            {
                Height = 25,
                Padding = new Thickness(4, 0, 4, 0),
                Content = new Wpf.Ui.Controls.SymbolIcon
                {
                    Symbol = Wpf.Ui.Controls.SymbolRegular.LineHorizontal320,
                    FontSize = 20
                }
            };
            button_drag.PreviewMouseLeftButtonDown += Button_PreviewMouseLeftButtonDown;
            button_drag.PreviewMouseMove += Button_PreviewMouseMove;
            button_drag.PreviewMouseLeftButtonUp += Button_PreviewMouseLeftButtonUp;
            //Button button_add = new Button
            //{
            //    Height = 25,
            //    Padding = new Thickness(4, 0, 4, 0),
            //    Content = new Wpf.Ui.Controls.SymbolIcon
            //    {
            //        Symbol = Wpf.Ui.Controls.SymbolRegular.AddCircle20,
            //        FontSize = 20
            //    }
            //};
            //button_add.Click += Button_Add_Clicked;
            TextBox textBox = new TextBox
            {
                Height = 25,
                Padding = new Thickness(4, 3, 4, 0)
            };
            textBox.KeyUp += TextBox_KeyUp;
            stackPanel.Children.Add(button_drag);
            //stackPanel.Children.Add(button_add);
            stackPanel.Children.Add(textBox);
            ListBoxItem newListBoxItem = new ListBoxItem
            {
                Padding = new Thickness(0),
                Content = stackPanel
            };
            newListBoxItem.KeyDown += ListBoxItem_Dismiss_KeyDown;
            if (index >= 0)
            {
                lb_code.Items.Insert(index, newListBoxItem);
            }
        }

        private T? FindAnchestor<T>(DependencyObject current) where T : DependencyObject
        {
            do
            {
                if (current is T)
                {
                    return (T)current;
                }
                current = VisualTreeHelper.GetParent(current);
            }
            while (current != null);
            return null;
        }

        private T FindChild<T>(DependencyObject parent, string childName) where T : DependencyObject
        {
            if (parent == null) return null;

            T foundChild = null;
            int childrenCount = VisualTreeHelper.GetChildrenCount(parent);

            for (int i = 0; i < childrenCount; i++)
            {
                var child = VisualTreeHelper.GetChild(parent, i);
                // 判断子元素是否是我们想要的类型
                if (child is T tchild && (child as FrameworkElement).Name == childName)
                {
                    foundChild = tchild;
                    break;
                }
                else
                {
                    // 递归查找
                    foundChild = FindChild<T>(child, childName);
                    if (foundChild != null) break;
                }
            }
            return foundChild;
        }

        private StackPanel FindParentStackPanel(DependencyObject child)
        {
            DependencyObject parent = VisualTreeHelper.GetParent(child);
            while (parent != null && !(parent is StackPanel))
            {
                parent = VisualTreeHelper.GetParent(parent);
            }
            return parent as StackPanel;
        }

        private Symbol? GetSelectedSymbol()
        {
            if (video_sketch.GetSelectedStrokes().Count > 0)
            {
                Stroke selectedStroke = video_sketch.GetSelectedStrokes()[0];
                if (d_StrokeSymbol.ContainsKey(selectedStroke))
                {
                    return d_StrokeSymbol[selectedStroke];
                }
            }
            return null;
        }

        private void GetShadowStrokes(Symbol? symbol)
        {
            if (useShadowSymbol)
            {
                if (symbol != null)
                {
                    foreach (Symbol ss in shadowSymbols)
                    {
                        if (ss.id == symbol.id)
                        {
                            return;
                        }
                    }
                    Symbol shadowSymbol = symbol.Clone();
                    shadowSymbols.Add(shadowSymbol);
                    StrokeCollection strokes = new StrokeCollection();
                    foreach (Stroke stroke in shadowSymbol.strokes)
                    {
                        stroke.DrawingAttributes.Color = SymbolColor.d_Colors["gray"];
                        if (symbol is Edge)
                        {
                            stroke.StylusPoints = ApplyBezierCurveInterpolation(stroke.StylusPoints, 0.2);
                            stroke.StylusPoints = ApplyBezierCurveInterpolation(stroke.StylusPoints, 3);
                        }
                        strokes.Add(CreateDashedStrokes(stroke));
                    }
                    shadowSymbol.strokes = strokes;
                    video_sketch.Strokes.Add(shadowSymbol.strokes);
                }
                if (i_shadowHistory == -1)
                {
                    i_shadowHistory = undoHistories.Count;
                }
                pp_check.IsOpen = true;
                gd_check.Focus();
            }
        }

        private void RemoveShadowStrokes()
        {
            foreach (Symbol shadowSymbol in shadowSymbols)
            {
                video_sketch.Strokes.Remove(shadowSymbol.strokes);
                shadowSymbol.Deleted();
            }
            shadowSymbols.Clear();
            i_shadowHistory = -1;
        }

        private void ReturnShadowStrokes()
        {
            if (i_shadowHistory == -1)
            {
                return;
            }
            int i_reHistory = redoHistories.Count;
            while (undoHistories.Count > i_shadowHistory)
            {
                Undo();
            }
            redoHistories.RemoveRange(i_reHistory, redoHistories.Count - i_reHistory);
            RemoveShadowStrokes();
        }

        private double[] GetLinkPoint(Node nodeHead, Node nodeTail)
        {
            double headCenterX = nodeHead.center[0];
            double headCenterY = nodeHead.center[1];
            double tailCenterX = nodeTail.center[0];
            double tailCenterY = nodeTail.center[1];
            var r1 = nodeHead.strokes.GetBounds();
            var r2 = nodeTail.strokes.GetBounds();
            double startX = -1, startY = -1, endX = -1, endY = -1;
            double minDistance;
            //计算临近点
            minDistance = EulerDistance(headCenterX, headCenterY, tailCenterX, tailCenterY);
            foreach (Stroke stroke in nodeHead.strokes)
            {
                if (stroke.StylusPoints.Count == 1)
                {
                    startX = stroke.StylusPoints[0].X;
                    startY = stroke.StylusPoints[0].Y;
                }
                else
                {
                    for (int i = 1; i < stroke.StylusPoints.Count; i++)
                    {
                        double x1 = stroke.StylusPoints[i - 1].X, y1 = stroke.StylusPoints[i - 1].Y;
                        double x2 = stroke.StylusPoints[i].X, y2 = stroke.StylusPoints[i].Y;
                        double[] foot = PerpendicularFoot(x1, y1, x2, y2, tailCenterX, tailCenterY);
                        if (IsBetween(x1, y1, x2, y2, foot[0], foot[1]))
                        {
                            double distance = EulerDistance(foot[0], foot[1], tailCenterX, tailCenterY);
                            if (distance < minDistance)
                            {
                                startX = foot[0];
                                startY = foot[1];
                                minDistance = distance;
                            }
                        }
                        else
                        {
                            double distance1 = EulerDistance(x1, y1, tailCenterX, tailCenterY);
                            double distance2 = EulerDistance(x2, y2, tailCenterX, tailCenterY);
                            if (distance1 < minDistance && distance1 < distance2)
                            {
                                startX = x1;
                                startY = y1;
                                minDistance = distance1;
                            }
                            else if (distance2 < minDistance)
                            {
                                startX = x2;
                                startY = y2;
                                minDistance = distance2;
                            }
                        }
                    }
                }
            }
            minDistance = EulerDistance(headCenterX, headCenterY, tailCenterX, tailCenterY);
            foreach (Stroke stroke in nodeTail.strokes)
            {
                if (stroke.StylusPoints.Count == 1)
                {
                    endX = stroke.StylusPoints[0].X;
                    endY = stroke.StylusPoints[0].Y;
                }
                else
                {
                    for (int i = 1; i < stroke.StylusPoints.Count; i++)
                    {
                        double x1 = stroke.StylusPoints[i - 1].X, y1 = stroke.StylusPoints[i - 1].Y;
                        double x2 = stroke.StylusPoints[i].X, y2 = stroke.StylusPoints[i].Y;
                        double[] foot = PerpendicularFoot(x1, y1, x2, y2, headCenterX, headCenterY);
                        if (IsBetween(x1, y1, x2, y2, foot[0], foot[1]))
                        {
                            double distance = EulerDistance(foot[0], foot[1], headCenterX, headCenterY);
                            if (distance < minDistance)
                            {
                                endX = foot[0];
                                endY = foot[1];
                                minDistance = distance;
                            }
                        }
                        else
                        {
                            double distance1 = EulerDistance(x1, y1, headCenterX, headCenterY);
                            double distance2 = EulerDistance(x2, y2, headCenterX, headCenterY);
                            if (distance1 < minDistance && distance1 < distance2)
                            {
                                endX = x1;
                                endY = y1;
                                minDistance = distance1;
                            }
                            else if (distance2 < minDistance)
                            {
                                endX = x2;
                                endY = y2;
                                minDistance = distance2;
                            }
                        }
                    }
                }
            }
            return new double[] { startX, startY, endX, endY };
        }

        private void RelayoutOverlappingNode(Node node)
        {
            return;
            Rect bbox1 = node.strokes.GetBounds();
            foreach (Symbol symbol in currentSymbols)
            {
                if (symbol is Node && symbol != node)
                {
                    Rect bbox2 = symbol.strokes.GetBounds();
                    double xLap = Math.Min(bbox1.Right, bbox2.Right) - Math.Max(bbox1.Left, bbox2.Left);
                    double yLap = Math.Min(bbox1.Bottom, bbox2.Bottom) - Math.Max(bbox1.Top, bbox2.Top);
                    if (xLap > 0 && yLap > 0)
                    {
                        if (xLap > yLap)
                        {
                            if (bbox1.Top > bbox2.Top)
                            {
                                MoveSymbol(symbol, 0, bbox1.Top - bbox2.Bottom - 50);
                            }
                            else
                            {
                                MoveSymbol(symbol, 0, bbox2.Top - bbox1.Bottom + 50);
                            }
                        }
                        else
                        {
                            if (bbox1.Left > bbox2.Left)
                            {
                                MoveSymbol(symbol, bbox1.Left - bbox2.Right - 50, 0);
                            }
                            else
                            {
                                MoveSymbol(symbol, bbox2.Left - bbox1.Right + 50, 0);
                            }
                        }
                    }
                }
            }
        }

        private Gesture[] LoadGestureSet(string path)
        {
            List<Gesture> gestures = new List<Gesture>();
            string[] gestureFolders = Directory.GetDirectories(path);
            foreach (string folder in gestureFolders)
            {
                string[] gestureFiles = Directory.GetFiles(folder, "*.xml");
                foreach (string file in gestureFiles)
                    gestures.Add(GestureIO.ReadGesture(file));
            }
            return gestures.ToArray();
        }

        private void LoadJson(string json)
        {
            if (json == null || json.Length == 0)
            {
                throw new Exception("empty json");
            }
            JsonDocument document = JsonDocument.Parse(json);
            JsonElement root = document.RootElement;
            List<JsonElement> edgeJEs = new List<JsonElement>();
            //创建元素
            foreach (JsonElement element in root.EnumerateArray())
            {
                Symbol symbol;
                StrokeCollection strokes = LoadStrokesFromJson(element);
                if (element.GetProperty("superclass").GetString() == "Node")
                {
                    symbol = new Node(++Symbol_id, element.GetProperty("text").GetString(), element.GetProperty("class").GetString(), element.GetProperty("color").GetString(),
                        new double[] { element.GetProperty("center")[0].GetDouble(), element.GetProperty("center")[1].GetDouble() }, strokes, new List<Symbol>(), video_text);
                    Node node = (Node)symbol;
                    //node.center = JsonSerializer.Deserialize<double[]>(element.GetProperty("center"));
                    node.area = element.GetProperty("area").GetDouble();
                }
                else if (element.GetProperty("superclass").GetString() == "Edge")
                {
                    symbol = new Edge(++Symbol_id, element.GetProperty("text").GetString(), element.GetProperty("class").GetString(), element.GetProperty("color").GetString(),
                        new double[2], strokes, new List<Symbol>(), video_text);
                    Edge edge = (Edge)symbol;
                    edge.weight = element.GetProperty("weight").GetDouble();
                    edgeJEs.Add(element);
                }
                else
                {
                    symbol = new Content(++Symbol_id, video_text);
                    Content content = (Content)symbol;
                }

                d_idSymbol.Add(Symbol_id, symbol);
                foreach (Stroke stroke in symbol.strokes)
                {
                    d_idStroke.Add(++Stroke_id, stroke);
                    d_StrokeSymbol.Add(stroke, symbol);
                    video_sketch.Strokes.Add(stroke);
                }
                currentSymbols.Add(symbol);
            }

            //创建连接关系
            for (int i = 0; i < edgeJEs.Count; i++)
            {
                foreach (JsonElement element in edgeJEs[i].GetProperty("head_node").EnumerateArray())
                {
                    (d_idSymbol[edgeJEs[i].GetProperty("id").GetInt16()] as Edge).nodes_from.Add(d_idSymbol[element.GetInt16()] as Node);
                    (d_idSymbol[element.GetInt16()] as Node).edges_out.Add(d_idSymbol[edgeJEs[i].GetProperty("id").GetInt16()] as Edge);
                }
                foreach (JsonElement element in edgeJEs[i].GetProperty("tail_node").EnumerateArray())
                {
                    (d_idSymbol[edgeJEs[i].GetProperty("id").GetInt16()] as Edge).nodes_to.Add(d_idSymbol[element.GetInt16()] as Node);
                    (d_idSymbol[element.GetInt16()] as Node).edges_in.Add(d_idSymbol[edgeJEs[i].GetProperty("id").GetInt16()] as Edge);
                }
            }
        }

        private StrokeCollection LoadStrokesFromJson(JsonElement element)
        {
            StrokeCollection strokes = new StrokeCollection();
            if (element.GetProperty("superclass").GetString() == "Node")
            {
                string code = element.GetProperty("mask").GetProperty("counts").GetString();
                int height = element.GetProperty("mask").GetProperty("size")[0].GetInt16();
                int width = element.GetProperty("mask").GetProperty("size")[1].GetInt16();
                Image<Gray, byte> image = CocoTools.decode(new RleObj { size = new int[] { height, width }, counts = code });

                VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
                CvInvoke.FindContours(image, contours, null, RetrType.List, ChainApproxMethod.ChainApproxTc89Kcos);
                for (int i = 0; i < contours.Size; i++)
                {
                    StylusPointCollection points = new StylusPointCollection();
                    for (int j = 0; j < contours[i].Size; j++)
                    {
                        points.Add(new StylusPoint(contours[i][j].X, contours[i][j].Y));
                    }
                    points.Add(new StylusPoint(contours[i][0].X, contours[i][0].Y));
                    Stroke stroke = new Stroke(points);
                    stroke.DrawingAttributes.Color = SymbolColor.d_Colors[element.GetProperty("color").GetString()];
                    strokes.Add(stroke);
                }
            }
            else if (element.GetProperty("superclass").GetString() == "Edge")
            {
                StylusPointCollection stylusPoints = new StylusPointCollection();
                foreach (JsonElement pointJE in element.GetProperty("line").EnumerateArray())
                {
                    stylusPoints.Add(new StylusPoint(pointJE[0].GetDouble(), pointJE[1].GetDouble()));
                }
                Stroke stroke = new Stroke(stylusPoints);
                stroke.DrawingAttributes.Color = SymbolColor.d_Colors[element.GetProperty("color").GetString()];
                strokes.Add(stroke);
            }
            else
            {

            }
            return strokes;
        }

        private string SaveJson()
        {
            List<object> root = new List<object>();
            foreach (Symbol symbol in currentSymbols)
            {
                Dictionary<string, object> element;
                if (symbol is Node)
                {
                    List<int> in_edge = new List<int>();
                    List<int> out_edge = new List<int>();
                    foreach (Edge edge in (symbol as Node).edges_in)
                    {
                        in_edge.Add(edge.id);
                    }
                    foreach (Edge edge in (symbol as Node).edges_out)
                    {
                        out_edge.Add(edge.id);
                    }
                    element = new Dictionary<string, object>
                    {
                        { "id", symbol.id },
                        { "text", symbol.text },
                        { "superclass", "Node" },
                        { "class", symbol.category },
                        { "mask", new { } },
                        { "in_edge", in_edge.ToArray() },
                        { "out_edge", out_edge.ToArray() },
                        { "area", (symbol as Node).area },
                        { "center", symbol.center.ToArray() },
                        { "color", symbol.color }
                    };
                }
                else if (symbol is Edge)
                {
                    List<int> head_node = new List<int>();
                    List<int> tail_node = new List<int>();
                    foreach (Node node in (symbol as Edge).nodes_from)
                    {
                        head_node.Add(node.id);
                    }
                    foreach (Node node in (symbol as Edge).nodes_to)
                    {
                        tail_node.Add(node.id);
                    }
                    List<double[]> line = new List<double[]>();
                    foreach (StylusPoint stylusPoint in symbol.strokes[0].StylusPoints)
                    {
                        line.Add(new double[] { stylusPoint.X, stylusPoint.Y });
                    }
                    element = new Dictionary<string, object>
                    {
                        { "id", symbol.id },
                        { "text", symbol.text },
                        { "superclass", "Edge" },
                        { "class", symbol.category },
                        { "head_node", head_node.ToArray() },
                        { "tail_node", tail_node.ToArray() },
                        { "line", line.ToArray() },
                        { "weight", (symbol as Edge).weight },
                        { "color", symbol.color }
                    };
                }
                else
                {
                    continue;
                }
                root.Add(element);
            }
            string json = JsonSerializer.Serialize(root);
            return json;
        }

        private void LoadAll(string fname)
        {
            FileStream fileStream = new FileStream(basePath + fname + ".isf", FileMode.Open, FileAccess.Read);
            StrokeCollection strokeCollection = new StrokeCollection(fileStream);

            string json = File.ReadAllText(basePath + fname + ".json", Encoding.UTF8);
            if (json == null || json.Length == 0)
            {
                throw new Exception("empty json");
            }
            JsonDocument document = JsonDocument.Parse(json);
            JsonElement root = document.RootElement;
            List<JsonElement> edgeJEs = new List<JsonElement>();
            int stroke_id = Stroke_id + 1, symbol_id = Symbol_id + 1;

            //创建元素
            foreach (JsonElement element in root.GetProperty("Symbol").EnumerateArray())
            {
                Symbol symbol;
                StrokeCollection strokes = new StrokeCollection();
                Symbol_id = symbol_id + element.GetProperty("id").GetInt16();
                if (element.GetProperty("superclass").GetString() == "Node")
                {
                    symbol = new Node(Symbol_id, element.GetProperty("text").GetString(), element.GetProperty("class").GetString(), element.GetProperty("color").GetString(),
                        new double[] { element.GetProperty("center")[0].GetDouble(), element.GetProperty("center")[1].GetDouble() }, strokes, new List<Symbol>(), video_text);
                    Node node = (Node)symbol;
                    //node.center = JsonSerializer.Deserialize<double[]>(element.GetProperty("center"));
                    node.area = element.GetProperty("area").GetDouble();
                }
                else if (element.GetProperty("superclass").GetString() == "Edge")
                {
                    symbol = new Edge(Symbol_id, element.GetProperty("text").GetString(), element.GetProperty("class").GetString(), element.GetProperty("color").GetString(),
                        new double[2], strokes, new List<Symbol>(), video_text);
                    Edge edge = (Edge)symbol;
                    edge.weight = element.GetProperty("weight").GetDouble();
                    edgeJEs.Add(element);
                }
                else
                {
                    symbol = new Content(Symbol_id, video_text);
                    Content content = (Content)symbol;
                }

                d_idSymbol.Add(Symbol_id, symbol);
                currentSymbols.Add(symbol);
            }

            //创建连接关系
            for (int i = 0; i < edgeJEs.Count; i++)
            {
                foreach (JsonElement element in edgeJEs[i].GetProperty("head_node").EnumerateArray())
                {
                    (d_idSymbol[symbol_id + edgeJEs[i].GetProperty("id").GetInt16()] as Edge).nodes_from.Add(d_idSymbol[symbol_id + element.GetInt16()] as Node);
                    (d_idSymbol[symbol_id + element.GetInt16()] as Node).edges_out.Add(d_idSymbol[symbol_id + edgeJEs[i].GetProperty("id").GetInt16()] as Edge);
                }
                foreach (JsonElement element in edgeJEs[i].GetProperty("tail_node").EnumerateArray())
                {
                    (d_idSymbol[symbol_id + edgeJEs[i].GetProperty("id").GetInt16()] as Edge).nodes_to.Add(d_idSymbol[symbol_id + element.GetInt16()] as Node);
                    (d_idSymbol[symbol_id + element.GetInt16()] as Node).edges_in.Add(d_idSymbol[symbol_id + edgeJEs[i].GetProperty("id").GetInt16()] as Edge);
                }
            }

            int si = 0;
            foreach (JsonElement element in root.GetProperty("Dictionary").EnumerateArray())
            {
                if (element[0].GetInt16() != -1)
                {
                    Stroke_id = stroke_id + element[0].GetInt16();
                    d_idStroke.Add(Stroke_id, strokeCollection[si]);
                    Symbol symbol = d_idSymbol[symbol_id + element[1].GetInt16()];
                    d_StrokeSymbol.Add(strokeCollection[si], symbol);
                    symbol.strokes.Add(strokeCollection[si]);
                }
                si++;
            }
            video_sketch.Strokes.Add(strokeCollection);
        }

        private void SaveAll(string fname)
        {
            RenderTargetBitmap rtp = new RenderTargetBitmap((int)video_sketch.ActualWidth, (int)video_sketch.ActualHeight, 96, 96, PixelFormats.Pbgra32);
            rtp.Render(video_sketch);
            JpegBitmapEncoder jpeg = new JpegBitmapEncoder();
            jpeg.QualityLevel = 100;
            jpeg.Frames.Add(BitmapFrame.Create(rtp));
            FileStream fs = new FileStream(basePath + fname + ".png", FileMode.Create);
            jpeg.Save(fs);
            fs.Close();
            fs.Dispose();

            FileStream fileStream = new FileStream(basePath + fname + ".isf", FileMode.Create);
            video_sketch.Strokes.Save(fileStream);
            fileStream.Close();

            List<int[]> dictionay = new List<int[]>();
            int si = 0;
            foreach (Stroke stroke in video_sketch.Strokes)
            {
                if (d_StrokeSymbol.ContainsKey(stroke))
                {
                    dictionay.Add(new int[] { si, d_StrokeSymbol[stroke].id });
                }
                else
                {
                    dictionay.Add(new int[] { -1, -1 });
                }
                si++;
            }

            List<object> symbols = new List<object>();
            foreach (Symbol symbol in currentSymbols)
            {
                Dictionary<string, object> element;
                if (symbol is Node)
                {
                    List<int> in_edge = new List<int>();
                    List<int> out_edge = new List<int>();
                    foreach (Edge edge in (symbol as Node).edges_in)
                    {
                        in_edge.Add(edge.id);
                    }
                    foreach (Edge edge in (symbol as Node).edges_out)
                    {
                        out_edge.Add(edge.id);
                    }
                    element = new Dictionary<string, object>
                    {
                        { "id", symbol.id },
                        { "text", symbol.text },
                        { "superclass", "Node" },
                        { "class", symbol.category },
                        { "mask", new { } },
                        { "in_edge", in_edge.ToArray() },
                        { "out_edge", out_edge.ToArray() },
                        { "area", (symbol as Node).area },
                        { "center", symbol.center.ToArray() },
                        { "color", symbol.color }
                    };
                }
                else if (symbol is Edge)
                {
                    List<int> head_node = new List<int>();
                    List<int> tail_node = new List<int>();
                    foreach (Node node in (symbol as Edge).nodes_from)
                    {
                        head_node.Add(node.id);
                    }
                    foreach (Node node in (symbol as Edge).nodes_to)
                    {
                        tail_node.Add(node.id);
                    }
                    List<double[]> line = new List<double[]>();
                    foreach (StylusPoint stylusPoint in symbol.strokes[0].StylusPoints)
                    {
                        line.Add(new double[] { stylusPoint.X, stylusPoint.Y });
                    }
                    element = new Dictionary<string, object>
                    {
                        { "id", symbol.id },
                        { "text", symbol.text },
                        { "superclass", "Edge" },
                        { "class", symbol.category },
                        { "head_node", head_node.ToArray() },
                        { "tail_node", tail_node.ToArray() },
                        { "line", line.ToArray() },
                        { "weight", (symbol as Edge).weight },
                        { "color", symbol.color }
                    };
                }
                else
                {
                    continue;
                }
                symbols.Add(element);
            }

            Dictionary<string, object> root = new Dictionary<string, object> { { "Dictionary", dictionay.ToArray() }, { "Symbol", symbols.ToArray() } };
            File.WriteAllText(basePath + fname + ".json", JsonSerializer.Serialize(root), Encoding.UTF8);
        }

        private List<Symbol> LoadSymbols(string fname)
        {
            List<Symbol> symbols = new List<Symbol>();
            FileStream fileStream = new FileStream(basePath + fname + ".isf", FileMode.Open, FileAccess.Read);
            StrokeCollection strokeCollection = new StrokeCollection(fileStream);

            string json = File.ReadAllText(basePath + fname + ".json", Encoding.UTF8);
            if (json == null || json.Length == 0)
            {
                throw new Exception("empty json");
            }
            JsonDocument document = JsonDocument.Parse(json);
            JsonElement root = document.RootElement;
            List<JsonElement> edgeJEs = new List<JsonElement>();
            int stroke_id = Stroke_id + 1, symbol_id = Symbol_id + 1;

            //创建元素
            foreach (JsonElement element in root.GetProperty("Symbol").EnumerateArray())
            {
                Symbol symbol;
                StrokeCollection strokes = new StrokeCollection();
                Symbol_id = symbol_id + element.GetProperty("id").GetInt16();
                if (element.GetProperty("superclass").GetString() == "Node")
                {
                    symbol = new Node(Symbol_id, element.GetProperty("text").GetString(), element.GetProperty("class").GetString(), element.GetProperty("color").GetString(),
                        new double[] { element.GetProperty("center")[0].GetDouble(), element.GetProperty("center")[1].GetDouble() }, strokes, new List<Symbol>(), video_text);
                    Node node = (Node)symbol;
                    //node.center = JsonSerializer.Deserialize<double[]>(element.GetProperty("center"));
                    node.area = element.GetProperty("area").GetDouble();
                }
                else if (element.GetProperty("superclass").GetString() == "Edge")
                {
                    symbol = new Edge(Symbol_id, element.GetProperty("text").GetString(), element.GetProperty("class").GetString(), element.GetProperty("color").GetString(),
                        new double[2], strokes, new List<Symbol>(), video_text);
                    Edge edge = (Edge)symbol;
                    edge.weight = element.GetProperty("weight").GetDouble();
                    edgeJEs.Add(element);
                }
                else
                {
                    symbol = new Content(Symbol_id, video_text);
                    Content content = (Content)symbol;
                }

                d_idSymbol.Add(Symbol_id, symbol);
                currentSymbols.Add(symbol);
                symbols.Add(symbol);
            }

            //创建连接关系
            for (int i = 0; i < edgeJEs.Count; i++)
            {
                foreach (JsonElement element in edgeJEs[i].GetProperty("head_node").EnumerateArray())
                {
                    (d_idSymbol[symbol_id + edgeJEs[i].GetProperty("id").GetInt16()] as Edge).nodes_from.Add(d_idSymbol[symbol_id + element.GetInt16()] as Node);
                    (d_idSymbol[symbol_id + element.GetInt16()] as Node).edges_out.Add(d_idSymbol[symbol_id + edgeJEs[i].GetProperty("id").GetInt16()] as Edge);
                }
                foreach (JsonElement element in edgeJEs[i].GetProperty("tail_node").EnumerateArray())
                {
                    (d_idSymbol[symbol_id + edgeJEs[i].GetProperty("id").GetInt16()] as Edge).nodes_to.Add(d_idSymbol[symbol_id + element.GetInt16()] as Node);
                    (d_idSymbol[symbol_id + element.GetInt16()] as Node).edges_in.Add(d_idSymbol[symbol_id + edgeJEs[i].GetProperty("id").GetInt16()] as Edge);
                }
            }

            int si = 0;
            foreach (JsonElement element in root.GetProperty("Dictionary").EnumerateArray())
            {
                if (element[0].GetInt16() != -1)
                {
                    Stroke_id = stroke_id + element[0].GetInt16();
                    d_idStroke.Add(Stroke_id, strokeCollection[si]);
                    Symbol symbol = d_idSymbol[symbol_id + element[1].GetInt16()];
                    d_StrokeSymbol.Add(strokeCollection[si], symbol);
                    symbol.strokes.Add(strokeCollection[si]);
                }
                si++;
            }

            return symbols;
        }

        private void SaveSymbols(string fname, List<Symbol> save_symbols)
        {
            StrokeCollection strokes = new StrokeCollection();
            foreach (Symbol symbol in save_symbols)
            {
                strokes.Add(symbol.strokes);
            }
            FileStream fileStream = new FileStream(basePath + fname + ".isf", FileMode.Create);
            strokes.Save(fileStream);
            fileStream.Close();

            List<int[]> dictionay = new List<int[]>();
            int si = 0;
            foreach (Stroke stroke in strokes)
            {
                if (d_StrokeSymbol.ContainsKey(stroke))
                {
                    dictionay.Add(new int[] { si, d_StrokeSymbol[stroke].id });
                }
                else
                {
                    dictionay.Add(new int[] { -1, -1 });
                }
                si++;
            }

            List<object> symbols = new List<object>();
            foreach (Symbol symbol in currentSymbols)
            {
                Dictionary<string, object> element;
                if (symbol is Node)
                {
                    List<int> in_edge = new List<int>();
                    List<int> out_edge = new List<int>();
                    foreach (Edge edge in (symbol as Node).edges_in)
                    {
                        in_edge.Add(edge.id);
                    }
                    foreach (Edge edge in (symbol as Node).edges_out)
                    {
                        out_edge.Add(edge.id);
                    }
                    element = new Dictionary<string, object>
                    {
                        { "id", symbol.id },
                        { "text", symbol.text },
                        { "superclass", "Node" },
                        { "class", symbol.category },
                        { "mask", new { } },
                        { "in_edge", in_edge.ToArray() },
                        { "out_edge", out_edge.ToArray() },
                        { "area", (symbol as Node).area },
                        { "center", symbol.center.ToArray() },
                        { "color", symbol.color }
                    };
                }
                else if (symbol is Edge)
                {
                    List<int> head_node = new List<int>();
                    List<int> tail_node = new List<int>();
                    foreach (Node node in (symbol as Edge).nodes_from)
                    {
                        head_node.Add(node.id);
                    }
                    foreach (Node node in (symbol as Edge).nodes_to)
                    {
                        tail_node.Add(node.id);
                    }
                    List<double[]> line = new List<double[]>();
                    foreach (StylusPoint stylusPoint in symbol.strokes[0].StylusPoints)
                    {
                        line.Add(new double[] { stylusPoint.X, stylusPoint.Y });
                    }
                    element = new Dictionary<string, object>
                    {
                        { "id", symbol.id },
                        { "text", symbol.text },
                        { "superclass", "Edge" },
                        { "class", symbol.category },
                        { "head_node", head_node.ToArray() },
                        { "tail_node", tail_node.ToArray() },
                        { "line", line.ToArray() },
                        { "weight", (symbol as Edge).weight },
                        { "color", symbol.color }
                    };
                }
                else
                {
                    continue;
                }
                symbols.Add(element);
            }

            Dictionary<string, object> root = new Dictionary<string, object> { { "Dictionary", dictionay.ToArray() }, { "Symbol", symbols.ToArray() } };
            File.WriteAllText(basePath + fname + ".json", JsonSerializer.Serialize(root), Encoding.UTF8);
        }

        private void ClearAll()
        {
            video_sketch.Strokes.Clear();
            video_text.Children.Clear();
            d_idStroke.Clear();
            d_idSymbol.Clear();
            d_StrokeSymbol.Clear();
            currentSymbols.Clear();
            markedSymbols.Clear();
            shadowSymbols.Clear();
            Stroke_id = -1;
            Symbol_id = -1;
            //previousSelectionBounds = new Rect();
        }
    }
}
