// Decompiled with JetBrains decompiler
// Type: Microsoft.Iris.Layouts.ScrollingLayout
// Assembly: UIX, Version=4.8.0.0, Culture=neutral, PublicKeyToken=ddd0da4d3e678217
// MVID: A56C6C9D-B7F6-46A9-8BDE-B3D9B8D60B11
// Assembly location: C:\Program Files\Zune\UIX.dll

using Microsoft.Iris.Layout;
using Microsoft.Iris.Library;
using Microsoft.Iris.Render;
using Microsoft.Iris.ViewItems;
using System;

namespace Microsoft.Iris.Layouts
{
    internal class ScrollingLayout : ILayout
    {
        private Orientation _orientation;
        private int _prefetch;
        private static bool s_allowScrollFocusIntoView;

        public ScrollingLayout(Orientation orientation, int prefetch)
        {
            _orientation = orientation;
            _prefetch = prefetch;
        }

        public Orientation Orientation
        {
            get => _orientation;
            set
            {
                if (_orientation == value)
                    return;
                _orientation = value;
            }
        }

        public int Prefetch
        {
            get => _prefetch;
            set
            {
                if (_prefetch == value)
                    return;
                _prefetch = value;
            }
        }

        public ItemAlignment DefaultChildAlignment => ItemAlignment.Default;

        Size ILayout.Measure(ILayoutNode layoutNode, Size constraint)
        {
            Size size;
            if (!(layoutNode.GetLayoutInput(ScrollingLayoutInput.Data) is ScrollingLayoutInput layoutInput) || layoutInput.Enabled)
            {
                Size infiniteConstraint = GetInfiniteConstraint(constraint);
                size = DefaultLayout.Measure(layoutNode, infiniteConstraint);
                layoutNode.MeasureData = size;
            }
            else
                size = DefaultLayout.Measure(layoutNode, constraint);
            return size;
        }

        void ILayout.Arrange(ILayoutNode layoutNode, LayoutSlot slot)
        {
            if (!(layoutNode.GetLayoutInput(ScrollingLayoutInput.Data) is ScrollingLayoutInput sli))
                sli = new ScrollingLayoutInput();
            int scrollAmount = sli.ScrollAmount;
            ScrollingLayoutOutput scrollingLayoutOutput = null;
            if (layoutNode.LayoutChildrenCount > 0)
            {
                if (sli.Enabled)
                {
                    scrollingLayoutOutput = Arrange(layoutNode, slot, sli, ref scrollAmount);
                }
                else
                {
                    DefaultLayout.Arrange(layoutNode, slot);
                    scrollAmount = 0;
                    scrollingLayoutOutput = new ScrollingLayoutOutput();
                }
            }
            sli.SetScrollAmount(scrollAmount);
            if (scrollingLayoutOutput == null)
                return;
            layoutNode.SetExtendedLayoutOutput(scrollingLayoutOutput);
        }

        private ScrollingLayoutOutput Arrange(
          ILayoutNode layoutNode,
          LayoutSlot slot,
          ScrollingLayoutInput sli,
          ref int scrollAmount)
        {
            LayoutSlot childSlot;
            Rectangle viewBounds;
            GetChildSlot(slot, scrollAmount, out childSlot, out viewBounds);
            int num = scrollAmount;
            ScrollingLayoutOutput scrollingLayoutOutput = ArrangeChildren(layoutNode, slot, childSlot, viewBounds, sli, true, ref scrollAmount);
            if (num != scrollAmount)
            {
                GetChildSlot(slot, scrollAmount, out childSlot, out viewBounds);
                scrollingLayoutOutput = ArrangeChildren(layoutNode, slot, childSlot, viewBounds, sli, false, ref scrollAmount);
            }
            return scrollingLayoutOutput;
        }

        private void GetChildSlot(
          LayoutSlot slot,
          int scrollAmount,
          out LayoutSlot childSlot,
          out Rectangle viewBounds)
        {
            Size infiniteConstraint = GetInfiniteConstraint(slot.Bounds);
            Size bounds = slot.Bounds;
            viewBounds = new Rectangle(Point.Zero, bounds);
            Point offset = ScrollAmountToOffset(_prefetch);
            Rectangle viewPeripheralBounds = viewBounds;
            viewPeripheralBounds.Inflate(offset.X, offset.Y);
            childSlot = new LayoutSlot(infiniteConstraint, slot.Offset, viewBounds, viewPeripheralBounds);
        }

