using ComPDFKit.Measure;
using ComPDFKit.PDFAnnotation;
using Compdfkit_Tools.Helper;
using Compdfkit_Tools.PDFControl;
using ComPDFKitViewer;
using ComPDFKitViewer.AnnotEvent;
using ComPDFKitViewer.PdfViewer;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
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.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;



namespace Compdfkit_Tools.Measure
{
    /// <summary>
    /// MeasureControl.xaml 的交互逻辑
    /// </summary>
    public partial class MeasureControl : UserControl
    {
        public MeasurePropertyControl measurePropertyControl = new MeasurePropertyControl();
        private CPDFDisplaySettingsControl displaySettingsControl;

        private PDFViewControl PdfViewControl = new PDFViewControl();

        private PanelState panelState = PanelState.GetInstance();

        public event EventHandler ExpandEvent;

        public MeasureControl()
        {
            InitializeComponent();
            MeasureSetting.MeasureChanged += MeasureSetting_MeasureChanged;
        }

        private void MeasureSetting_MeasureChanged(object sender, MeasureEventArgs e)
        {
            InfoPanel.SetMeasureType(e.Type);
            InfoPanel.SetMeasureInfo(e);
        }
        #region Init PDFViewer

        public void InitWithPDFViewer(PDFViewControl pdfViewControl, CPDFViewer pdfViewer)
        {
            PdfViewControl = pdfViewControl;
            PdfViewControl.PDFView = pdfViewer;
            PDFMeasureTool.InitWithPDFViewer(pdfViewer, measurePropertyControl, this);
            FloatPageTool.InitWithPDFViewer(pdfViewer);
            PDFGrid.Child = PdfViewControl;

            panelState.PropertyChanged -= PanelState_PropertyChanged;
            panelState.PropertyChanged += PanelState_PropertyChanged;
            pdfViewControl.PDFView.AnnotActiveHandler -= PDFView_AnnotActiveHandler;
            pdfViewControl.PDFView.AnnotActiveHandler += PDFView_AnnotActiveHandler;
            pdfViewControl.PDFView.AnnotCommandHandler -= PDFView_AnnotCommandHandler;
            pdfViewControl.PDFView.AnnotCommandHandler += PDFView_AnnotCommandHandler;
            SetInfoPanelVisble(false, false);
        }

        private void PDFView_AnnotCommandHandler(object sender, AnnotCommandArgs e)
        {
            switch (e.CommandType)
            {
                case CommandType.Context:
                    if (e.CommandTarget == TargetType.Annot && e.PressOnAnnot)
                    {
                        e.Handle = true;
                        e.PopupMenu = new ContextMenu();
                        e.PopupMenu.Items.Add(new MenuItem() { Header = "Delete", Command = ApplicationCommands.Delete, CommandTarget = (UIElement)sender });
                        MenuItem menuItem = new MenuItem();
                        menuItem.Header = "Measurement Settings";
                        menuItem.Click += (item, param) =>
                        {
                            SettingPanel.UpdateArgsList = e.AnnotEventArgsList;
                            SettingPanel.BindMeasureSetting();
                            SetInfoPanelVisble(false, true);
                        };

                        MenuItem propertyItem = new MenuItem();
                        propertyItem.Header = "Properties";
                        propertyItem.Click += (item, param) =>
                        {
                            ExpandEvent?.Invoke(this, new EventArgs());
                        };
                        e.PopupMenu.Items.Add(menuItem);
                        e.PopupMenu.Items.Add(propertyItem);
                    }
                    break;

                case CommandType.Delete:
                    e.DoCommand();
                    break;
                default:
                    break;
            }
        }



