using System;
using System.Collections;
using System.Collections.Generic;
using AlgorithmCollection;
using UnityEngine;

// 递归与分治算法

namespace AlgorithmCollection.Recursion
{

    public struct DivisionDescriptor
    {
        public int left;
        public int right;
        public object userdata;
    }

    public static class RecursionHelper
    {
        #region 全排列,返回数据的所有组合

        public static void Permutations<T>(List<T> data, ref List<List<T>> perms)          //  A B C D 
        {                                                                                  //  + A (BCD)
            List<List<T>> outPerms = new List<List<T>>();                                  //  	+ B (CD)
            List<T> temp = new List<T>(data.Count);                                        //  		+ C(D)
            DivideAndConquer(data,                                                         //  			+D
                (IList<T> dataList) => // init                                             //  		+ D(C)
                {                                                                          //  			+C
                    DivisionDescriptor div = new DivisionDescriptor();                     //  	+ C (BD)
                    div.userdata = -1;                                                     //  		+ B(D)
                    div.left = 0;                                                          //  		+ D(B)
                    div.right = dataList.Count - 1;                                        //  	+ D (BC)
                    return div;                                                            //  		+ B(C)
                },                                                                         //  		+ C(B)
                (IList<T> dataList, DivisionDescriptor div) => // adhoc 最小子任务处理      //  + B (ACD)
                {                                                                          //  + C (ABD)
                    temp.Add(dataList[div.left]);                                          //  + D (ABC)
                    List<T> newCompose = new List<T>(temp);                                
                    outPerms.Add(newCompose);                                              
                    temp.RemoveAt(temp.Count - 1);                                         
                },                                                                         
                (IList<T> dataList, DivisionDescriptor div, out bool bAdhoc) => // 划分    
                {
                    int left = div.left; // 包含第一个元素在内的范围
                    int right = div.right;
                    int pivot = (int)div.userdata; // 第一个元素在范围内的索引
                    DivisionDescriptor[] divisions;
                    int l = left;
                    if (pivot != -1)
                    {
                        temp.Add(dataList[pivot]);
                        Algorithms.Swap(ref dataList, pivot, left);
                        l = left + 1;
                    }
                    divisions = new DivisionDescriptor[right - l + 1];
                    int j = 0;
                    for (int i = l; i <= right ; ++i)
                    {
                        divisions[j].left = l;
                        divisions[j].right = right;
                        divisions[j].userdata = (int)i;
                        j++;
                    }
                    bAdhoc = l == right;
                    return divisions;
                },
                null, // 合并
                (IList<T> dataList, DivisionDescriptor div) => //子任务后处理
                {
                    int pivot = (int)div.userdata; // 第一个元素的索引
                    int left = div.left;
                    int right = div.right;
                    Algorithms.Swap(ref dataList, pivot, left);
                    temp.RemoveAt(temp.Count - 1);
                }
            );
            perms = outPerms;
        }

        // 生成器形式,每次返回一个组合
        public static IEnumerable Permutations<T>(List<T> data)
        {
            foreach (var perm in _Permutations(data, 0, data.Count - 1))
            {
                yield return perm;
            }
        }

        // 计算start~end范围内的全排列
        private static IEnumerable _Permutations<T>(List<T> data, int start, int end, List<T> perm = null)
        {
			if (perm == null)
                perm = new List<T>(data.Count);
            if (start == end)
            {
                perm.Add(data[start]);
                yield return perm;
                perm.RemoveAt(perm.Count - 1);
            }
            else
            {
                for (int i = start; i <= end; ++i)
                {
                    perm.Add(data[i]);
                    Algorithms.Swap(ref data, start, i);
                    IEnumerator itor = _Permutations(data, start + 1, end, perm).GetEnumerator();
                    while (itor.MoveNext())
                        yield return itor.Current;
                    Algorithms.Swap(ref data, start, i);
                    perm.RemoveAt(perm.Count - 1);
                }
            }
        }
        #endregion

        #region 分治算法

        public delegate DivisionDescriptor Init<T>(IList<T> dataList);
        public delegate void AdHoc<T>(IList<T> dataList, DivisionDescriptor division);
        public delegate DivisionDescriptor[] Divide<T>(IList<T> dataList, DivisionDescriptor division, out bool bAdhoc);
        public delegate void Merge<T>(IList<T> dataList, DivisionDescriptor[] divisions);
        public delegate void Postprocess<T>(IList<T> dataList, DivisionDescriptor div);

        // 分治算法框架
        public static void DivideAndConquer<T>(IList<T> dataList, Init<T> init, AdHoc<T> adhoc, Divide<T> divide, Merge<T> merge = null, Postprocess<T> postprocess = null)
        {
            DivisionDescriptor div = init(dataList);
            _DivideAndConquer(dataList, div, adhoc, divide, merge, postprocess);
        }

        private static void _DivideAndConquer<T>(IList<T> dataList, DivisionDescriptor div, AdHoc<T> adhoc, Divide<T> divide, Merge<T> merge, Postprocess<T> postprocess)
        {
            bool bAdhoc;
            DivisionDescriptor[] division = divide(dataList, div, out bAdhoc);
            if (!bAdhoc)
            {
                for(int i = 0; i < division.Length; ++i)
                {
                    _DivideAndConquer(dataList, division[i], adhoc, divide, merge, postprocess);
                    postprocess?.Invoke(dataList, division[i]);
                }
                merge?.Invoke(dataList, division);
            }
            else
            {
                for(int i = 0; i < division.Length; ++i)
                {
                    adhoc(dataList, division[i]);
                }
            }
        }

        // 分治算法框架,非递归
        public static void DivideAndConquer_NoneRecursion<T>(IList<T> dataList, int threshold, AdHoc<T> adhoc, Divide<T> divide, Merge<T> merge)
        {

        }

        #endregion 

    }
}