﻿// ****************************************************************************
// <copyright file="IDictionaryExtensions.cs" company="Pedro Lamas">
// Copyright © Pedro Lamas 2014
// </copyright>
// ****************************************************************************
// <author>Pedro Lamas</author>
// <email>pedrolamas@gmail.com</email>
// <project>Cimbalino.Toolkit.Core</project>
// <web>http://www.pedrolamas.com</web>
// <license>
// See license.txt in this solution or http://www.pedrolamas.com/license_MIT.txt
// </license>
// ****************************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;

namespace Cimbalino.Toolkit.Extensions
{
    /// <summary>
    /// Provides a set of static (Shared in Visual Basic) methods for <see cref="IDictionary{TKey, TValue}"/> instances.
    /// </summary>
    public static class IDictionaryExtensions
    {
        /// <summary>
        /// Applies the specified <see cref="Action{KeyValuePair}"/> to the dictionary.
        /// </summary>
        /// <param name="dictionary">The dictionary.</param>
        /// <param name="action">The action to apply.</param>
        /// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
        /// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
        public static void Apply<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> dictionary, Action<KeyValuePair<TKey, TValue>> action)
        {
            foreach (var item in dictionary)
            {
                action(item);
            }
        }

        /// <summary>
        /// Gets the value associated with the specified key.
        /// </summary>
        /// <param name="dictionary">The dictionary.</param>
        /// <param name="key">The key whose value to get.</param>
        /// <returns>The value for the specified key.</returns>
        /// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
        /// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
        public static TValue GetValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {
            return dictionary.GetValue(key, default(TValue));
        }

        /// <summary>
        /// Gets the value associated with the specified key.
        /// </summary>
        /// <param name="dictionary">The dictionary.</param>
        /// <param name="key">The key whose value to get.</param>
        /// <param name="defaultValue">The default value if the specified key does not exist.</param>
        /// <returns>The value for the specified key.</returns>
        /// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
        /// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
        public static TValue GetValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
        {
            TValue value;

            return dictionary.TryGetValue(key, out value) ? value : defaultValue;
        }

        /// <summary>
        /// Sets the value for the specified key. If the entry does not exist, a new one will be added.
        /// </summary>
        /// <param name="dictionary">The dictionary.</param>
        /// <param name="key">The key whose value to set.</param>
        /// <param name="value">The value for the specified key.</param>
        /// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
        /// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
        public static void SetValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue value)
        {
            if (dictionary.ContainsKey(key))
            {
                dictionary[key] = value;
            }
            else
            {
                dictionary.Add(key, value);
            }
        }

        /// <summary>
        /// Creates a proper query string for the values in the dictionary.
        /// </summary>
        /// <param name="dictionary">The dictionary.</param>
        /// <returns>A proper query string.</returns>
        public static string ToQueryString(this IEnumerable<KeyValuePair<string, string>> dictionary)
        {
            return dictionary.ToQueryString(false);
        }

        /// <summary>
        /// Creates a proper query string for the values in the dictionary, with or without empty values included.
        /// </summary>
        /// <param name="dictionary">The dictionary.</param>
        /// <param name="includeEmptyValues">If the empty values should be included in the resulting query string.</param>
        /// <returns>A proper query string.</returns>
        public static string ToQueryString(this IEnumerable<KeyValuePair<string, string>> dictionary, bool includeEmptyValues)
        {
            return string.Join("&", dictionary
                .Where(x => includeEmptyValues || !string.IsNullOrEmpty(x.Value))
                .Select(x => WebUtility.UrlEncode(x.Key) + "=" + WebUtility.UrlEncode(x.Value ?? string.Empty)));
        }
    }
}