        private void PDFView_AnnotActiveHandler(object sender, AnnotAttribEvent e)
        {
            if (e == null || e.IsAnnotCreateReset)
            {
                if (e == null)
                {
                    measurePropertyControl?.ClearMeasurePanel();
                    if(PDFMeasureTool.ToolChecked()==false)
                    {
                        SetInfoPanelVisble(false, false);
                    }
                }
                return;
            }
            else
            {
                switch (e.GetAnnotTypes())
                {
                    case AnnotArgsType.LineMeasure:
                        LineMeasureArgs LineArgs = e.GetAnnotHandlerEventArgs(AnnotArgsType.LineMeasure).First() as LineMeasureArgs;
                        panelState.RightPanel = PanelState.RightPanelState.PropertyPanel;
                        measurePropertyControl.SetPropertyForMeasureCreate(LineArgs, e);
                        SetInfoPanelVisble(true, false);
                        SetMeasureInfoPanel(LineArgs.GetPDFAnnot(), LineArgs);
                        break;
                    case AnnotArgsType.PolygonMeasure:
                        PolygonMeasureArgs polygonArgs = e.GetAnnotHandlerEventArgs(AnnotArgsType.PolygonMeasure).First() as PolygonMeasureArgs;
                        panelState.RightPanel = PanelState.RightPanelState.PropertyPanel;
                        measurePropertyControl.SetPropertyForMeasureCreate(polygonArgs, e);
                        SetInfoPanelVisble(true, false);
                        SetMeasureInfoPanel(polygonArgs.GetPDFAnnot(),polygonArgs);
                        break;

                    case AnnotArgsType.PolyLineMeasure:
                        PolyLineMeasureArgs polyLineArgs = e.GetAnnotHandlerEventArgs(AnnotArgsType.PolyLineMeasure).First() as PolyLineMeasureArgs;
                        panelState.RightPanel = PanelState.RightPanelState.PropertyPanel;
                        measurePropertyControl.SetPropertyForMeasureCreate(polyLineArgs, e);
                        SetInfoPanelVisble(true, false);
                        SetMeasureInfoPanel(polyLineArgs.GetPDFAnnot(),polyLineArgs);
                        break;
                }
            }
        }