        private ScrollingLayoutOutput ArrangeChildren(
          ILayoutNode layoutNode,
          LayoutSlot slot,
          LayoutSlot childSlot,
          Rectangle viewBounds,
          ScrollingLayoutInput sli,
          bool applyPendingScrollData,
          ref int scrollAmount)
        {
            Rectangle areaOfInterestBounds = Rectangle.Zero;
            bool scrollAreaOfInterestIntoView = sli.ScrollIntoViewDisposition.Enabled;
            bool flag1 = false;
            VisibleIndexRangeLayoutOutput rangeLayoutOutput = null;
            Rectangle rectangle1 = Rectangle.Zero;
            Rectangle bounds = new Rectangle(new MajorMinor(-scrollAmount, 0).ToPoint(Orientation), Size.Max(slot.Bounds, (Size)layoutNode.MeasureData));
            foreach (ILayoutNode layoutChild in layoutNode.LayoutChildren)
            {
                layoutChild.Arrange(childSlot, bounds);
                rangeLayoutOutput = layoutChild.GetExtendedLayoutOutput(VisibleIndexRangeLayoutOutput.DataCookie) as VisibleIndexRangeLayoutOutput;
                bool flag2 = true;
                AreaOfInterest area1;
                if (!layoutChild.TryGetAreaOfInterest(AreaOfInterestID.ScrollIntoViewRequest, out area1) && !layoutChild.TryGetAreaOfInterest(AreaOfInterestID.PendingFocus, out area1))
                    flag2 = layoutChild.TryGetAreaOfInterest(AreaOfInterestID.Focus, out area1);
                if (flag2)
                    areaOfInterestBounds = area1.Rectangle;
                if (IsFocusAreaOfInterest(area1.Id) && !sli.ScrollIntoViewDisposition.Enabled)
                    DisallowScrollFocusIntoView();
                scrollAreaOfInterestIntoView &= ScrollFocusIntoView;
                if (area1.Id == AreaOfInterestID.ScrollIntoViewRequest && !areaOfInterestBounds.IsZero)
                {
                    scrollAreaOfInterestIntoView = true;
                    flag1 = true;
                }
                Rectangle rectangle2 = new Rectangle(Point.Zero, layoutChild.DesiredSize);
                AreaOfInterest area2;
                if (layoutChild.TryGetAreaOfInterest(AreaOfInterestID.ScrollableRange, out area2))
                    rectangle2 = Rectangle.Union(rectangle2, area2.Rectangle);
                rectangle1 = Rectangle.Union(rectangle1, rectangle2);
            }
            ScrollingLayoutOutput scrollAmount1 = CalculateScrollAmount(layoutNode, viewBounds, rectangle1, sli, applyPendingScrollData, scrollAreaOfInterestIntoView, areaOfInterestBounds, ref scrollAmount);
            scrollAmount1.VisibleIndices = rangeLayoutOutput;
            scrollAmount1.ProcessedExplicitScrollIntoViewRequest = flag1;
            scrollAmount1.ScrollFocusIntoView = ScrollFocusIntoView;
            return scrollAmount1;
        }

        private bool IsFocusAreaOfInterest(AreaOfInterestID areaOfInterestID) => areaOfInterestID == AreaOfInterestID.PendingFocus || areaOfInterestID == AreaOfInterestID.Focus;

        private ScrollingLayoutOutput CalculateScrollAmount(
          ILayoutNode layoutNode,
          Rectangle viewBounds,
          Rectangle scrollableBounds,
          ScrollingLayoutInput sli,
          bool applyPendingScrollData,
          bool scrollAreaOfInterestIntoView,
          Rectangle areaOfInterestBounds,
          ref int scrollAmount)
        {
            int space1 = ItemToSpace(viewBounds.Size);
            int space2 = ItemToSpace(scrollableBounds.Size);
            int num1 = -(space1 - space2);
            int num2 = (int)Math.Round(space1 * (double)sli.PageStep);
            int num3 = ItemToSpace(scrollableBounds.Location.ToSize());
            int num4 = num3 + num1;
            if (num1 < 0)
            {
                num3 = 0;
                num4 = 0;
            }
            if (!areaOfInterestBounds.IsZero && scrollAreaOfInterestIntoView)
            {
                scrollAmount = ScrollIntoView(layoutNode, areaOfInterestBounds, scrollAmount, space1, space2, num3, num4, sli.ScrollIntoViewDisposition);
                if (sli.SecondaryScrollIntoViewDisposition != null && sli.SecondaryScrollIntoViewDisposition.Enabled)
                    scrollAmount = ScrollIntoView(layoutNode, areaOfInterestBounds, scrollAmount, space1, space2, num3, num4, sli.SecondaryScrollIntoViewDisposition);
                scrollAmount = Math.Max(scrollAmount, num3);
                scrollAmount = Math.Min(scrollAmount, num4);
            }
            else if (num1 > 0)
            {
                if (applyPendingScrollData)
                {
                    float position = 0.0f;
                    if (sli.GetPendingScrollPosition(out position))
                    {
                        int num5 = (int)Math2.Blend(num3, num4, position, false);
                        scrollAmount = num5;
                    }
                    int amount = 0;
                    if (sli.GetPendingPageRequests(out amount))
                    {
                        int num5 = amount * num2;
                        scrollAmount += num5;
                    }
                }
                scrollAmount = Math.Max(scrollAmount, num3);
                scrollAmount = Math.Min(scrollAmount, num4);
            }
            else
                scrollAmount = 0;
            int space3 = ItemToSpace(scrollableBounds.Location.ToSize());
            bool flag1 = -scrollAmount < space3;
            bool flag2 = -scrollAmount + space2 > space1;
            float num6 = 1f;
            float val2 = 1f;
            float num7 = 0.0f;
            float num8 = 1f;
            float num9 = num1;
            float num10 = scrollAmount;
            if (num2 > 0)
            {
                val2 = (float)(num9 / (double)num2 + 1.0);
                num6 = Math.Max(Math.Min((float)(num10 / (double)num2 + 1.0), val2), 0.0f);
            }
            if (num1 > 0)
            {
                num7 = num10 / space2;
                num8 = (num10 + space1) / space2;
            }
            return new ScrollingLayoutOutput()
            {
                CanScrollNegative = flag1,
                CanScrollPositive = flag2,
                CurrentPage = num6,
                TotalPages = val2,
                ViewNear = num7,
                ViewFar = num8
            };
        }

