using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Microsoft.Expression.Shapes;
using NLog.Config;
using Misc;

namespace FLY.Thick.Blowing.UI.Fix.Client.UiModule
{
    /// <summary>
    /// UserControl1.xaml 的交互逻辑
    /// </summary>
    public partial class PolarChart : UserControl, IPolarChart, INotifyPropertyChanged
    {
        #region 私有成员变量
        /// <summary>
        /// 中心
        /// </summary>
        Point Center;
        /// <summary>
        /// 总半径
        /// </summary>
        double Radius;
        /// <summary>
        /// 分区环,宽度
        /// </summary>
        double BoltNoRingThickness;
        /// <summary>
        /// 最内环,宽度
        /// </summary>
        double InnerRingThickness;
        /// <summary>
        /// 图表,宽度
        /// </summary>
        double GraphThickness;

        double Avg;


        List<Arc> BoltArc = new List<Arc>();
        #endregion
        #region IPolarChart
        public static readonly DependencyProperty BoltCntProperty =
            DependencyProperty.Register(nameof(BoltCnt), typeof(int), typeof(PolarChart), new PropertyMetadata(
            88,
            new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                (d as PolarChart).NotifyPropertyChanged(nameof(BoltCnt));
            })));

        public int BoltCnt
        {
            get
            {
                return (int)GetValue(BoltCntProperty);
            }
            set
            {
                SetValue(BoltCntProperty, value);
            }
        }


        public static int GetBoltCnt(UIElement element)
        {
            return (int)element.GetValue(BoltCntProperty);
        }
        public static void SetBoltCnt(UIElement element, int boltCnt)
        {
            element.SetValue(BoltCntProperty, boltCnt);
        }





        public static readonly DependencyProperty MPIsRightProperty =
DependencyProperty.Register(nameof(MPIsRight), typeof(bool), typeof(PolarChart), new PropertyMetadata(
true,
new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    (d as PolarChart).NotifyPropertyChanged(nameof(MPIsRight));
})));
        public bool MPIsRight
        {
            get
            {
                return (bool)GetValue(MPIsRightProperty);
            }
            set
            {
                SetValue(MPIsRightProperty, value);
            }
        }

        public static bool GetMPIsRight(UIElement element)
        {
            return (bool)element.GetValue(MPIsRightProperty);
        }
        public static void SetMPIsRight(UIElement element, bool isRight)
        {
            element.SetValue(MPIsRightProperty, isRight);
        }




        public static readonly DependencyProperty OrgBoltNoProperty =
    DependencyProperty.Register(nameof(OrgBoltNo), typeof(int), typeof(PolarChart), new PropertyMetadata(
    1,
    new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as PolarChart).NotifyPropertyChanged(nameof(OrgBoltNo));
    })));
        public int OrgBoltNo
        {
            get
            {
                return (int)GetValue(OrgBoltNoProperty);
            }
            set
            {
                SetValue(OrgBoltNoProperty, value);
            }
        }


        public static int GetOrgBoltNo(UIElement element)
        {
            return (int)element.GetValue(OrgBoltNoProperty);
        }
        public static void SetOrgBoltNo(UIElement element, int value)
        {
            element.SetValue(OrgBoltNoProperty, value);
        }

        public static readonly DependencyProperty TolerancePercentProperty =
    DependencyProperty.Register(nameof(TolerancePercent), typeof(double), typeof(PolarChart), new PropertyMetadata(
0.05,
new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    (d as PolarChart).NotifyPropertyChanged(nameof(TolerancePercent));
})));
        public double TolerancePercent
        {
            get
            {
                return (double)GetValue(TolerancePercentProperty);
            }
            set
            {
                SetValue(TolerancePercentProperty, value);
            }
        }

        public static double GetTolerancePercent(UIElement element)
        {
            return (double)element.GetValue(TolerancePercentProperty);
        }
        public static void SetTolerancePercent(UIElement element, double value)
        {
            element.SetValue(TolerancePercentProperty, value);
        }

        public static readonly DependencyProperty YRangePercentProperty =