        private void SetMeasureInfoPanel(CPDFAnnotation rawAnnot,AnnotHandlerEventArgs annotArgs=null)
        {
            if (rawAnnot == null)
            {
                return;
            }
            try
            {
                if (rawAnnot.Type == C_ANNOTATION_TYPE.C_ANNOTATION_LINE)
                {
                    CPDFLineAnnotation lineAnnot = rawAnnot as CPDFLineAnnotation;
                    if (lineAnnot.IsMersured() && lineAnnot.Points != null && lineAnnot.Points.Count() == 2)
                    {
                        CPDFDistanceMeasure lineMeasure = lineAnnot.GetDistanceMeasure();
                        CPDFMeasureInfo measureInfo = lineMeasure.MeasureInfo;
                        Vector standVector = new Vector(1, 0);

                        Point startPoint = new Point(lineAnnot.Points[0].x, lineAnnot.Points[0].y);
                        Point endPoint = new Point(lineAnnot.Points[1].x, lineAnnot.Points[1].y);
                        Vector movevector = endPoint - startPoint;
                        double inch = movevector.Length / 72D;
                        double rate = measureInfo.RulerTranslate / measureInfo.RulerBase;
                        double ratio = GetMeasureRatio(measureInfo.RulerBaseUnit);
                        double showLenght = inch * rate / ratio;

                        MeasureEventArgs measureEvent = new MeasureEventArgs();
                        measureEvent.Angle = (int)Math.Abs(Vector.AngleBetween(movevector, standVector));
                        measureEvent.RulerTranslateUnit = measureInfo.RulerTranslateUnit;
                        measureEvent.RulerTranslate = measureInfo.RulerTranslate;
                        measureEvent.RulerBase = measureInfo.RulerBase;
                        measureEvent.RulerBaseUnit = measureInfo.RulerBaseUnit;
                        measureEvent.MousePos = new Point(
                           (int)Math.Abs(movevector.X),
                           (int)Math.Abs(movevector.Y));
                        measureEvent.Type = CPDFMeasureType.CPDF_DISTANCE_MEASURE;
                        NumberFormatInfo formatInfo = new NumberFormatInfo();
                        formatInfo.NumberDecimalDigits = Math.Abs(measureInfo.Precision).ToString().Length - 1;
                        measureEvent.Distance = showLenght.ToString("N", formatInfo) + measureInfo.RulerTranslateUnit;
                        measureEvent.Precision = GetMeasureShowPrecision(measureInfo.Precision);

                        MeasureSetting.InvokeMeasureChangeEvent(this, measureEvent);
                        if(annotArgs!=null)
                        {
                            SettingPanel.UpdateArgsList =new List<AnnotHandlerEventArgs> { annotArgs};
                        }
                    }
                }

                if (rawAnnot.Type == C_ANNOTATION_TYPE.C_ANNOTATION_POLYLINE)
                {
                    CPDFPolylineAnnotation polylineAnnot = rawAnnot as CPDFPolylineAnnotation;
                    if (polylineAnnot.IsMersured() && polylineAnnot.Points != null && polylineAnnot.Points.Count() >= 2)
                    {
                        double totalInch = 0;
                        for (int i = 0; i < polylineAnnot.Points.Count - 1; i++)
                        {
                            Point endLinePoint = new Point(
                                polylineAnnot.Points[i + 1].x,
                                polylineAnnot.Points[i + 1].y
                                );
                            Point startLinePoint = new Point(
                                polylineAnnot.Points[i].x,
                                polylineAnnot.Points[i].y
                                );
                            Vector subVector = endLinePoint - startLinePoint;
                            totalInch += subVector.Length;
                        }
                        totalInch = totalInch / 72D;
                        CPDFPerimeterMeasure lineMeasure = polylineAnnot.GetPerimeterMeasure();
                        CPDFMeasureInfo measureInfo = lineMeasure.MeasureInfo;

                        double rate = measureInfo.RulerTranslate / measureInfo.RulerBase;
                        double ratio = GetMeasureRatio(measureInfo.RulerBaseUnit);
                        double showLenght = totalInch * rate / ratio;

                        MeasureEventArgs measureEvent = new MeasureEventArgs();
                        measureEvent.Angle = 0;
                        //if (polylineAnnot.Points.Count() >= 3)
                        //{
                        //    int count = polylineAnnot.Points.Count();
                        //    Point endLinePoint = new Point(
                        //       polylineAnnot.Points[count - 1].x,
                        //       polylineAnnot.Points[count - 1].y
                        //       );
                        //    Point cornerLinePoint = new Point(
                        //        polylineAnnot.Points[count - 2].x,
                        //        polylineAnnot.Points[count - 2].y
                        //        );
                        //    Point startLinePoint = new Point(
                        //        polylineAnnot.Points[count - 3].x,
                        //        polylineAnnot.Points[count - 3].y
                        //        );
                        //    Vector startVector = startLinePoint - cornerLinePoint;
                        //    Vector endvector = endLinePoint - cornerLinePoint;
                        //    measureEvent.Angle = (int)Math.Abs(Vector.AngleBetween(endvector, startVector));
                        //}
                        measureEvent.RulerTranslateUnit = measureInfo.RulerTranslateUnit;
                        measureEvent.RulerTranslate = measureInfo.RulerTranslate;
                        measureEvent.RulerBase = measureInfo.RulerBase;
                        measureEvent.RulerBaseUnit = measureInfo.RulerBaseUnit;
                        measureEvent.Precision = GetMeasureShowPrecision(measureInfo.Precision);
                        measureEvent.Type = CPDFMeasureType.CPDF_PERIMETER_MEASURE;
                        NumberFormatInfo formatInfo = new NumberFormatInfo();
                        formatInfo.NumberDecimalDigits = Math.Abs(measureInfo.Precision).ToString().Length - 1;
                        measureEvent.Distance = showLenght.ToString("N", formatInfo) + measureInfo.RulerTranslateUnit;
                        MeasureSetting.InvokeMeasureChangeEvent(this, measureEvent);
                        if (annotArgs != null)
                        {
                            SettingPanel.UpdateArgsList = new List<AnnotHandlerEventArgs> { annotArgs };
                        }
                    }
                }

                if(rawAnnot.Type== C_ANNOTATION_TYPE.C_ANNOTATION_POLYGON)
                {
                    CPDFPolygonAnnotation Annot = rawAnnot as CPDFPolygonAnnotation;

                    double Area = Annot.GetMeasureValue(CPDFCaptionType.CPDF_CAPTION_AREA);
                    double inch = MeasureSetting.GetMeasurePDFArea(Area);
                    double Length = Annot.GetMeasureValue(CPDFCaptionType.CPDF_CAPTION_LENGTH);
                    double currentInch = MeasureSetting.GetMeasurePDFLength(Length);

                    MeasureEventArgs measureEvent = new MeasureEventArgs();
                    measureEvent.RulerTranslateUnit = MeasureSetting.RulerTranslateUnit;
                    measureEvent.RulerTranslate = MeasureSetting.RulerTranslate;
                    measureEvent.RulerBase = MeasureSetting.RulerBase;
                    measureEvent.RulerBaseUnit = MeasureSetting.RulerBaseUnit;
                    measureEvent.Precision = MeasureSetting.Precision;
                    measureEvent.Type = CPDFMeasureType.CPDF_AREA_MEASURE;
                    measureEvent.Distance = string.Format(
                        "{0}{1}",
                        MeasureSetting.GetPrecisionData(currentInch),
                        MeasureSetting.RulerTranslateUnit);
                    measureEvent.Area = string.Format(
                        "{0} sq {1}", 
                        MeasureSetting.GetPrecisionData(inch), 
                        MeasureSetting.RulerTranslateUnit);

                    MeasureSetting.InvokeMeasureChangeEvent(this, measureEvent);
                    if (annotArgs != null)
                    {
                        SettingPanel.UpdateArgsList = new List<AnnotHandlerEventArgs> { annotArgs };
                    }
                }
            }
            catch (Exception e)
            {

            }
        }

