// BackArrowRadRibbonBackstageItem.cs
// Copyright (c) 2018 Bentley Systems, Incorporated. All Rights Reserved.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Text;
using Telerik.Windows.Controls;
using Haestad.Support.Library;
using Haestad.Support.Support;

// Note: <whar> Even though this class holds on to some GDI objects, it does not implement IDisposable nor does it dispose 
// those GDI objects at any time, since the lifetime of this object is the same as the application lifetime.

namespace Haestad.Framework.UI.Integration
{
    /// <summary>
    /// Class defines and implements a back arrow back stage tab item for use with the Office 2013 position.
    /// </summary>
    public class BackArrowRadRibbonBackstageItem : RadRibbonBackstageItem
    {
        #region Constructor
        public BackArrowRadRibbonBackstageItem(Color normalColor, Color highlightColor)
        {
            NormalColor = normalColor;
            HighlightColor = highlightColor;

            ButtonMetricsCalculated = false;
            IsMouseOverBackButton = false;

            InitializeEvents();
        }
        #endregion

        #region Event Handlers
        private void BackArrowRadRibbonBackstageItem_Loaded(object sender, RoutedEventArgs e)
        {
            Height = 80.0;
            CalculateButtonMetrics();
        }
        #endregion

        #region Protected Override Methods
        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            base.OnRenderSizeChanged(sizeInfo);
            CalculateButtonMetrics();
        }

        protected override void ChangeVisualState(bool useTransitions)
        {
            /*No-op*/
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            UdpateIsMouseOverBackButton(e);
            InvalidateVisual();
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            if (!IsMouseOverBackButton)
                e.Handled = true;
        }

        protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
        {
            if (!ButtonMetricsCalculated)
                CalculateButtonMetrics();

            Pen penToDrawWith = IsMouseOverBackButton ? HighlightPen : NormalPen;
            drawingContext.DrawEllipse(null, penToDrawWith, ButtonCenter, Radius, Radius);

            Brush brushToDrawWith = IsMouseOverBackButton ? HighlightBrush : NormalBrush;
            DrawPolygon(drawingContext, brushToDrawWith, null, ArrowPoints, FillRule.EvenOdd);
        }
        #endregion

        #region Private Methods
        private void InitializeEvents()
        {
            Loaded += BackArrowRadRibbonBackstageItem_Loaded;
        }

        private void CalculateButtonMetrics()
        {
            const double DIAMETER_FACTOR = 0.45;
            const double LEFT_OFFSET = 3.0;
            const double SIGN45 = 0.7071;
            
            Diameter = ActualHeight * DIAMETER_FACTOR;
            Radius = Diameter / 2.0;
            m_buttonCenter.X = m_buttonCenterGP.X = LEFT_OFFSET + Diameter;
            m_buttonCenter.Y = m_buttonCenterGP.Y = Diameter;

            double lineThickness = 0.20 * Radius;
            double halfLineThickness = lineThickness / 2.0;
            double topY = ButtonCenter.Y - Radius * 0.4;
            double bottomY = ButtonCenter.Y + Radius * 0.4; 

            PenWidth = lineThickness * SIGN45;
            m_normalPen = null;
            m_highlightPen = null;

            ArrowPoints = new Point[] { 
                new Point(ButtonCenter.X - Radius * 0.5, ButtonCenter.Y), 
                new Point (ButtonCenter.X - Radius * 0.2, topY), 
                new Point (ButtonCenter.X - Radius * 0.2 + lineThickness, topY), 
                new Point (ButtonCenter.X - Radius * 0.275, ButtonCenter.Y - halfLineThickness * SIGN45),
                new Point (ButtonCenter.X + Radius * 0.6, ButtonCenter.Y - halfLineThickness * SIGN45),
                new Point (ButtonCenter.X + Radius * 0.6, ButtonCenter.Y + halfLineThickness * SIGN45),
                new Point (ButtonCenter.X - Radius * 0.275, ButtonCenter.Y + halfLineThickness * SIGN45),
                new Point (ButtonCenter.X - Radius * 0.2 + lineThickness, bottomY),
                new Point (ButtonCenter.X - Radius * 0.2, bottomY)
            };

            ButtonMetricsCalculated = true;
        }
  
        private void DrawPolygon(DrawingContext drawingContext, Brush brush, Pen pen, Point[] points, FillRule fillRule)
        {
            StreamGeometry streamGeometry = new StreamGeometry();
            streamGeometry.FillRule = fillRule;

            using (StreamGeometryContext context = streamGeometry.Open())
            {
                context.BeginFigure(points[0], true, true);
                context.PolyLineTo(points.Skip(1).ToArray(), true, false);
            }

            drawingContext.DrawGeometry(brush, pen, streamGeometry);
        }
        #endregion

        private void UdpateIsMouseOverBackButton(MouseEventArgs e)
        {
            if (!ButtonMetricsCalculated)
                CalculateButtonMetrics();

            Point mousePosition = e.MouseDevice.GetPosition(this);
            double lineLength = MathLibrary.CalculateLineLength(ButtonCenterGP, new GeometryPoint(mousePosition.X, mousePosition.Y));
            IsMouseOverBackButton = lineLength <= Radius;
        }

        #region Private Properties
        private Point ButtonCenter
        {
            get 
            {
                if (m_buttonCenter == null)
                    m_buttonCenter = new Point();
                return m_buttonCenter; 
            }
        }

        private GeometryPoint ButtonCenterGP
        {
            get
            {
                if (m_buttonCenterGP == null)
                    m_buttonCenterGP = new GeometryPoint();
                return m_buttonCenterGP;
            }
        }

        private Pen NormalPen
        {
            get
            {
                if (m_normalPen == null)
                    m_normalPen = new Pen(NormalBrush, PenWidth);
                return m_normalPen;
            }
        }

        private Pen HighlightPen
        {
            get
            {
                if (m_highlightPen == null)
                    m_highlightPen = new Pen(HighlightBrush, PenWidth);
                return m_highlightPen;
            }
        }

        private Brush NormalBrush
        {
            get
            {
                if (m_normalBrush == null)
                    m_normalBrush = new SolidColorBrush(NormalColor);
                return m_normalBrush;
            }
        }

        private Brush HighlightBrush
        {
            get
            {
                if (m_highlightBrush == null)
                    m_highlightBrush = new SolidColorBrush(HighlightColor);
                return m_highlightBrush;
            }
        }

        private Point[] ArrowPoints
        {
            get;
            set;
        }

        private Color NormalColor
        {
            get;
            set;
        }

        private Color HighlightColor
        {
            get;
            set;
        }

        private double Radius
        {
            get;
            set;
        }

        private double Diameter
        {
            get;
            set;
        }

        private double PenWidth
        {
            get;
            set;
        }

        private bool ButtonMetricsCalculated
        {
            get;
            set;
        }

        private bool IsMouseOverBackButton
        {
            get;
            set;
        }
        #endregion

        #region Private Fields
        private Brush m_normalBrush;
        private Brush m_highlightBrush;
        private Pen m_normalPen;
        private Pen m_highlightPen;
        private Point m_buttonCenter;
        private GeometryPoint m_buttonCenterGP;
        #endregion
    }
}