        private int ScrollIntoView(
          ILayoutNode layoutNode,
          Rectangle areaOfInterestBounds,
          int scrollAmount,
          int viewMajorSpace,
          int naturalMajorSpace,
          int naturalMinScroll,
          int naturalMaxScroll,
          ScrollIntoViewDisposition scrollIntoView)
        {
            Rectangle rectangle = areaOfInterestBounds;
            int num1 = ItemToSpace(rectangle.Location.ToSize());
            int space = ItemToSpace(rectangle.Size);
            int num2 = num1 + space;
            int num3 = scrollAmount;
            int num4 = viewMajorSpace;
            int num5 = num3 + num4;
            int num6 = num3;
            int num7 = num5;
            int beginPadding = scrollIntoView.BeginPadding;
            switch (scrollIntoView.BeginPaddingRelativeTo)
            {
                case RelativeEdge.Near:
                    num6 = num3 + beginPadding;
                    break;
                case RelativeEdge.Far:
                    num6 = num5 - beginPadding;
                    break;
            }
            int endPadding = scrollIntoView.EndPadding;
            switch (scrollIntoView.EndPaddingRelativeTo)
            {
                case RelativeEdge.Near:
                    num7 = num3 + endPadding;
                    break;
                case RelativeEdge.Far:
                    num7 = num5 - endPadding;
                    break;
            }
            int num8 = num6 - num3;
            int num9 = num7 - num5;
            if (scrollIntoView.Locked)
            {
                float num10 = num7 - num6;
                float num11 = num10 * scrollIntoView.LockedPosition;
                float num12 = num10 * (1f - scrollIntoView.LockedPosition);
                int num13 = num1 + (int)(space * (double)scrollIntoView.LockedAlignment);
                num1 = num13 - (int)num11;
                num2 = num13 + (int)num12;
            }
            int num14 = scrollAmount;
            if (num2 > num7)
            {
                scrollAmount = num2 - num4 - num9;
                int num10 = scrollAmount - num14;
                num6 += num10;
                int num11 = num7 + num10;
            }
            if (num1 < num6)
                scrollAmount = num1 - num8;
            if (scrollIntoView.ContentPositioningBehavior == ContentPositioningPolicy.ShowMaximalContent)
                scrollAmount = Math2.Clamp(scrollAmount, naturalMinScroll, naturalMaxScroll);
            return scrollAmount;
        }

        private int ItemToSpace(Size size) => new MajorMinor(size, _orientation).Major;

        protected Point ScrollAmountToOffset(int scrollAmount) => new MajorMinor(scrollAmount, 0).ToPoint(_orientation);

        protected Size GetInfiniteConstraint(Size maxExtent) => new MajorMinor(maxExtent, _orientation)
        {
            Major = 16777215
        }.ToSize(_orientation);

        public static void ResetScrollFocusIntoView() => s_allowScrollFocusIntoView = true;

        public static bool ScrollFocusIntoView => s_allowScrollFocusIntoView;

        public static void DisallowScrollFocusIntoView() => s_allowScrollFocusIntoView = false;

        public bool Equals(ILayout other)
        {
            if (other is not ScrollingLayout o) return false;

            return DefaultChildAlignment == o.DefaultChildAlignment
                && Orientation == o.Orientation
                && Prefetch == o.Prefetch;
        }
    }
}