        private double GetMeasureRatio(string baseUnit)
        {
            if (baseUnit == CPDFMeasure.CPDF_PT)
            {
                return 1 / 72;
            }
            if (baseUnit == CPDFMeasure.CPDF_IN)
            {
                return 1;
            }
            if (baseUnit == CPDFMeasure.CPDF_MM)
            {
                return 1 / 25.4;
            }
            if (baseUnit == CPDFMeasure.CPDF_CM)
            {
                return 1 / 2.54;
            }
            if (baseUnit == CPDFMeasure.CPDF_M)
            {
                return 1 / 0.0254;
            }
            if (baseUnit == CPDFMeasure.CPDFO_KM)
            {
                return 1 / 0.0254 / 1000;
            }

            if (baseUnit == CPDFMeasure.CPDF_FT)
            {
                return 12;
            }
            if (baseUnit == CPDFMeasure.CPDF_YD)
            {
                return 36;
            }
            if (baseUnit == CPDFMeasure.CPDF_MI)
            {
                return 63360;
            }
            return 0;
        }

        private double GetMeasureShowPrecision(int precision)
        {
            if (precision == CPDFMeasure.PRECISION_VALUE_ZERO)
            {
                return 1;
            }
            if (CPDFMeasure.PRECISION_VALUE_ONE == precision)
            {
                return 0.1;
            }
            if (CPDFMeasure.PRECISION_VALUE_TWO == precision)
            {
                return 0.01;
            }
            if (CPDFMeasure.PRECISION_VALUE_THREE == precision)
            {
                return 0.001;
            }
            if (CPDFMeasure.PRECISION_VALUE_FOUR == precision)
            {
                return 0.0001;
            }
            return 0;
        }

        public void SetSettingsControl(CPDFDisplaySettingsControl cPDFDisplaySettingsControl)
        {
            displaySettingsControl = cPDFDisplaySettingsControl;
        }

