using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace ScaffoldingExample.Helpers
{
    /// <summary>
    /// Класс для изменения порядка следования элементов
    /// </summary>
    /// <typeparam name="T">Тип данных</typeparam>
    public class OrderHelper<T> where T : IOrderHelper<T>, new() 
    {
        /// <summary>
        /// Новый порядковый номер по умолчанию для нового элемента
        /// </summary>
        /// <param name="data">Множество данных на котором будет определяться порядок</param>
        /// <returns></returns>
        public static int OrderForNewRecord(IEnumerable<T> data)
        {
            T t = new T();

            int Result = 0;
            if (data.Count() == 0)
            {
                Result = 1;
            }
            else
            {
                int i = t.MaxOrder(data);
                Result = i + 1;
            }

            return Result;
        }

        /// <summary>
        /// Компенсация порядков при удалении
        /// Необходимо вызывать перед удалением
        /// </summary>
        /// <param name="data">Множество данных на котором будет определяться порядок</param>
        /// <param name="objToDelete">Объект, который должен быть удален</param>
        public static void OrderDelCompensate(IEnumerable<T> data, T currentObj, out List<T> elementsToSave)
        {
            //Порядок для удаляемого объекта
            int delOrder = currentObj.GetOrder();

            //Список объектов, у которых порядок больше удаляемого
            var q = data.Where(x => x.GetOrder() > delOrder).ToList();
            foreach (var x in q)
            {
                //Уменьшить порядок на 1
                int currentOrder = x.GetOrder();
                if (currentOrder > 0)
                {
                    x.SetOrder(currentOrder - 1);
                }
            }

            //Необходимо сохранить измененные элементы
            elementsToSave = q;
        }

        /// <summary>
        /// Изменение порядка
        /// </summary>
        /// <param name="data">Множество, на котором производится изменение</param>
        /// <param name="objCurrent">Объект, у которого изменяется порядок</param>
        /// <param name="d">Направление перемещения: 1 - вверх, другое - вниз</param>
        public static void OrderChange(IEnumerable<T> data, T currentObj, int d, out T pairedOrderElement)
        {
            pairedOrderElement = default(T);
            T t = new T();
            var q = data.ToList();
            int currentObjOrder = currentObj.GetOrder();

            //Если менее 1 записи, то порядок не изменяется
            if (q.Count > 1)
            {
                int OrderMin = t.MinOrder(data);
                int OrderMax = t.MaxOrder(data);

                //Перемещение вверх
                if (d == 1)
                {
                    //Верхний элемент не перемещается вверх
                    if (currentObjOrder > OrderMin)
                    {
                        //Поиск предыдущего элемента для обмена
                        
                        //Множество предыдущих элементов
                        var prevs = q.Where(x => x.GetOrder() < currentObjOrder);
                        //Максимальный порядок для предыдущих элементов
                        int prevsMaxOrder = t.MaxOrder(prevs);
                        //Предыдущий элемент
                        var prevsMax = prevs.FirstOrDefault(x => x.GetOrder() == prevsMaxOrder);
                        if (prevsMax != null)
                        {
                            //Если предыдущий элемент найден, то обмен порядками
                            int prevObjOrder = prevsMax.GetOrder();
                            //Текущий порядок присваивается предыдущему элементу
                            prevsMax.SetOrder(currentObjOrder);
                            //Предыдущий порядок присваивается текущему элементу
                            currentObj.SetOrder(prevObjOrder);
                            //Выходной параметр
                            pairedOrderElement = prevsMax;
                        }
                    }
                }
                else
                {
                    //Нижний элемент не перемещается вниз
                    if (currentObjOrder < OrderMax)
                    {
                        //Поиск последующего элемента для обмена

                        //Множество последущих элементов
                        var posts = q.Where(x => x.GetOrder() > currentObjOrder);
                        //Минимальный порядок для последующих элементов
                        int postsMinOrder = t.MinOrder(posts);
                        //Последующий элемент
                        var postsMin = posts.FirstOrDefault(x => x.GetOrder() == postsMinOrder);
                        if (postsMin != null)
                        {
                            //Если последующий элемент найден, то обмен порядками
                            int postObjOrder = postsMin.GetOrder();
                            //Текущий порядок присваивается последующему элементу
                            postsMin.SetOrder(currentObjOrder);
                            //Последующий порядок присваивается текущему элементу
                            currentObj.SetOrder(postObjOrder);
                            //Выходной параметр
                            pairedOrderElement = postsMin;
                        }
                    }
                }
            }
        }

    }
}