using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Linq.Expressions;

using Xunit;

namespace LinqStudy.Test.LinqToObject
{
    /// <summary>
    /// 排序操作符
    /// 数据源为null时,均引发ArgumentNullException异常
    /// </summary>
    public class OrderTest
    {
        #region OrderBy

        /// <summary>
        /// OrderBy:升序排序(从小到大);延迟执行
        /// </summary>
        [Fact]
        public void OrderBy_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 3, Name = "张三", Age=33 },
                new Person(){ Id = 5, Name = "王五", Age=55 },
                new Person(){ Id = 4, Name = "李四", Age=44 },
            };

            var oprationItem = peoples.OrderBy(p => p.Id);
            var firtName = oprationItem.First().Name;

            Assert.Equal("张三", firtName);
        }

        /// <summary>
        /// 延迟执行
        /// </summary>
        [Fact]
        public void OrderBy_Delay_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 3, Name = "张三", Age=33 },
                new Person(){ Id = 5, Name = "王五", Age=55 },
                new Person(){ Id = 4, Name = "李四", Age=44 },
            };

            var oprationItem = peoples.OrderBy(p => p.Id);

            peoples.Insert(0, new Person() { Id = 6, Name = "赵六", Age = 66 });

            //执行一次排序
            var firtName = oprationItem.First().Name;
            //再执行一次排序
            var lastName = oprationItem.Last().Name;

            Assert.Equal("张三", firtName);
            Assert.Equal("赵六", lastName);
        }

        /// <summary>
        /// 重载:自定义Comparable比较器
        /// </summary>
        [Fact]
        public void OrderBy_CustomComparable_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 1, Name = "张三", Age=33 },
                new Person(){ Id = 3, Name = "李四", Age=65 },
                new Person(){ Id = 2, Name = "王五", Age=17 },
            };

            var oprationItem = peoples.OrderBy(p => p, new PersonComparer());

            var firtId = oprationItem.First().Id;
            var lastId = oprationItem.Last().Id;

            Assert.Equal(1, firtId);
            Assert.Equal(3, lastId);
        }
        #endregion

        #region OrderByDescending
        /// <summary>
        /// OrderByDescending:降序排序(从大到步);延迟执行
        /// </summary>
        [Fact]
        public void OrderByDescending_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 1, Name = "张三", Age=33 },
                new Person(){ Id = 3, Name = "李四", Age=65 },
                new Person(){ Id = 2, Name = "王五", Age=17 },
            };

            var oprationItem = peoples.OrderByDescending(p => p.Id);

            var firtId = oprationItem.First().Id;
            var lastId = oprationItem.Last().Id;

            Assert.Equal(3, firtId);
            Assert.Equal(1, lastId);
        }

        /// <summary>
        /// 延迟执行
        /// </summary>
        [Fact]
        public void OrderByDescending_Delay_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 1, Name = "张三", Age=33 },
                new Person(){ Id = 3, Name = "李四", Age=65 },
                new Person(){ Id = 2, Name = "王五", Age=17 },
            };

            var oprationItem = peoples.OrderByDescending(p => p.Id);

            var addItem = new Person() { Id = 4, Name = "赵六", Age = 87 };
            peoples.Add(addItem);

            var firtId = oprationItem.First().Id;
            var lastId = oprationItem.Last().Id;

            Assert.Equal(4, firtId);
            Assert.Equal(1, lastId);
        }

        /// <summary>
        /// 重载:自定义Comparable比较器
        /// </summary>
        [Fact]
        public void OrderByDescending_CustomComparable_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 1, Name = "张三", Age=33 },
                new Person(){ Id = 3, Name = "李四", Age=65 },
                new Person(){ Id = 2, Name = "王五", Age=17 },
            };

            var oprationItem = peoples.OrderByDescending(p => p, new PersonComparer());

            var firtId = oprationItem.First().Id;
            var lastId = oprationItem.Last().Id;

            Assert.Equal(3, firtId);
            Assert.Equal(1, lastId);
        }
        #endregion

        #region ThenBy
        /// <summary>
        /// ThenBy:按次要关键字,进行升序排序(从小到大);延迟执行
        /// </summary>
        [Fact]
        public void ThenBy_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 1, Name = "张三", Age=44 },
                new Person(){ Id = 1, Name = "李四", Age=33 },
                new Person(){ Id = 2, Name = "王五", Age=22 },
                new Person(){ Id = 2, Name = "赵六", Age=11 },
            };

            //先按Id排序,Id相同的,再按年龄排序。
            var oprationItem = peoples.OrderBy(p => p.Id).ThenBy(p => p.Age).Select(p => p.Name);
            var expected = new List<string>() { "李四", "张三", "赵六", "王五" };

            Assert.Equal(expected, oprationItem);
        }

        /// <summary>
        /// 延迟执行
        /// </summary>
        [Fact]
        public void ThenBy_Delay_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 1, Name = "张三", Age=44 },
                new Person(){ Id = 1, Name = "李四", Age=33 },
                new Person(){ Id = 2, Name = "王五", Age=22 },
                new Person(){ Id = 2, Name = "赵六", Age=11 },
            };

            var oprationItem = peoples.OrderBy(p => p.Id).ThenBy(p => p.Age);

            var addItme = new Person() { Id = 1, Name = "刘能", Age = 2 };
            peoples.Add(addItme);

            var actual = oprationItem.Select(p => p.Name).ToList();
            var expected = new List<string>() { "刘能", "李四", "张三", "赵六", "王五" };

            Assert.Equal(expected, actual);
        }

        /// <summary>
        /// 重载:自定义Comparable比较器
        /// </summary>
        [Fact]
        public void ThenBy_CustomComparable_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 1, Name = "张三", Age=44 },
                new Person(){ Id = 1, Name = "李四", Age=33 },
                new Person(){ Id = 2, Name = "王五", Age=22 },
                new Person(){ Id = 2, Name = "赵六", Age=11 },
            };

            var oprationItem = peoples.OrderBy(p => p, new PersonComparer()).ThenBy(p => p.Age, Comparer<int>.Default);

            var actual = oprationItem.Select(p => p.Name).ToList();
            var expected = new List<string>() { "李四", "张三", "赵六", "王五" };

            Assert.Equal(expected, actual);
        }
        #endregion

        #region ThenByDescending
        /// <summary>
        /// ThenByDescending:按次要关键字,进行降序排序(从大到小);延迟执行
        /// </summary>
        [Fact]
        public void ThenByDescending_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 1, Name = "张三", Age=44 },
                new Person(){ Id = 1, Name = "李四", Age=33 },
                new Person(){ Id = 2, Name = "王五", Age=22 },
                new Person(){ Id = 2, Name = "赵六", Age=11 },
            };

            //先按Id排序,Id相同的,再按年龄排序。
            var oprationItem = peoples.OrderBy(p => p.Id).ThenByDescending(p => p.Age).Select(p => p.Name);
            var expected = new List<string>() { "张三", "李四", "王五", "赵六" };

            Assert.Equal(expected, oprationItem);
        }

        /// <summary>
        /// 延迟执行
        /// </summary>
        [Fact]
        public void ThenByDescending_Delay_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 1, Name = "张三", Age=44 },
                new Person(){ Id = 1, Name = "李四", Age=33 },
                new Person(){ Id = 2, Name = "王五", Age=22 },
                new Person(){ Id = 2, Name = "赵六", Age=11 },
            };

            var oprationItem = peoples.OrderBy(p => p.Id).ThenByDescending(p => p.Age);

            var addItme = new Person() { Id = 1, Name = "刘能", Age = 2 };
            peoples.Add(addItme);

            var actual = oprationItem.Select(p => p.Name).ToList();
            var expected = new List<string>() { "张三", "李四", "刘能", "王五", "赵六" };

            Assert.Equal(expected, actual);
        }

        /// <summary>
        /// 重载:自定义Comparable比较器
        /// </summary>
        [Fact]
        public void ThenByDescending_CustomComparable_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 1, Name = "张三", Age=44 },
                new Person(){ Id = 1, Name = "李四", Age=33 },
                new Person(){ Id = 2, Name = "王五", Age=22 },
                new Person(){ Id = 2, Name = "赵六", Age=11 },
            };

            var oprationItem = peoples.OrderBy(p => p, new PersonComparer()).ThenByDescending(p => p.Age, Comparer<int>.Default);

            var actual = oprationItem.Select(p => p.Name).ToList();
            var expected = new List<string>() { "张三", "李四", "王五", "赵六", };

            Assert.Equal(expected, actual);
        }
        #endregion

        #region Resevse
        /// <summary>
        /// Resevse:反序序列(逆向);立即执行
        /// </summary>
        [Fact]
        public void Resevse_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 1, Name = "张三", Age=44 },
                new Person(){ Id = 2, Name = "李四", Age=33 },
            };

            //简单逆序
            peoples.Reverse();
            var firstId = peoples.First().Id;

            Assert.Equal(2, firstId);
        }

        /// <summary>
        /// Resevse:反序序列(逆向);立即执行
        /// </summary>
        [Fact]
        public void Resevse_immediately_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 1, Name = "张三", Age=33 },
                new Person(){ Id = 2, Name = "李四", Age=44 },
            };

            //简单逆序
            peoples.Reverse();

            peoples.Add(new Person() { Id = 3, Name = "云花公主", Age = 18 });

            //数据源变化,不影响结果。
            var firstId = peoples.First().Id;

            Assert.Equal(2, firstId);
        }

        /// <summary>
        /// Resevse重载:index开始项,count反序项的数量
        /// </summary>
        [Fact]
        public void Resevse_index_count_Test()
        {
            List<Person> peoples = new List<Person>()
            {
                new Person(){ Id = 1, Name = "张三", Age=44 },
                new Person(){ Id = 2, Name = "李四", Age=33 },
                new Person(){ Id = 3, Name = "王五", Age=44 },
                new Person(){ Id = 4, Name = "赵六", Age=33 },
            };

            //从指定位置开始逆序指定数量的项。
            //从序号为1(第2项)开始,反序2项:即反序第2第3两项。
            peoples.Reverse(1, 2);

            var secondId = peoples[1].Id;
            var thirdId = peoples[2].Id;

            Assert.Equal(3, secondId);
            Assert.Equal(2, thirdId);
        }
        #endregion
    }
}