        public void ClearAllToolState()
        {
            PDFMeasureTool.ClearAllToolState();
        }
        public void ClearViewerControl()
        {
            PDFGrid.Child = null;
            BotaContainer.Child = null;
            PropertyContainer.Child = null;
            displaySettingsControl = null;
        }

        private void PanelState_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(PanelState.IsLeftPanelExpand))
            {
                ExpandLeftPanel(panelState.IsLeftPanelExpand);
            }
            else if (e.PropertyName == nameof(PanelState.RightPanel))
            {
                if (panelState.RightPanel == PanelState.RightPanelState.PropertyPanel)
                {
                    ExpandRightPropertyPanel(measurePropertyControl, Visibility.Visible);
                }
                else if (panelState.RightPanel == PanelState.RightPanelState.ViewSettings)
                {
                    ExpandRightPropertyPanel(displaySettingsControl, Visibility.Visible);
                }
                else
                {
                    ExpandRightPropertyPanel(null, Visibility.Collapsed);
                }
            }
        }

        #endregion

        #region Expand and collapse Panel

        public void ExpandRightPropertyPanel(Visibility visible)
        {
            ExpandRightPropertyPanel(measurePropertyControl, visible);
        }

        public void ExpandNullRightPropertyPanel(Visibility visible)
        {
            ExpandRightPropertyPanel(null, visible);
        }

        public void ExpandViewSettings(Visibility visible)
        {
            SetViewSettings(displaySettingsControl, visible);
        }

        private void ExpandRightPropertyPanel(UIElement propertytPanel, Visibility visible)
        {
            PropertyContainer.Width = 260;
            PropertyContainer.Child = propertytPanel;
            PropertyContainer.Visibility = visible;
        }

        private void SetViewSettings(CPDFDisplaySettingsControl displaySettingsControl, Visibility visibility)
        {
            PropertyContainer.Child = displaySettingsControl;
            PropertyContainer.Visibility = visibility;
        }

        public void ExpandLeftPanel(bool isExpand)
        {
            BotaContainer.Visibility = isExpand ? Visibility.Visible : Visibility.Collapsed;
            Splitter.Visibility = isExpand ? Visibility.Visible : Visibility.Collapsed;
            if (isExpand)
            {
                BodyGrid.ColumnDefinitions[0].Width = new GridLength(320);
                BodyGrid.ColumnDefinitions[1].Width = new GridLength(15);
            }
            else
            {
                BodyGrid.ColumnDefinitions[0].Width = new GridLength(0);
                BodyGrid.ColumnDefinitions[1].Width = new GridLength(0);
            }
        }

        #endregion

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {

        }

        private void MeasureInfoPanel_SettingClick(object sender, EventArgs e)
        {
            SettingPanel.ReturnToInfoPanel = true;
            SetInfoPanelVisble(false, true);
            SettingPanel.BindMeasureSetting();
        }

        private void SettingPanel_CancelEvent(object sender, EventArgs e)
        {
            SetInfoPanelVisble(SettingPanel.ReturnToInfoPanel, false);
        }

        private void SettingPanel_DoneEvent(object sender, EventArgs e)
        {
            SetInfoPanelVisble(SettingPanel.ReturnToInfoPanel, false);
        }

        public void SetInfoPanelVisble(bool measureInfo, bool measureSetting)
        {
            if (measureInfo)
            {
                InfoPanel.ClearMeasureInfo();
            }
            InfoPanel.Visibility = measureInfo ? Visibility.Visible : Visibility.Collapsed;
            SettingPanel.Visibility = measureSetting ? Visibility.Visible : Visibility.Collapsed;
        }

        public void SetMeasureInfoType(CPDFMeasureType measureType)
        {
            InfoPanel?.SetMeasureType(measureType);
        }

        public void SetMeasureScale(CPDFMeasureType measureType, string scale)
        {
            InfoPanel?.SetMeasureScale(measureType,scale);
        }
    }
}