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;
using System.Reflection;
using System.Windows.Input.StylusPlugIns;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private bool IsChildOf(DependencyObject child, DependencyObject parent)
        {
            var currentParent = VisualTreeHelper.GetParent(child);
            while (currentParent != null)
            {
                if (currentParent == parent)
                {
                    return true;
                }
                currentParent = VisualTreeHelper.GetParent(currentParent);
            }
            return false;
        }

        private T FindParent<T>(DependencyObject child) where T : DependencyObject
        {
            DependencyObject parent = VisualTreeHelper.GetParent(child);
            while (parent != null && !(parent is T))
            {
                parent = VisualTreeHelper.GetParent(parent);
            }
            return parent as T;
        }

        private double EulerDistance(double x1, double y1, double x2, double y2)
        {
            return Math.Sqrt(Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2));
        }

        private double EulerNorm(double x, double y)
        {
            return Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2));
        }

        private double CosineValue(double x1, double y1, double x2, double y2)
        {
            return ((x1 - x2) * (y1 - y2)) / (EulerNorm(x1, y1) * EulerNorm(x2, y2));
        }

        private double[] IntersectionPoint(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
        {
            double x0 = ((x3 - x4) * (x2 * y1 - x1 * y2) - (x1 - x2) * (x4 * y3 - x3 * y4)) / ((x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4));
            double y0 = ((y3 - y4) * (y2 * x1 - y1 * x2) - (y1 - y2) * (y4 * x3 - y3 * x4)) / ((y3 - y4) * (x1 - x2) - (y1 - y2) * (x3 - x4));
            return new double[] { x0, y0 };
        }

        private bool IsIntersecting(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
        {
            double x13 = x3 - x1, y13 = y3 - y1;
            double x14 = x4 - x1, y14 = y4 - y1;
            double x23 = x3 - x2, y23 = y3 - y2;
            double x24 = x4 - x2, y24 = y4 - y2;
            double sind1 = (x13 * y14 - x14 * y13) * (x23 * y24 - x24 * y23);
            double sind2 = (x13 * y23 - x23 * y13) * (x14 * y24 - x24 * y14);
            return (sind1 <= 0 && sind2 <= 0);
        }

        private bool IsBetween(double x1, double y1, double x2, double y2, double x3, double y3)
        {
            return ((x3 - x1) * (x3 - x2) <= 0 && (y3 - y1) * (y3 - y2) <= 0);
        }

        private double[] PerpendicularFoot(double x1, double y1, double x2, double y2, double x3, double y3)
        {
            double k = ((x3 - x1) * (x2 - x1) + (y3 - y1) * (y2 - y1)) / ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
            double x0 = x1 + k * (x2 - x1);
            double y0 = y1 + k * (y2 - y1);
            return new double[] { x0, y0 };
        }

        public static StylusPointCollection ApplyLowPassFilter(StylusPointCollection points, double alpha)
        {
            StylusPointCollection filteredPoints = new StylusPointCollection();
            StylusPoint prevPoint = points[0];

            foreach (StylusPoint point in points)
            {
                double filteredX = alpha * point.X + (1 - alpha) * prevPoint.X;
                double filteredY = alpha * point.Y + (1 - alpha) * prevPoint.Y;
                filteredPoints.Add(new StylusPoint(filteredX, filteredY));
                prevPoint = new StylusPoint(filteredX, filteredY);
            }

            return filteredPoints;
        }

        public StylusPointCollection ApplyRandomPerturbation(StylusPointCollection points, double maxPerturbation)
        {
            Random random = new Random();
            StylusPointCollection perturbedPoints = new StylusPointCollection();

            perturbedPoints.Add(points[0]);
            for (int i = 1; i < points.Count - 1; i++)
            {
                double dx = (double)(random.NextDouble() * 2 - 1) * maxPerturbation;
                double dy = (double)(random.NextDouble() * 2 - 1) * maxPerturbation;
                perturbedPoints.Add(new StylusPoint(points[i].X + dx, points[i].Y + dy));
            }
            perturbedPoints.Add(points.Last());

            return perturbedPoints;
        }

        public StylusPointCollection ApplyBezierCurveInterpolation(StylusPointCollection points, double numSegments)
        {
            Random random = new Random();
            StylusPointCollection interpolatedPoints = new StylusPointCollection();

            //interpolatedPoints.Add(points[0]);
            for (int i = 0; i < points.Count - 1; i++)
            {
                StylusPoint p0 = points[i];
                StylusPoint p1 = points[i + 1];

                double segments = numSegments * EulerDistance(p0.X, p0.Y, p1.X, p1.Y) / 10;

                for (int j = 0; j <= segments; j++)
                {
                    double t = (double)j / segments;
                    double x = (1 - t) * p0.X + t * p1.X;
                    double y = (1 - t) * p0.Y + t * p1.Y;
                    interpolatedPoints.Add(new StylusPoint(x, y));
                }
            }
            interpolatedPoints.Add(points.Last());

            return interpolatedPoints;
        }

        public StylusPointCollection ApplyBrushStrokeSimulation(StylusPointCollection points, double strokeLength, double strokeWidth)
        {
            Random random = new Random();
            StylusPointCollection brushStrokePoints = new StylusPointCollection();

            for (int i = 0; i < points.Count - 1; i++)
            {
                StylusPoint p0 = points[i];
                StylusPoint p1 = points[i + 1];

                double dx = p1.X - p0.X;
                double dy = p1.Y - p0.Y;
                double distance = (double)Math.Sqrt(dx * dx + dy * dy);
                int numStrokes = (int)(distance / strokeLength);

                for (int j = 0; j < numStrokes; j++)
                {
                    double t = (double)j / numStrokes;
                    double x = p0.X + t * dx;
                    double y = p0.Y + t * dy;
                    double offsetX = (double)(random.NextDouble() * 2 - 1) * strokeWidth;
                    double offsetY = (double)(random.NextDouble() * 2 - 1) * strokeWidth;
                    brushStrokePoints.Add(new StylusPoint(x + offsetX, y + offsetY));
                }
            }

            return brushStrokePoints;
        }

        public StylusPointCollection ApplyHandDrawnStyle(StylusPointCollection points)
        {
            StylusPoint point = points[points.Count - 1];
            points = ApplyBezierCurveInterpolation(points, 0.2);
            points = ApplyRandomPerturbation(points, 2.8);
            points = ApplyBezierCurveInterpolation(points, 3);
            points = ApplyRandomPerturbation(points, 1.2);
            //stroke.StylusPoints = ApplyBrushStrokeSimulation(stroke.StylusPoints, 1, 1);
            points = ApplyLowPassFilter(points, 0.3);
            //stroke.StylusPoints = ApplyLowPassFilter(stroke.StylusPoints, 0.6);
            points[points.Count - 1] = point;
            return points;
        }

        private StrokeCollection CreateDashedStrokes(Stroke originalStroke)
        {
            StrokeCollection dashedStrokes = new StrokeCollection();
            var stylusPoints = originalStroke.StylusPoints;
            int dashLength = 4;  // 虚线每段的长度
            int spaceLength = 2;  // 虚线间隔的长度
            int count = 0;
            bool drawing = true;

            StylusPointCollection pointsCollection = new StylusPointCollection();
            foreach (var point in stylusPoints)
            {
                if (drawing)
                {
                    pointsCollection.Add(point);
                    count++;
                    if (count == dashLength)
                    {
                        dashedStrokes.Add(new Stroke(pointsCollection, originalStroke.DrawingAttributes));
                        pointsCollection = new StylusPointCollection();
                        drawing = false;
                        count = 0;
                    }
                }
                else
                {
                    count++;
                    if (count == spaceLength)
                    {
                        drawing = true;
                        count = 0;
                    }
                }
            }

            // 添加最后一段，如果是绘制状态
            if (drawing && pointsCollection.Count > 0)
            {
                dashedStrokes.Add(new Stroke(pointsCollection, originalStroke.DrawingAttributes));
            }

            return dashedStrokes;
        }

        private System.Windows.Media.Color LightColor(System.Windows.Media.Color color, double factor, double blendFactor)
        {
            int r, g, b;
            // factor > 1.0 makes the color lighter, factor < 1.0 makes it darker.
            r = (int)(color.R + (255 - color.R) * factor);
            g = (int)(color.G + (255 - color.G) * factor);
            b = (int)(color.B + (255 - color.B) * factor);
            color = Color.FromArgb(color.A, (byte)Math.Min(r, 255), (byte)Math.Min(g, 255), (byte)Math.Min(b, 255));
            r = (int)(color.R + (255 - color.R) * blendFactor);
            g = (int)(color.G + (255 - color.G) * blendFactor);
            b = (int)(color.B + (255 - color.B) * blendFactor);
            color = Color.FromArgb(color.A, (byte)r, (byte)g, (byte)b);
            return color;
        }
    }
}