DependencyProperty.Register(nameof(YRangePercent), typeof(double), typeof(PolarChart), new PropertyMetadata(
3.0,
new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as PolarChart).NotifyPropertyChanged(nameof(YRangePercent));
})));
        public double YRangePercent
        {
            get
            {
                return (double)GetValue(YRangePercentProperty);
            }
            set
            {
                SetValue(YRangePercentProperty, value);
            }
        }

        public static double GetYRangePercent(UIElement element)
        {
            return (double)element.GetValue(YRangePercentProperty);
        }
        public static void SetYRangePercent(UIElement element, double value)
        {
            element.SetValue(YRangePercentProperty, value);
        }


        ObservableCollection<double> values = new ObservableCollection<double>();
        public ObservableCollection<double> Values
        {
            get
            {
                return values;
            }
            set
            {
                if (values != value)
                {
                    if (values != null)
                        values.CollectionChanged -= _values_CollectionChanged;

                    values = value;

                    values.CollectionChanged += _values_CollectionChanged;
                    NotifyPropertyChanged(nameof(Values));
                }
            }
        }
        System.Collections.Specialized.NotifyCollectionChangedEventHandler _values_CollectionChanged;

        List<Brush> AreaColors;
        #endregion
        public PolarChart()
        {
            InitializeComponent();

            AreaColors = FLY.Thick.Blowing.UI.Fix.Client.Themes.Colors.AreaColors;

            _values_CollectionChanged = new System.Collections.Specialized.NotifyCollectionChangedEventHandler(values_CollectionChanged);

            this.PropertyChanged += new PropertyChangedEventHandler(PolarChart_PropertyChanged);

            Init();

            DataBindAll_Init();
        }
        string[] propertynames_draw = new string[] { nameof(BoltCnt), nameof(OrgBoltNo), nameof(MPIsRight), nameof(TolerancePercent), nameof(YRangePercent) };
        void PolarChart_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (propertynames_draw.Contains(e.PropertyName))
            {
                Draw();
            }
        }
        void values_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            //根据修改, 操作mYVal, 与 IsEmpty
            switch (e.Action)
            {
                case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                    {
                        DataBindAll();
                    }
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Remove://修改X. 永远不执行
                    {
                        DataBindAll();
                    }
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Replace://修改Y
                    {
                        DataBindAll();
                    }
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Add://添加 X,Y
                    {
                        DataBindAll();
                    }
                    break;
            }
        }

        void Init()
        {
            Center = new Point(LayoutRoot.Width / 2, LayoutRoot.Width / 2);
            Radius = LayoutRoot.Width / 2;
            BoltNoRingThickness = 20;
            InnerRingThickness = (Radius - BoltNoRingThickness) / 4;
            GraphThickness = (Radius - InnerRingThickness - BoltNoRingThickness);

        }

        void Draw()
        {
            Clear();
            UpdateCalState();

            Draw_Background();
            Draw_Manual();
            Draw_BoltNo();
            Draw_Datas();
            Draw_TolerancePercent();
        }
        double TransformDegrees(double degrees)
        {
            if (MPIsRight)
                return -degrees + 90;
            else
                return -degrees - 90;
        }
        void Draw_BoltNo()
        {
            double startAngle;
            double endAngle;
            SolidColorBrush brush_line = new SolidColorBrush(Color.FromRgb(208, 208, 208));

            Arc arc_org = null;
            TextBlock t_org = null;

            for (int i = 0; i < BoltCnt; i++)
            {
                startAngle = TransformDegrees((i + 0 - (OrgBoltNo - 1) - 0.5) * 360 / BoltCnt);
                endAngle = TransformDegrees((i + 1 - (OrgBoltNo - 1) - 0.5) * 360 / BoltCnt);

                if (startAngle > endAngle)
                {
                    double tmp = endAngle;
                    endAngle = startAngle;
                    startAngle = tmp;
                }
                Arc arc = new Arc()
                {
                    ArcThickness = BoltNoRingThickness,
                    ArcThicknessUnit = Microsoft.Expression.Media.UnitType.Pixel,
                    StartAngle = startAngle,
                    EndAngle = endAngle,
                    Stretch = System.Windows.Media.Stretch.None,
                    Stroke = System.Windows.Media.Brushes.White,
                    Fill = System.Windows.Media.Brushes.Black,
                    Width = Radius * 2,
                    Height = Radius * 2,
                    Opacity = 0.8
                };


                Point p = Polar.ToPoint(
                    new Polar() { Degrees = (endAngle + startAngle) / 2, Radius = Radius - BoltNoRingThickness / 2 },
                    Center);

                TextBlock t = new TextBlock()
                {
                    TextWrapping = System.Windows.TextWrapping.NoWrap,

                    TextAlignment = System.Windows.TextAlignment.Center,
                    Width = 20,
                    Height = 15,
                    Text = (i + 1).ToString(),
                    FontFamily = new System.Windows.Media.FontFamily("Trebuchet MS"),
                    FontWeight = System.Windows.FontWeights.Bold,
                    Foreground = System.Windows.Media.Brushes.White
                };

                t.SetValue(Canvas.LeftProperty, p.X - t.Width / 2);
                t.SetValue(Canvas.TopProperty, p.Y - t.Height / 2);

                if ((i + 1) == 1) {
                    arc.Fill = System.Windows.Media.Brushes.Red;
                }

                if ((i + 1) == (int)OrgBoltNo)
                {
                    //凸显!!!!!!
                    arc_org = arc;
                    t_org = t;
                }
                else
                {
                    LayoutRoot.Children.Add(arc);
                    LayoutRoot.Children.Add(t);
                }
            }
            if (arc_org != null)
            {
                double w = arc_org.EndAngle - arc_org.StartAngle;
                arc_org.Fill = Brushes.White;// new SolidColorBrush(Color.FromRgb(0x57, 0x9a, 0xab));
                if (OrgBoltNo == 1) 
                {
                    arc_org.Fill = Brushes.Red;
                }

                arc_org.Stroke = Brushes.Black;
                arc_org.Width += arc_org.ArcThickness;
                arc_org.ArcThickness *= 2;
                arc_org.Height = arc_org.Width;
                arc_org.Margin = new Thickness(Radius - arc_org.Width / 2);
                arc_org.StartAngle -= w / 4;
                arc_org.EndAngle += w / 4;

                LayoutRoot.Children.Add(arc_org);

                t_org.Foreground = Brushes.Black;
                if (OrgBoltNo == 1)
                {
                    t_org.Foreground = Brushes.White;
                }
                LayoutRoot.Children.Add(t_org);
            }
        }
        void Draw_Manual()
        {
            double startAngle;
            double endAngle;
            //每5个一条线
            int XStep = 5;
            
            for(int i=0;i<BoltCnt;i+=XStep)
            {
                int start_boltindex = i;

                startAngle = TransformDegrees((start_boltindex + 0 - (OrgBoltNo - 1) - 0.5) * 360 / BoltCnt);

                Point p1 = Polar.ToPoint(
                    new Polar() { Degrees = startAngle, Radius = InnerRingThickness + GraphThickness },
                    Center);

                Point p2 = Polar.ToPoint(
                    new Polar() { Degrees = startAngle, Radius = InnerRingThickness },
                    Center);

                Line l = new Line() { X1 = p1.X, Y1 = p1.Y, X2 = p2.X, Y2 = p2.Y, Stroke = new SolidColorBrush(Colors.LightGray) };
                LayoutRoot.Children.Add(l);
            }
        }
        void Draw_Background()
        {
            SolidColorBrush brush_alarm = new SolidColorBrush(Colors.LightGray);
            double r = InnerRingThickness;
            //最里面的圆
            Ellipse ellipse_inner = new Ellipse()
            {
                Width = r * 2,
                Height = r * 2,
                Stroke = Brushes.Black,
                Margin = new Thickness(Radius - r)
            };
            LayoutRoot.Children.Add(ellipse_inner);
            //目标线
            r = InnerRingThickness + GraphThickness * 0.5;
            Ellipse ellipse_target = new Ellipse()
            {
                Width = r * 2,
                Height = r * 2,
                Stroke = AreaColors[0],
                Margin = new Thickness(Radius - r),
                StrokeThickness = 1
            };
            LayoutRoot.Children.Add(ellipse_target);

            double toleranceThickness = GraphThickness / (2 * YRangePercent);
            double target_r = r;

            for (int i = 1; i < YRangePercent; i++) 
            {
                Brush stroke;
                if (i == 1)
                {
                    stroke = AreaColors[1];
                }
                else if (i == 2)
                {
                    stroke = AreaColors[2];
                }
                else {
                    stroke = brush_alarm;
                }


                //-公差线
                r = target_r + toleranceThickness * i;
                Ellipse ellipse_alarm1 = new Ellipse()
                {
                    Width = r * 2,
                    Height = r * 2,
                    Stroke = stroke,
                    Margin = new Thickness(Radius - r),
                    StrokeThickness = 1
                };

                //+公差线
                r = target_r - toleranceThickness * i;
                Ellipse ellipse_alarm2 = new Ellipse()
                {
                    Width = r * 2,
                    Height = r * 2,
                    Stroke = stroke,
                    Margin = new Thickness(Radius - r),
                    StrokeThickness = 1
                };

                LayoutRoot.Children.Add(ellipse_alarm1);
                LayoutRoot.Children.Add(ellipse_alarm2);
            }
        }
        void Draw_Datas()//初始化所有 BoltArc
        {
            double startAngle;
            double endAngle;

            if (BoltArc.Count > 0)
            {
                foreach (Arc arc in BoltArc)
                    LayoutRoot.Children.Remove(arc);
                BoltArc.Clear();
            }

            for (int i = 0; i < BoltCnt; i++)
            {
                startAngle = TransformDegrees((i + 0 - (OrgBoltNo - 1) - 0.5) * 360 / BoltCnt);
                endAngle = TransformDegrees((i + 1 - (OrgBoltNo - 1) - 0.5) * 360 / BoltCnt);

                if (startAngle > endAngle)
                {
                    double tmp = endAngle;
                    endAngle = startAngle;
                    startAngle = tmp;
                }

                Arc arc = new Arc()
                {
                    ArcThicknessUnit = Microsoft.Expression.Media.UnitType.Pixel,
                    StartAngle = startAngle,
                    EndAngle = endAngle,
                    Stretch = System.Windows.Media.Stretch.None,
                    Stroke = System.Windows.Media.Brushes.Black,
                    StrokeThickness = 1
                };

                Update_OneData(i, arc);

                LayoutRoot.Children.Add(arc);
                BoltArc.Add(arc);
            }
        }

        void Draw_TolerancePercent()
        {
            double startAngle = TransformDegrees(0);
            double percent = TolerancePercent;
            if (percent < 0.01)
                percent = 0.01;
            double toleranceThickness = GraphThickness / (2 * YRangePercent);
            double target_r = InnerRingThickness + GraphThickness * 0.5;

            ////Value 外小 内大
            ////负公差
            //Draw_Marker(new Polar() { Degrees = startAngle, Radius = target_r + toleranceThickness }, $"{(-100 * percent):F0}%");

            ////正公差
            //Draw_Marker(new Polar() { Degrees = startAngle, Radius = target_r - toleranceThickness }, $"{(+100 * percent):F0}%");

            //Value 外大 内小
            //负公差
            Draw_Marker(new Polar() { Degrees = startAngle, Radius = target_r - toleranceThickness }, $"{(-100 * percent):F0}%");

            //正公差
            Draw_Marker(new Polar() { Degrees = startAngle, Radius = target_r + toleranceThickness }, $"{(+100 * percent):F0}%");
        }
        void Draw_Marker(Polar polar, string s)
        {
            Point p1 = Polar.ToPoint(
                polar,
                Center);

            SolidColorBrush brush_alarm = new SolidColorBrush(Color.FromRgb(0xff, 0xc1, 0xc1));
            SolidColorBrush brush_line = new SolidColorBrush(Color.FromRgb(208, 208, 208));
            double r = 15;
            //底
            Ellipse ellipse_background = new Ellipse()
            {
                Width = r * 2,
                Height = r * 2,
                Fill = System.Windows.Media.Brushes.Red,
                Opacity = 0.8,
                Stroke = System.Windows.Media.Brushes.Black,
                StrokeThickness = 1
            };
            ellipse_background.SetValue(Canvas.LeftProperty, p1.X - ellipse_background.Width / 2);
            ellipse_background.SetValue(Canvas.TopProperty, p1.Y - ellipse_background.Width / 2);

            TextBlock t = new TextBlock()
            {
                TextWrapping = System.Windows.TextWrapping.NoWrap,

                TextAlignment = System.Windows.TextAlignment.Center,
                Width = 20,
                Height = 12,
                Text = s,
                FontFamily = new System.Windows.Media.FontFamily("Trebuchet MS"),
                FontWeight = System.Windows.FontWeights.Bold,
                Foreground = System.Windows.Media.Brushes.White,
                FontSize = 10
            };

            t.SetValue(Canvas.LeftProperty, p1.X - t.Width / 2);
            t.SetValue(Canvas.TopProperty, p1.Y - t.Height / 2);

            LayoutRoot.Children.Add(ellipse_background);
            LayoutRoot.Children.Add(t);
        }
        void Clear()
        {
            LayoutRoot.Children.Clear();
            BoltArc.Clear();
        }

        void Update_OneData(int index)
        {
            if (index >= BoltArc.Count)
                return;

            Update_OneData(index, BoltArc[index]);
        }
        
        void Update_OneData(int index, Arc arc)
        { 
            double percent = TolerancePercent;
            if (percent < 0.01)
                percent = 0.01;
            
            double r = 0;
            if (Values != null && index < Values.Count && !double.IsNaN(Values[index]))
            {
                r = ((Values[index] - Avg) / Avg) / (2 * YRangePercent * percent) * GraphThickness;
                arc.Visibility = Visibility.Visible;
            }
            else {
                arc.Visibility = Visibility.Hidden;
            }

            double target_r = InnerRingThickness + GraphThickness * 0.5;

            //--------------------------------------------------------------
            //限制
            if (r > GraphThickness * 0.5)
            {
                r = GraphThickness * 0.5;
            }
            else if (r < -GraphThickness * 0.5)
            {
                r = -GraphThickness * 0.5;
            }


            //--------------------------------------------------------------
            //改变颜色
            double toleranceThickness = GraphThickness / (YRangePercent * 2);

            if (r > toleranceThickness * 2)
            {
                arc.Fill = AreaColors[2];
            }
            else if (r < -toleranceThickness * 2)
            {
                arc.Fill = AreaColors[2];
            }

            else if (r > toleranceThickness)
            {
                arc.Fill = AreaColors[1];
            }
            else if (r < -toleranceThickness)
            {
                arc.Fill = AreaColors[1];
            }
            else
            {
                arc.Fill = AreaColors[0];
            }

            //扇型的厚度
            arc.ArcThickness = Math.Abs(r);

            //扇型最外圆直径

            //Value 外小 内大
            //if (r < 0)
            //    arc.Width = (target_r - r) * 2;
            //else
            //    arc.Width = target_r * 2;
            //Value 外大 内小
            if (r > 0)
                arc.Width = (target_r + r) * 2;
            else
                arc.Width = target_r * 2;


            arc.Height = arc.Width;
            arc.Margin = new Thickness(Radius - arc.Width / 2);
            
        }
        /// <summary>
        /// 与 Multi,EmptyValue,DataFirst,DataLast 相关
        /// </summary>
        void UpdateCalState()
        {
            if (Values == null)
                return;
            List<double> datlist;
            if (BoltCnt >= Values.Count())
            {
                datlist = Values.ToList();
            }
            else
            {
                datlist = Values.ToList().GetRange(0, BoltCnt);
            }
            double avg = datlist.AverageNoNull();
            if (!double.IsNaN(avg))
                Avg = avg;
            return;
        }
        void Update_Datas()
        {
            UpdateCalState();
            for (int i = 0; i < BoltCnt; i++)
                Update_OneData(i);
        }
        
        //public void Draw
        
        #region INotifyPropertyChanged 成员
        public void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            Draw();

        }



        bool batabindall_flag = false;
        System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
        void DataBindAll_Init()
        {
            timer = new System.Windows.Threading.DispatcherTimer();
            timer.Tick += new EventHandler(delegate (object sender, EventArgs e)
            {
                if (batabindall_flag)
                {
                    batabindall_flag = false;
                    Update_Datas();
                }
            });

            timer.Interval = TimeSpan.FromSeconds(0.2);
            timer.Start();
        }
        void DataBindAll()
        {
            batabindall_flag = true;
        }
    }
    public interface IPolarChart
    {
        /// <summary>
        /// 分区数
        /// </summary>
        int BoltCnt { get; set; }

        /// <summary>
        /// 测厚仪测量点位置方向:Left, Right (也就是三角形在左还是右)
        /// </summary>
        bool MPIsRight { get; set; }

        /// <summary>
        /// 复位分区号,也就是三角形对应的 分区号
        /// </summary>
        int OrgBoltNo { get; set; }

        /// <summary>
        /// 公差%
        /// </summary>
        double TolerancePercent { get; set; }

        /// <summary>
        /// Y轴是 TolerancePercent 的倍数
        /// </summary>
        double YRangePercent { get; set; }
        /// <summary>
        /// 数据源
        /// </summary>
        ObservableCollection<double> Values { get; set; }
    }

    /// <summary>
    /// Polar 12点方向=0°,3点方向=90°,6点方向=180°,9点方向=270°
    /// Point 左上角 x=0,y=0; 右上角 x=100, y=0; 左下角 x=0,y=100;
    /// </summary>
    class Polar
    {
        public double Degrees;//角度制!!!
        public double Radius;
        public static Point ToPoint(Polar polar, Point center)
        {
            Point p = new Point();
            Vector v = new Vector();
            v.Y = -polar.Radius * Math.Cos(DegreesToRadians(polar.Degrees));
            v.X = polar.Radius * Math.Sin(DegreesToRadians(polar.Degrees));
            p = center + v;
            return p;
        }
        public static double DegreesToRadians(double degrees)
        {
            double radians = Math.PI / 180 * degrees;
            return radians;
        }

    }
}