using System.Collections;
using System.Collections.Generic;
using System;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;

public static class IEnumerableExt
{
    public static IEnumerable<T> AsEnumerable<T>(this T value)
    {
        yield return value;
    }

    public static T[] AsArray<T>(this IEnumerable<T> list)
    {
        return list.ToArray<T>();
    }

    public static List<T> AsList<T>(this IEnumerable<T> list)
    {
        return list.ToList<T>();
    }

    public static IEnumerable<R> Map<T, R>(this IEnumerable<T> list, Func<T, R> func)
    {
        if(list == null)
            throw new System.ArgumentNullException("list null");
        
        foreach (T t in list)
        {
            var r = func(t);
            if(r != null)
                yield return r;
        }
        //return list.Select(func);
    }

    public static IEnumerable<ValueTuple> ForEach<T>(this IEnumerable<T> list, Action<T> action)
    {
        return list.Map(action.ToFunc()).ToList();//list.ForEach<T>((e) => { action(e); });
    }

    public static IEnumerable<R> Bind<T, R>(this IEnumerable<T> list, Func<T, IEnumerable<R>> func)
    {
        foreach (T t in list)
        {
            foreach (R r in func(t))
                if (r != null)
                    yield return r;
        }
    }
    
    public static IEnumerable<T> AllWhere<T>(this IEnumerable<T> list, Func<T,bool> predict)
    {
        return list.Where(predict);
    }


    public static int IndexOf<T>(this IEnumerable<T> list, Func<T, bool> equalFunc)
    {
        var enumerator = list.GetEnumerator();
        int index = 0;
        while(enumerator.MoveNext())
        {
            T cur = enumerator.Current;
            if (equalFunc(cur))
            {
                return index;
            }
            index++;
        }
        return -1;
    }

    public static T GetMin<T>(this IEnumerable<T> list,Func<T,float> getValue)// where T:class
    {
        if (list.Count<T>() == 0)
            return default(T);

        T min = default(T);
        float curMinValue = float.MaxValue;
        foreach(var element in list)
        {
            if(getValue(element) < curMinValue)
            {
                curMinValue = getValue(element);
                min = element;
            }
        }
        return min;
    }
    public static T GetMax<T>(this IEnumerable<T> list,Func<T,float> getValue)
    {
        if (list.Count<T>() == 0)
            return default(T);

        T max = default(T);
        float curMaxValue = float.MinValue;
        foreach(var element in list)
        {
            if(getValue(element) > curMaxValue)
            {
                curMaxValue = getValue(element);
                max = element;
            }
        }
        return max;
    }

}

