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

namespace HandyControl.Controls
{
    public class CompareTrack : Track
    {
        protected override Size ArrangeOverride(Size arrangeSize)
        {
            base.ArrangeOverride(arrangeSize);

            var isVertical = Orientation == Orientation.Vertical;
            ComputeSliderLengths(arrangeSize, isVertical, out var decreaseButtonLength, out var thumbLength,
                out var increaseButtonLength);

            var offset = new Point();
            var pieceSize = arrangeSize;
            var isDirectionReversed = IsDirectionReversed;

            if (isVertical)
            {
                CoerceLength(ref decreaseButtonLength, arrangeSize.Height);
                CoerceLength(ref increaseButtonLength, arrangeSize.Height);
                CoerceLength(ref thumbLength, arrangeSize.Height);

                offset.Y = isDirectionReversed ? decreaseButtonLength + thumbLength : 0.0;
                pieceSize.Height = increaseButtonLength;

                IncreaseRepeatButton?.Arrange(new Rect(offset, pieceSize));

                offset.Y = isDirectionReversed ? 0.0 : increaseButtonLength + thumbLength;
                pieceSize.Height = decreaseButtonLength;

                if (DecreaseRepeatButton != null)
                {
                    DecreaseRepeatButton.Arrange(new Rect(offset, pieceSize));
                    DecreaseRepeatButton.Height = pieceSize.Height;
                }

                offset.Y = isDirectionReversed ? decreaseButtonLength : increaseButtonLength;
                pieceSize.Height = thumbLength;

                Thumb?.Arrange(new Rect(offset, pieceSize));
            }
            else
            {
                CoerceLength(ref decreaseButtonLength, arrangeSize.Width);
                CoerceLength(ref increaseButtonLength, arrangeSize.Width);
                CoerceLength(ref thumbLength, arrangeSize.Width);

                offset.X = isDirectionReversed ? increaseButtonLength + thumbLength : 0.0;
                pieceSize.Width = decreaseButtonLength;

                DecreaseRepeatButton?.Arrange(new Rect(offset, pieceSize));


                offset.X = isDirectionReversed ? 0.0 : decreaseButtonLength + thumbLength;
                pieceSize.Width = increaseButtonLength;

                if (IncreaseRepeatButton != null)
                {
                    IncreaseRepeatButton.Arrange(new Rect(offset, pieceSize));
                    IncreaseRepeatButton.Width = pieceSize.Width;
                }

                offset.X = isDirectionReversed ? increaseButtonLength : decreaseButtonLength;
                pieceSize.Width = thumbLength;

                Thumb?.Arrange(new Rect(offset, pieceSize));
            }

            return arrangeSize;
        }

        private void ComputeSliderLengths(Size arrangeSize, bool isVertical, out double decreaseButtonLength,
            out double thumbLength, out double increaseButtonLength)
        {
            var min = Minimum;
            var range = Math.Max(0.0, Maximum - min);
            var offset = Math.Min(range, Value - min);

            double trackLength;

            // Compute thumb size
            if (isVertical)
            {
                trackLength = arrangeSize.Height;
                thumbLength = Thumb?.DesiredSize.Height ?? 0;
            }
            else
            {
                trackLength = arrangeSize.Width;
                thumbLength = Thumb?.DesiredSize.Width ?? 0;
            }

            CoerceLength(ref thumbLength, trackLength);

            var remainingTrackLength = trackLength - thumbLength;

            decreaseButtonLength = remainingTrackLength * offset / range;
            CoerceLength(ref decreaseButtonLength, remainingTrackLength);

            increaseButtonLength = remainingTrackLength - decreaseButtonLength;
            CoerceLength(ref increaseButtonLength, remainingTrackLength);
        }

        private static void CoerceLength(ref double componentLength, double trackLength)
        {
            if (componentLength < 0)
                componentLength = 0.0;
            else if (componentLength > trackLength || double.IsNaN(componentLength))
                componentLength = trackLength;
        }
    }
}
