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 Emgu.CV.CvEnum;
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;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        class History
        {
            public string name;
            public Dictionary<string, object> items;

            public History(string name, Dictionary<string, object> items)
            {
                this.name = name;
                this.items = items;
            }
        }

        private void PushHistory(History history)
        {
            if (useHistory)
            {
                undoHistories.Add(history);
                redoHistories.Clear();
            }
        }

        //Un
        private void UnMoveEdgeHead(Edge edge, double movedDistanceX, double movedDistanceY)
        {
            Stroke stroke = edge.strokes[0];
            double startX = stroke.StylusPoints[0].X;
            double startY = stroke.StylusPoints[0].Y;
            double endX = stroke.StylusPoints.Last().X;
            double endY = stroke.StylusPoints.Last().Y;
            double targetX = startX - movedDistanceX;
            double targetY = startY - movedDistanceY;
            if (stroke.StylusPoints.Count == 2)
            {
                stroke.StylusPoints[0] = new StylusPoint(targetX, targetY);
            }
            else
            {
                // 计算缩放比例
                double scaleX = (targetX - endX) / (startX - endX);
                double scaleY = (targetY - endY) / (startY - endY);
                // 创建缩放和平移变换
                Matrix matrix = new Matrix();
                matrix.ScaleAt(scaleX, scaleY, endX, endY);
                stroke.Transform(matrix, false);
            }
            edge.ResetArrow();
        }

        private void UnMoveEdgeTail(Edge edge, double movedDistanceX, double movedDistanceY)
        {
            Stroke stroke = edge.strokes[0];
            double startX = stroke.StylusPoints[0].X;
            double startY = stroke.StylusPoints[0].Y;
            double endX = stroke.StylusPoints.Last().X;
            double endY = stroke.StylusPoints.Last().Y;
            double targetX = endX - movedDistanceX;
            double targetY = endY - movedDistanceY;
            if (stroke.StylusPoints.Count == 2)
            {
                stroke.StylusPoints[1] = new StylusPoint(targetX, targetY);
            }
            else
            {
                // 计算缩放比例
                double scaleX = (targetX - startX) / (endX - startX);
                double scaleY = (targetY - startY) / (endY - startY);
                // 创建缩放和平移变换
                Matrix matrix = new Matrix();
                matrix.ScaleAt(scaleX, scaleY, startX, startY);
                stroke.Transform(matrix, false);
            }
            edge.ResetArrow();
        }

        private void UnAddNode(Node node)
        {
            node.Disconnect();
            node.Deleted();
            foreach (Stroke stroke in node.strokes)
            {
                if (video_sketch.Strokes.Contains(stroke))
                {
                    video_sketch.Strokes.Remove(stroke);
                }
            }
            currentSymbols.Remove(node);
        }

        private void UnAddEdge(Edge edge)
        {
            edge.Disconnect();
            edge.Deleted();
            foreach (Stroke stroke in edge.strokes)
            {
                if (video_sketch.Strokes.Contains(stroke))
                {
                    video_sketch.Strokes.Remove(stroke);
                }
            }
            currentSymbols.Remove(edge);
        }

        private void UnDeleteSymbol(Symbol symbol)
        {
            symbol.Connect();
            symbol.Added();
            foreach (Stroke stroke in symbol.strokes)
            {
                if (!video_sketch.Strokes.Contains(stroke))
                {
                    video_sketch.Strokes.Add(stroke);
                }
            }
            currentSymbols.Add(symbol);
        }

        private void UnMoveSymbol(Symbol symbol, double movedDistanceX, double movedDistanceY)
        {
            Matrix matrix = new Matrix();
            matrix.Translate(-movedDistanceX, -movedDistanceY);
            foreach (Stroke stroke in symbol.strokes)
            {
                stroke.Transform(matrix, false);
            }
            symbol.Moved();
        }

        private void UnResizeSymbol(Symbol symbol, Rect oldBounds, Rect bounds)
        {
            Matrix matrix = new Matrix();
            matrix.Translate(oldBounds.Left - bounds.Left, oldBounds.Top - bounds.Top);
            matrix.ScaleAt(oldBounds.Width / bounds.Width, oldBounds.Height / bounds.Height, oldBounds.Left, oldBounds.Top);
            foreach (Stroke stroke in symbol.strokes)
            {
                stroke.Transform(matrix, false);
            }
            symbol.Resized();
        }

        //Re
        private void ReMoveEdgeHead(Edge edge, double movedDistanceX, double movedDistanceY)
        {
            UnMoveEdgeHead(edge, -movedDistanceX, -movedDistanceY);
        }

        private void ReMoveEdgeTail(Edge edge, double movedDistanceX, double movedDistanceY)
        {
            UnMoveEdgeTail(edge, -movedDistanceX, -movedDistanceY);
        }

        private void ReAddNode(Node node)
        {
            UnDeleteSymbol(node);
        }

        private void ReAddEdge(Edge edge)
        {
            UnDeleteSymbol(edge);
        }

        private void ReDeleteSymbol(Symbol symbol)
        {
            if (symbol is Node)
            {
                UnAddNode(symbol as Node);
            }
            else if (symbol is Edge)
            {
                UnAddEdge(symbol as Edge);
            }
        }

        private void ReMoveSymbol(Symbol symbol, double movedDistanceX, double movedDistanceY)
        {
            UnMoveSymbol(symbol, -movedDistanceX, -movedDistanceY);
        }

        private void ReResizeSymbol(Symbol symbol, Rect oldBounds, Rect bounds)
        {
            UnResizeSymbol(symbol, bounds, oldBounds);
        }

        private void Undo(bool group=false)
        {
            if (undoHistories.Count == 0)
            {
                System.Windows.MessageBox.Show("无可撤回项");
                return;
            }
            useHistory = false;
            History history = undoHistories.Last();
            switch (history.name)
            {
                case "MoveEdgeHead":
                    UnMoveEdgeHead((Edge)history.items["edge"], (double)history.items["movedDistanceX"], (double)history.items["movedDistanceY"]);
                    break;
                case "MoveEdgeTail":
                    UnMoveEdgeTail((Edge)history.items["edge"], (double)history.items["movedDistanceX"], (double)history.items["movedDistanceY"]);
                    break;
                case "AddNode_s":
                    UnAddNode((Node)history.items["node"]);
                    break;
                case "AddNode":
                    UnAddNode((Node)history.items["node"]);
                    break;
                case "AddEdge":
                    UnAddEdge((Edge)history.items["edge"]);
                    break;
                case "DeleteSymbol":
                    UnDeleteSymbol((Symbol)history.items["symbol"]);
                    break;
                case "MoveSymbol":
                    UnMoveSymbol((Symbol)history.items["symbol"], (double)history.items["movedDistanceX"], (double)history.items["movedDistanceY"]);
                    break;
                case "ResizeSymbol":
                    UnResizeSymbol((Symbol)history.items["symbol"], (Rect)history.items["oldBounds"], (Rect)history.items["bounds"]);
                    break;
                case "StartGroup":
                    group = false;
                    break;
                case "EndGroup":
                    group = true;
                    break;
                default:
                    throw new Exception("unknown history");
            }
            undoHistories.Remove(history);
            redoHistories.Add(history);
            useHistory = true;
            if (group)
            {
                Undo(group);
            }
        }

        private void Redo(bool group=false)
        {
            if (redoHistories.Count == 0)
            {
                System.Windows.MessageBox.Show("无可重做项");
                return;
            }
            useHistory = false;
            History history = redoHistories.Last();
            switch (history.name)
            {
                case "MoveEdgeHead":
                    ReMoveEdgeHead((Edge)history.items["edge"], (double)history.items["movedDistanceX"], (double)history.items["movedDistanceY"]);
                    break;
                case "MoveEdgeTail":
                    ReMoveEdgeTail((Edge)history.items["edge"], (double)history.items["movedDistanceX"], (double)history.items["movedDistanceY"]);
                    break;
                case "AddNode_s":
                    ReAddNode((Node)history.items["node"]);
                    break;
                case "AddNode":
                    ReAddNode((Node)history.items["node"]);
                    break;
                case "AddEdge":
                    ReAddEdge((Edge)history.items["edge"]);
                    break;
                case "DeleteSymbol":
                    ReDeleteSymbol((Symbol)history.items["symbol"]);
                    break;
                case "MoveSymbol":
                    ReMoveSymbol((Symbol)history.items["symbol"], (double)history.items["movedDistanceX"], (double)history.items["movedDistanceY"]);
                    break;
                case "ResizeSymbol":
                    ReResizeSymbol((Symbol)history.items["symbol"], (Rect)history.items["oldBounds"], (Rect)history.items["bounds"]);
                    break;
                case "StartGroup":
                    group = true;
                    break;
                case "EndGroup":
                    group = false;
                    break;
                default:
                    throw new Exception("unknown history");
            }
            redoHistories.Remove(history);
            undoHistories.Add(history);
            useHistory = true;
            if (group)
            {
                Redo(group);
            }
        }
    }
}
