using System;
using System.Windows.Controls;
using System.Windows;

namespace CutomPanels
{
    class CircularPanel : Panel
    {
        //rerejestrowana właściwość zależna CircleTotalProperty
        public static readonly DependencyProperty CircleTotalProperty
           = DependencyProperty.Register("CircleTotal", typeof(double), typeof(CircularPanel),
                                         new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsArrange));
        //właściwość CirleTotal
        public double CircleTotal
        {
            get { return (double)GetValue(CircleTotalProperty); }
            set { SetValue(CircleTotalProperty, value); }
        }
        //rerejestrowana właściwość zależna CircleBeginingProperty
        public static readonly DependencyProperty CircleBeginingProperty
           = DependencyProperty.Register("CircleBegining", typeof(double), typeof(CircularPanel),
                                         new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsArrange));
        //właściwość CircleBegining
        public double CircleBegining
        {
            get { return (double)GetValue(CircleBeginingProperty); }
            set { SetValue(CircleBeginingProperty, value); }
        }
        //maksymalne wiekości elementów dzieci
        double _maxWidth = 0;
        double _maxHeight = 0;
        protected override Size MeasureOverride(Size availableSize)
        {
            foreach (UIElement child in Children)
            {
                //każdemu dziecku przyznawany jest największy możliwy rozmiar
                child.Measure(new Size(double.PositiveInfinity,
                double.PositiveInfinity));
                //wybierana jest największa szerokość
                _maxWidth = Math.Max(_maxWidth, child.DesiredSize.Width);
                //wybierana jest największa szerokość
                _maxHeight = Math.Max(_maxHeight, child.DesiredSize.Height);
            }
            // rodzic zwraca minimalny zerowy rozmiar 
            return new Size(0, 0);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            //szerokość panelu zmniejszona o szerkość najszerszego elementu
            //w celu uniknięcia  najszerszego elementu
            double layoutWidth = finalSize.Width - _maxWidth;
            //wysokość panelu zmniejszona o wysokość najwyższego elementu
            //w celu uniknięcia przycięcia  najwyższego elementu
            double layoutHeight = finalSize.Height - _maxHeight;
            //obwód okręgu
            double layoutCirfumference
                = EstimateEllipseCircumference(layoutWidth,
                                            layoutHeight);
            //odstęp pomiędzy elementami na okręgu
            double singleSpace = (layoutCirfumference) / (CircleTotal % 1 == 0 ? Children.Count : Children.Count - 1) * CircleTotal;
            //odstęp sumaryczny
            double generalSpace = singleSpace;
            double angle = DegreesIntoRadians(CircleBegining);
            foreach (UIElement child in Children)
            {
                if (child != null)
                {

                    //obliczane współrzędne danego punktu na elipsie
                    Point childPoint = GetPointFromEllipse(layoutWidth,
                                                layoutHeight,
                                                new Point(finalSize.Width / 2,
                                                          finalSize.Height / 2),
                                                angle);
                    //kąt pomiędzy linią początkową, a aktualną przesunięty o odpowiedni kąt określony w CircleBegining
                    angle = (Math.PI * 2) * (generalSpace / layoutCirfumference) + DegreesIntoRadians(CircleBegining);
                    //z kążdym nowo dodanym elementem zwiększamy odstęp od miejsca, od którego zaczęło się układanie elementów
                    generalSpace += singleSpace;
                    //aranżacja elementów
                    child.Arrange(new Rect(new Point(childPoint.X - child.DesiredSize.Width * 0.5, childPoint.Y - child.DesiredSize.Height * 0.5), child.DesiredSize));
                }
            }
            return finalSize;
        }
        private static Point GetPointFromEllipse(double width, double height, Point center, double angle)
        {
            double x = center.X + ((width / 2) * Math.Cos(angle));
            double y = center.Y + ((height / 2) * Math.Sin(angle));
            return new Point(x, y);
        }
        private static double EstimateEllipseCircumference(double width, double height)
        {
            double circumference = Math.PI * (3 / 2 * (width / 2 + height / 2) - Math.Pow(width * height, 1 / 2));
            return circumference;
        }
        private static double DegreesIntoRadians(double degrees)
        {
            return Math.PI / 180 * degrees;
        }
    }

}
