text: ﻿using NUnit.Framework;
  using System;
  using System.Globalization;
  using System.Threading;
  
  namespace Xamarin.Forms.Core.UnitTests
  {
  	[TestFixture]
  	public class FlexLayoutTests : BaseTestFixture
  	{
  		[Test]
  		public void TestBasicLayout()
  		{
  			var label1 = new Label { IsPlatformEnabled = true };
  			var label2 = new Label { IsPlatformEnabled = true };
  
  			var layout = new FlexLayout {
  				IsPlatformEnabled = true,
  				Children = {
  					label1,
  					label2,
  				}
  			};
  
  			layout.Layout(new Rectangle(0, 0, 912, 912));
  
  			Assert.That(layout.Bounds, Is.EqualTo(new Rectangle(0, 0, 912, 912)));
  			Assert.That(label1.Bounds, Is.EqualTo(new Rectangle(0, 0, 100, 912)));
  			Assert.That(label2.Bounds, Is.EqualTo(new Rectangle(100, 0, 100, 912)));
  		}
  
  		[Test]
  		public void TestBasicLayoutWithElementsWidth()
  		{
  			var label1 = new Label { IsPlatformEnabled = true, WidthRequest = 120 };
  			var label2 = new Label { IsPlatformEnabled = true, WidthRequest = 120 };
  
  			var layout = new FlexLayout {
  				IsPlatformEnabled = true,
  				Children = {
  					label1,
  					label2,
  				}
  			};
  
  			layout.Layout(new Rectangle(0, 0, 912, 912));
  
  			Assert.That(layout.Bounds, Is.EqualTo(new Rectangle(0, 0, 912, 912)));
  			Assert.That(label1.Bounds, Is.EqualTo(new Rectangle(0, 0, 120, 912)));
  			Assert.That(label2.Bounds, Is.EqualTo(new Rectangle(120, 0, 120, 912)));
  
  		}
  
  		[Test]
  		public void TestBasicLayoutWithElementsWidthAndMargin()
  		{
  			var label1 = new Label { IsPlatformEnabled = true, WidthRequest = 100, Margin = new Thickness(5, 0, 0, 0) };
  			var label2 = new Label { IsPlatformEnabled = true, WidthRequest = 100, Margin = new Thickness(5, 0, 0, 0) };
  
  			var layout = new FlexLayout {
  				IsPlatformEnabled = true,
  				Children = {
  					label1,
  					label2,
  				}
  			};
  
  			layout.Layout(new Rectangle(0, 0, 912, 912));
  
  			Assert.AreEqual(912, layout.Width);
  			Assert.AreEqual(912, layout.Height);
  
  			Assert.AreEqual(new Rectangle(5, 0, 100, 912), label1.Bounds);
  			Assert.AreEqual(new Rectangle(110, 0, 100, 912), label2.Bounds);
  		}
  
  		[Test]
  		public void TestSetBounds()
  		{
  			var layoutSize = new Size(320, 50);
  
  			var layout = new FlexLayout {
  				Direction = FlexDirection.Row,
  				AlignItems = FlexAlignItems.Start,
  				IsPlatformEnabled = true
  			};
  
  			var label1 = new Label { IsPlatformEnabled = true };
  			FlexLayout.SetGrow(label1, 1);
  			layout.Children.Add(label1);
  
  			var label2 = new Label { IsPlatformEnabled = true };
  			FlexLayout.SetGrow(label2, 1);
  			layout.Children.Add(label2);
  
  			var label3 = new Label { IsPlatformEnabled = true };
  			FlexLayout.SetGrow(label3, 1);
  			layout.Children.Add(label3);
  
  			layout.Layout(new Rectangle(0, 0, layoutSize.Width, layoutSize.Height));
  
  			Assert.AreEqual(label2.Bounds.Left, Math.Max(label1.Bounds.Left, label1.Bounds.Right), 1);
  			Assert.AreEqual(label3.Bounds.Left, Math.Max(label2.Bounds.Left, label2.Bounds.Right), 1);
  
  			double totalWidth = 0;
  			foreach (var view in layout.Children)
  			{
  				totalWidth += view.Bounds.Width;
  			}
  
  			Assert.AreEqual(layoutSize.Width, totalWidth, 2);
  		}
  
  		[Test]
  		public void TestRelayoutOnChildrenRemoved()
  		{
  			var layoutSize = new Size(300, 50);
  
  			var layout = new FlexLayout {
  				IsPlatformEnabled = true,
  				Direction = FlexDirection.Row
  			};
  
  			var label1 = new Label { IsPlatformEnabled = true };
  			FlexLayout.SetGrow(label1, 1);
  			layout.Children.Add(label1);
  
  			var label2 = new Label { IsPlatformEnabled = true };
  			FlexLayout.SetGrow(label2, 1);
  			layout.Children.Add(label2);
  
  			var label3 = new Label { IsPlatformEnabled = true };
  			FlexLayout.SetGrow(label3, 1);
  			layout.Children.Add(label3);
  
  			layout.Layout(new Rectangle(0, 0, layoutSize.Width, layoutSize.Height));
  
  			foreach (var view in layout.Children)
  				Assert.That(view.Bounds.Width, Is.EqualTo(100));
  
  			layout.Children.Remove(label3);
  
  			Assert.That(label1.Bounds.Width, Is.EqualTo(150));
  			Assert.That(label2.Bounds.Width, Is.EqualTo(150));
  			Assert.That(label3.Bounds.Width, Is.EqualTo(100));
  		}
  
  		[Test]
  		public void TestFlexLayoutIsIncludeChangeWorksOnSecondPass()
  		{
  			var layoutSize = new Size(300, 50);
  			var layout = new FlexLayout {
  				Direction = FlexDirection.Row,
  				IsPlatformEnabled = true,
  			};
  
  			var label1 = new Label { IsPlatformEnabled = true };
  			FlexLayout.SetGrow(label1, 1);
  			layout.Children.Add(label1);
  
  			var label2 = new Label { IsPlatformEnabled = true };
  			FlexLayout.SetGrow(label2, 1);
  			layout.Children.Add(label2);
  
  			var label3 = new Label { IsPlatformEnabled = true };
  			FlexLayout.SetGrow(label3, 1);
  
  			layout.Layout(new Rectangle(0, 0, layoutSize.Width, layoutSize.Height));
  
  			Assert.AreEqual(150, label1.Bounds.Width);
  			Assert.AreEqual(150, label2.Bounds.Width);
  			Assert.AreEqual(-1, label3.Bounds.Width);
  
  			layout.Children.Add(label3);
  
  			layout.Layout(new Rectangle(0, 0, layoutSize.Width, layoutSize.Height));
  			Assert.AreEqual(100, label1.Bounds.Width);
  			Assert.AreEqual(100, label2.Bounds.Width);
  			Assert.AreEqual(100, label3.Bounds.Width);
  		}
  
  		[Test]
  		// fixed at https://github.com/xamarin/flex/commit/0ccb9f1625abdc5400def29651373937bf6610cd
  		public void TestSwapChildrenOrder()
  		{
  			var layoutSize = new Size(300, 50);
  
  			var layout = new FlexLayout { 
  				Direction = FlexDirection.Row,
  				IsPlatformEnabled = true,
  			};
  
  			var label0 = new Label { IsPlatformEnabled = true, Text="Label0" };
  			FlexLayout.SetGrow(label0, 1);
  			layout.Children.Add(label0);
  
  			var label1 = new Label { IsPlatformEnabled = true, Text = "Label1" };
  			FlexLayout.SetGrow(label1, 1);
  			layout.Children.Add(label1);
  
  			var label2 = new Label { IsPlatformEnabled = true, Text = "Label2" };
  			FlexLayout.SetGrow(label2, 1);
  			layout.Children.Add(label2);
  
  			layout.Layout(new Rectangle(0, 0, layoutSize.Width, layoutSize.Height));
  
  			Assert.AreEqual(new Rectangle(0, 0, 100, 50), label0.Bounds);
  			Assert.AreEqual(new Rectangle(100, 0, 100, 50), label1.Bounds);
  			Assert.AreEqual(new Rectangle(200, 0, 100, 50), label2.Bounds);
  
  			var lastItem = layout.Children[2];
  			Assert.That(lastItem, Is.SameAs(label2));
  
  			layout.Children.Remove(lastItem);
  			Assert.AreEqual(new Rectangle(0, 0, 150, 50), label0.Bounds);
  			Assert.AreEqual(new Rectangle(150, 0, 150, 50), label1.Bounds);
  
  			layout.Children.Insert(0, lastItem);
  
  			Assert.AreEqual(new Rectangle(0, 0, 100, 50), label2.Bounds);
  			Assert.AreEqual(new Rectangle(100, 0, 100, 50), label0.Bounds);
  			Assert.AreEqual(new Rectangle(200, 0, 100, 50), label1.Bounds);
  		}
  
  		[Test]
  		public void TestSizeThatFits()
  		{
  			Device.PlatformServices = new MockPlatformServices(useRealisticLabelMeasure:true);
  
  			var layout = new FlexLayout {
  				Direction = FlexDirection.Row,
  				AlignItems = FlexAlignItems.Start,
  				IsPlatformEnabled = true
  			};
  
  			var label1 = new Label {
  				IsPlatformEnabled = true,
  				LineBreakMode = LineBreakMode.TailTruncation,
  				Text = @"This is a very very very very very very very very long piece of text."
  			};
  			FlexLayout.SetShrink(label1, 1);
  			layout.Children.Add(label1);
  
  			var label2 = new Label {
  				Text = "",
  				IsPlatformEnabled = true,
  				WidthRequest = 10,
  				HeightRequest = 10
  			};
  			layout.Children.Add(label2);
  			layout.Layout(new Rectangle(0, 0, 320, 50));
  
  			var label2Size = label2.Measure(double.PositiveInfinity, double.PositiveInfinity);
  			Assert.AreEqual(10, label2Size.Request.Height);
  			Assert.AreEqual(10, label2Size.Request.Width);
  
  			var label1Size = label1.Measure(double.PositiveInfinity, double.PositiveInfinity);
  			//	var layoutSize = layout.Measure(-1, -1);
  		}
  
  		[Test]
  		public void TestNesting()
  		{
  			var header = new View { HeightRequest = 50, IsPlatformEnabled = true, };
  			var footer = new View { HeightRequest = 50, IsPlatformEnabled = true, };
  			Func<View> createItem = () => {
  				var v = new View { WidthRequest = 50, Margin = 5, IsPlatformEnabled = true, };
  				FlexLayout.SetGrow(v, 1);
  				return v;
  			};
  
  			var layout = new FlexLayout
  			{
  				IsPlatformEnabled = true,
  				Children = {
  					header,
  					new FlexLayout{
  						Direction = FlexDirection.Row,
  						IsPlatformEnabled = true,
  						Children = {
  							createItem(),
  							createItem(),
  							createItem(),
  							createItem(),
  							createItem(),
  						}
  					},
  					footer,
  				},
  				Direction = FlexDirection.Column,
  			};
  
  			var inner = layout.Children[1] as FlexLayout;
  			FlexLayout.SetGrow(inner, 1);
  
  			layout.Layout(new Rectangle(0, 0, 300, 600));
  			Assert.That(layout.Bounds, Is.EqualTo(new Rectangle(0, 0, 300, 600)));
  			Assert.That(header.Bounds, Is.EqualTo(new Rectangle(0, 0, 300, 50)));
  			Assert.That(inner.Bounds, Is.EqualTo(new Rectangle(0, 50, 300, 500)));
  			Assert.That(inner.Children[0].Bounds, Is.EqualTo(new Rectangle(5, 5, 50, 490)));
  			Assert.That(inner.Children[1].Bounds, Is.EqualTo(new Rectangle(65, 5, 50, 490)));
  			Assert.That(inner.Children[2].Bounds, Is.EqualTo(new Rectangle(125, 5, 50, 490)));
  			Assert.That(inner.Children[3].Bounds, Is.EqualTo(new Rectangle(185, 5, 50, 490)));
  			Assert.That(inner.Children[4].Bounds, Is.EqualTo(new Rectangle(245, 5, 50, 490)));
  
  			Assert.That(footer.Bounds, Is.EqualTo(new Rectangle(0, 550, 300, 50)));
  		}
  
  		[Test]
  		public void TestMeasuring()
  		{
  			var label = new Label {
  				IsPlatformEnabled = true,
  			};
  			var Layout = new FlexLayout {
  				IsPlatformEnabled = true,
  				Direction = FlexDirection.Row,
  				Wrap = FlexWrap.Wrap,
  				Children = { 
  					label,
  				}
  			};
  
  			//measure sith +inf as main-axis
  			var measure = Layout.Measure(double.PositiveInfinity, 40);
  			Assert.That(measure.Request, Is.EqualTo(new Size(100, 40)));
  
  			//measure sith +inf as cross-axis
  			measure = Layout.Measure(200, double.PositiveInfinity);
  			Assert.That(measure.Request, Is.EqualTo(new Size(200, 20)));
  
  			//measure with +inf as both axis
  			measure = Layout.Measure(double.PositiveInfinity, double.PositiveInfinity);
  			Assert.That(measure.Request, Is.EqualTo(new Size(100, 20)));
  
  		}
  
  		[Test]
  		public void TestMarginsWithWrap()
  		{
  			var label0 = new Label {
  				IsPlatformEnabled = true,
  				Margin=6,
  			};
  			var label1 = new Label {
  				IsPlatformEnabled = true,
  				Margin=6,
  			};
  			var label2 = new Label {
  				IsPlatformEnabled = true,
  			};
  			FlexLayout.SetGrow(label0, 0);
  			FlexLayout.SetBasis(label0, new FlexBasis(.5f, true));
  			FlexLayout.SetGrow(label1, 0);
  			FlexLayout.SetBasis(label1, new FlexBasis(.5f, true));
  			FlexLayout.SetGrow(label2, 0);
  			FlexLayout.SetBasis(label2, new FlexBasis(1f, true));
  			var layout = new FlexLayout {
  				IsPlatformEnabled = true,
  				Direction = FlexDirection.Row,
  				Wrap = FlexWrap.Wrap,
  				AlignItems = FlexAlignItems.Start,
  				AlignContent = FlexAlignContent.Start,
  				Children = {
  					label0,
  					label1,
  					label2,
  				}
  			};
  
  			var measure = layout.Measure(300, double.PositiveInfinity);
  			Assert.That(measure.Request, Is.EqualTo(new Size(300, 52)));
  			layout.Layout(new Rectangle(0, 0, 300, 300));
  			Assert.That(label0.Bounds, Is.EqualTo(new Rectangle(6, 6, 138, 20)));
  			Assert.That(label1.Bounds, Is.EqualTo(new Rectangle(156, 6, 138, 20)));
  			Assert.That(label2.Bounds, Is.EqualTo(new Rectangle(0, 32, 300, 20)));
  		}
  
  		[Test]
  		//https://github.com/xamarin/Xamarin.Forms/issues/2551
  		public void TestReverseWithGrow()
  		{
  			var label0 = new Label {
  				IsPlatformEnabled = true,
  			};
  			FlexLayout.SetGrow(label0, 1);
  			var layout = new FlexLayout {
  				IsPlatformEnabled = true,
  				Direction = FlexDirection.ColumnReverse,
  				Children = {
  					label0,
  				}
  			};
  
  			layout.Layout(new Rectangle(0, 0, 300, 300));
  			Assert.That(label0.Bounds, Is.EqualTo(new Rectangle(0, 0, 300, 300)));
  		}
  
  		[Test]
  		public void TestIsVisible()
  		//https://github.com/xamarin/Xamarin.Forms/issues/2593
  		{
  			var label0 = new Label {
  				IsPlatformEnabled = true,
  			};
  			var label1 = new Label {
  				IsPlatformEnabled = true,
  			};
  			var label2 = new Label {
  				IsPlatformEnabled = true,
  			};
  			var layout = new FlexLayout {
  				IsPlatformEnabled = true,
  				Direction = FlexDirection.Column,
  				Children = {
  					label0,
  					label1,
  					label2,
  				}
  			};
  
  			layout.Layout(new Rectangle(0, 0, 300, 300));
  			Assert.That(label0.Bounds, Is.EqualTo(new Rectangle(0, 0, 300, 20)));
  			Assert.That(label1.Bounds, Is.EqualTo(new Rectangle(0, 20, 300, 20)));
  			Assert.That(label2.Bounds, Is.EqualTo(new Rectangle(0, 40, 300, 20)));
  
  			label1.IsVisible = false;
  			Assert.That(label0.Bounds, Is.EqualTo(new Rectangle(0, 0, 300, 20)));
  			Assert.That(label2.Bounds, Is.EqualTo(new Rectangle(0, 20, 300, 20)));
  
  			label0.IsVisible = false;
  			label1.IsVisible = true;
  			Assert.That(label1.Bounds, Is.EqualTo(new Rectangle(0, 0, 300, 20)));
  			Assert.That(label2.Bounds, Is.EqualTo(new Rectangle(0, 20, 300, 20)));
  		}
  
  		[Test]
  		public void ChangingGrowTriggersLayout()
  		//https://github.com/xamarin/Xamarin.Forms/issues/2821
  		{
  			var layout = new FlexLayout {
  				IsPlatformEnabled = true,
  				Direction = FlexDirection.Column,
  			};
  
  			layout.Layout(new Rectangle(0, 0, 300, 300));
  			for (var i = 0; i < 3; i++) {
  				var box = new BoxView {
  					IsPlatformEnabled = true,
  				};
  				layout.Children.Add(box);
  				FlexLayout.SetGrow(box, 1f);
  			}
  
  			Assert.That(layout.Children[2].Bounds, Is.EqualTo(new Rectangle(0, 200, 300, 100)));
  		}
  
  		[Test]
  		public void PaddingOnLayout()
  		//https://github.com/xamarin/Xamarin.Forms/issues/2663
  		{
  			var label0 = new Label {
  				IsPlatformEnabled = true,
  			};
  			var label1 = new Label {
  				IsPlatformEnabled = true,
  			};
  			var label2 = new Label {
  				IsPlatformEnabled = true,
  			};
  			var layout = new FlexLayout {
  				IsPlatformEnabled = true,
  				JustifyContent = FlexJustify.SpaceBetween,
  				AlignItems = FlexAlignItems.Start,
  
  				Padding = new Thickness(20,10,20,0),
  				Children = {
  					label0,
  					label1,
  					label2,
  				}
  			};
  
  			layout.Layout(new Rectangle(0, 0, 500, 300));
  			Assert.That(layout.Children[0].Bounds, Is.EqualTo(new Rectangle(20, 10, 100, 20)));
  			Assert.That(layout.Children[2].Bounds, Is.EqualTo(new Rectangle(380, 10, 100, 20)));
  		}
  	}
  }
  