/* Copyright (C) 2008 - 2011 by John Cronin
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

// Utility functions

using System;
using System.Collections.Generic;
using System.Text;

namespace libtysila
{
    public class util
    {
        /** <summary>Simple implementation of Except from C# 3.0</summary>
         * <param name="first">Elements of this set are returned as a new set, unless they occur in second</param>
         * <param name="second">If an element is in this set, it prevents that value being returned should it occur in first</param>
         */

        public static IEnumerable<T> Except<T>(IEnumerable<T> first, IEnumerable<T> second)
        {
            List<T> ret = new List<T>();
            IList<T> s = second as IList<T>;

            if (s == null)
                s = new List<T>(second);

            foreach (T t in first)
            {
                if (!(s.Contains(t)))
                    ret.Add(t);
            }
            return ret;
        }

        /** <summary>Returns a dictionary containing elements within first but not second</summary> */
        public static IEnumerable<KeyValuePair<K, V>> Except<K, V>(IDictionary<K, V> first, IDictionary<K, V> second)
        {
            foreach (KeyValuePair<K, V> kvp in first)
            {
                if (!second.ContainsKey(kvp.Key))
                    yield return kvp;
            }
            yield break;
        }

        /** <summary>Simple implementation of Intersect from C# 3.0</summary>
         * <param name="first">First set</param>
         * <param name="second">Second set</param>
         */

        public static IEnumerable<T> Intersect<T>(IEnumerable<T> first, IEnumerable<T> second)
        {
            if (first == null)
                yield break;
            if (second == null)
                yield break;

            if (!(first is ICollection<T>))
                first = new List<T>(first);

            foreach (T t in second)
            {
                if (((ICollection<T>)first).Contains(t))
                    yield return t;
            }
            yield break;
        }

        /** <summary>Returns a Dictionary of items from first whose keys are in second</summary>
         * <param name="first">Source dictionary</param>
         * <param name="second">Keys to look for</param>
         */
        public static IDictionary<K, V> Intersect<K, V>(IDictionary<K, V> first, ICollection<K> second)
        {
            Dictionary<K, V> ret = new Dictionary<K, V>();
            foreach (K k in second)
            {
                if (first.ContainsKey(k))
                    ret.Add(k, first[k]);
            }
            return ret;
        }

        /** <summary>Simple implementation of Union from C# 3.0</summary>
         * <param name="first">First set</param>
         * <param name="second">Second set</param>
         */

        public static IEnumerable<T> Union<T>(IEnumerable<T> first, IEnumerable<T> second)
        {
            if (first == null)
                yield break;
            if (second == null)
                yield break;

            if (!(first is ICollection<T>))
                first = new List<T>(first);

            foreach (T t in first)
                yield return t;

            foreach (T t in second)
            {
                if (!(((ICollection<T>)first).Contains(t)))
                    yield return t;
            }
            yield break;
        }

        /** <summary>Returns a dictionary containing those members of the initial dictionary whose keys are contained in match</summary>
         */
        public static IEnumerable<KeyValuePair<K, V>> Union<K, V>(IDictionary<K, V> initial, IEnumerable<K> match)
        {
            if (!(match is ICollection<K>))
                match = new List<K>(match);

            foreach (KeyValuePair<K, V> kvp in initial)
            {
                if (((ICollection<K>)match).Contains(kvp.Key))
                    yield return kvp;
            }
            yield break;
        }

        /** <summary>Aligns a value to a multiple of a particular value</summary>
         */
        public static int align(int input, int factor)
        {
            int i_rem_f = input % factor;
            if (i_rem_f == 0)
                return input;
            return input - i_rem_f + factor;
        }

        /** <summary>Return the largest of two numbers</summary>
         */
        public static int max(int a, int b)
        {
            if (a >= b)
                return a;
            else
                return b;
        }
    }
}
