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

namespace EasyDevCore.Common
{
    /// <summary>
    /// 
    /// </summary>
    public static class LinqExtensions
    {
        /// <summary>
        /// Indexes the of.
        /// </summary>
        /// <typeparam name="TSource">The type of the source.</typeparam>
        /// <param name="source">The source.</param>
        /// <param name="item">The item.</param>
        /// <returns></returns>
        public static int IndexOf<TSource>(this IEnumerable<TSource> source, TSource item)
        {
            int index = 0;
            foreach (TSource sourceItem in source)
            {
                if ((item == null && sourceItem == null) || (sourceItem != null && sourceItem.Equals(item))) return index;
                index++;
            }
            return -1;
        }

         /// <summary>
        /// Fors the each.
        /// </summary>
        /// <typeparam name="TSource">The type of the source.</typeparam>
        /// <param name="source">The source.</param>
        /// <param name="action">The action.</param>
        /// <returns></returns>
        public static IEnumerable<TSource> ForEach<TSource>(this IEnumerable<TSource> source, Action<TSource> action)
        {
            foreach (var item in source)
                action(item);
            return source;
        }

        /// <summary>
        /// Fors the each.
        /// </summary>
        /// <typeparam name="TSource">The type of the source.</typeparam>
        /// <param name="source">The source.</param>
        /// <param name="action">The action.</param>
        /// <returns></returns>
        public static IEnumerable ForEach<TSource>(this IEnumerable source, Action<TSource> action)
        {
            foreach (var item in source)
                action((TSource)item);
            return source;
        }

        /// <summary>
        /// Firsts the value.
        /// </summary>
        /// <typeparam name="TSource">The type of the t source.</typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="predicate">The predicate.</param>
        /// <param name="selector">The selector.</param>
        /// <returns>V.</returns>
        public static V FirstValue<TSource, V>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, Func<TSource, V> selector)
        {
#pragma warning disable CS8604 // Possible null reference argument.
            return selector(source.FirstOrDefault(predicate));
#pragma warning restore CS8604 // Possible null reference argument.
        }

        /// <summary>
        /// Firsts the value.
        /// </summary>
        /// <typeparam name="TSource">The type of the t source.</typeparam>
        /// <typeparam name="V"></typeparam>
        /// <param name="source">The source.</param>
        /// <param name="selector">The selector.</param>
        /// <returns>V.</returns>
        public static V FirstValue<TSource, V>(this IEnumerable<TSource> source, Func<TSource, V> selector)
        {
#pragma warning disable CS8604 // Possible null reference argument.
            return selector(source.FirstOrDefault());
#pragma warning restore CS8604 // Possible null reference argument.
        }

        /// <summary>
        /// Maps the specified selector.
        /// </summary>
        /// <typeparam name="TSource">The type of the source.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="source">The source.</param>
        /// <param name="selector">The selector.</param>
        /// <returns>
        ///   <br />
        /// </returns>
        public static IEnumerable<TResult> Map<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
            => source.Select(selector);
    }
}
