﻿using System;

namespace Fairweather.Service
{
    /*       Autogenerated: Tuple.pl      */
    public static class Pair
    {
        public static IPair<T1, T2>
        To_Mutable<T1, T2>(this IPair<T1, T2> pair) {

            throw new NotImplementedException();

        }

        public static IPair<T1, T2>
        To_Immutable<T1, T2>(this IPair<T1, T2> pair) {

            throw new NotImplementedException();

        }

        public static T[]
        To_Array<T>(this Pair<T> pair) {

            var ret = new T[] { pair.First, pair.Second };

            return ret;

        }

        public static Pair<T>
        Flip<T>(this Pair<T> pair) {

            var ret = new Pair<T>(pair.Second, pair.First);

            return ret;

        }

        public static Pair<T2, T1>
        Flip<T1, T2>(this Pair<T1, T2> pair) {

            var ret = Make(pair.Second, pair.First);

            return ret;
        }


        public static int
        Compare_First<T>(Pair<T> pair1, Pair<T> pair2)
            where T : IComparable<T> {

            var ret = pair1.First.CompareTo(pair2.First);
            if (ret == 0)
                ret = pair1.Second.CompareTo(pair2.Second);
            return ret;

        }

        public static int
        Compare_Second<T>(Pair<T> pair1, Pair<T> pair2)
            where T : IComparable<T> {

            var ret = pair1.Second.CompareTo(pair2.Second);
            if (ret == 0)
                ret = pair1.First.CompareTo(pair2.First);

            return ret;

        }

        static public Pair<T>
        Make1<T>(T first, T second) {

            var ret = new Pair<T>(first, second);
            return ret;

        }

        static public Pair<T1, T2>
        Make<T1, T2>(T1 first, T2 second) {

            var ret = new Pair<T1, T2>(first, second);
            return ret;

        }

        static public Mutable_Pair<T1, T2>
        Make_Mutable<T1, T2>(T1 first, T2 second) {

            var ret = new Mutable_Pair<T1, T2>(first, second);
            return ret;

        }


        static public Pair<Pair<T>>
        Unfold<T>(Quad<T> quad) {

            var ret = new Pair<Pair<T>>(new Pair<T>(quad.First, quad.Second),
                                    new Pair<T>(quad.Third, quad.Fourth));
            return ret;
        }

        static public Quad<T>
        Fold<T>(Pair<Pair<T>> pair) {

            var ret = new Quad<T>(pair.First.First, pair.First.Second,
                                  pair.Second.First, pair.Second.Second);
            return ret;
        }


        static public Pair<T>
        Mutate<T>(this Pair<T> pair, T value, bool first) {

            Pair<T> ret;
            if (first)
                ret = new Pair<T>(value, pair.Second);
            else
                ret = new Pair<T>(pair.First, value);

            return ret;

        }


        static public Pair<T1, T2>
        Mutate<T1, T2>(this Pair<T1, T2> pair, T1 value) {

            var ret = Pair.Make(value, pair.Second);

            return ret;

        }


        static public Pair<T1, T2>
        Mutate<T1, T2>(this Pair<T1, T2> pair, T2 value) {

            var ret = Pair.Make(pair.First, value);

            return ret;

        }


        static public Pair<TResult>
        Fmap<TSource, TResult>(Pair<TSource> pair, Func<TSource, TResult> func) {

            return new Pair<TResult>(func(pair.First),
                               func(pair.Second));

        }


        static public Pair<TResult>
        Fmap<T1, T2, TResult>(Pair<T1> pair1,
                              Pair<T2> pair2,
                              Func<T1, T2, TResult> func) {

            return new Pair<TResult>(func(pair1.First, pair2.First),
                                     func(pair1.Second, pair2.Second));
        }

        static public void
        Apply<T1, T2>(Pair<T1> pair1, Pair<T2> pair2, Action<T1, T2> act) {

            act(pair1.First, pair2.First);
            act(pair1.Second, pair2.Second);

        }

        static public void
        Apply<T>(Pair<T> pair, Action<T> act) {

            act(pair.First);
            act(pair.Second);

        }

        public static Pair<T> 
        Fmap<T>(Pair<T> pair, 
                Func<T, T> func,
                bool first, 
                bool second) {

            var tmp_first = pair.First;
            var tmp_second = pair.Second;
            if (first) {
                tmp_first = func(tmp_first);
            }
            if (second) {
                tmp_second = func(tmp_second);
            }
            var ret = new Pair<T>(tmp_first, tmp_second);
            return ret;
        }

        public static Pair<TResult>
        Fmap<TSource, TResult>(Pair<TSource> pair, 
                               Func<TSource, TResult> func,
                               bool first, 
                               bool second) {

            var tmp_first = func(pair.First);
            var tmp_second = func(pair.Second);
            var ret = new Pair<TResult>(tmp_first, tmp_second);
            return ret;
        }


    }

    /*       Autogenerated: Tuple.pl      */
    public static class Triple
    {
        static public T[] To_Array<T>(this Triple<T> triple) {
            var ret = new T[] { triple.First, triple.Second, triple.Third };

            return ret;

        }



        static public Triple<T>
        Make1<T>(T first, T second, T third) {

            var ret = new Triple<T>(first, second, third);
            return ret;

        }

        static public Triple<T1, T2, T3>
        Make<T1, T2, T3>(T1 first, T2 second, T3 third) {

            var ret = new Triple<T1, T2, T3>(first, second, third);
            return ret;

        }

        static public Mutable_Triple<T1, T2, T3>
        Make_Mutable<T1, T2, T3>(T1 first, T2 second, T3 third) {

            var ret = new Mutable_Triple<T1, T2, T3>(first, second, third);
            return ret;

        }


        static public void
        Apply<T>(Triple<T> triple, Action<T> act) {

            act(triple.First);
            act(triple.Second);
            act(triple.Third);

        }

        // triple.{[^)]+}
        // triple1.\1, triple2.\1
        static public void
        Apply<T1, T2>(Triple<T1> triple1,
                      Triple<T2> triple2,
                      Action<T1, T2> act) {

            act(triple1.First, triple2.First);
            act(triple1.Second, triple2.Second);
            act(triple1.Third, triple2.Third);

        }

        static public Triple<TResult>
        Fmap<TSource, TResult>(Triple<TSource> triple, Func<TSource, TResult> func) {
            return new
            Triple<TResult>(func(triple.First),
                            func(triple.Second),
                            func(triple.Third));
        }

        static public Triple<TResult>
        Fmap<TSource1, TSource2, TResult>(Triple<TSource1> triple1,
                Triple<TSource2> triple2,
                Func<TSource1, TSource2, TResult> func) {

            return new Triple<TResult>(func(triple1.First, triple2.First),
                                       func(triple1.Second, triple2.Second),
                                       func(triple1.Third, triple2.Third));

        }

        public static Triple<T>
        Fmap<T>
        (Triple<T> triple, Func<T, T> func, bool first, bool second, bool third) {

            var tmp_first = triple.First;
            var tmp_second = triple.Second;
            var tmp_third = triple.Third;
            if (first) {
                tmp_first = func(tmp_first);
            }
            if (second) {
                tmp_second = func(tmp_second);
            }
            if (third) {
                tmp_third = func(tmp_third);
            }
            var ret = new Triple<T>(tmp_first, tmp_second, tmp_third);
            return ret;
        }

        public static Triple<TResult>
        Fmap<TSource, TResult>
        (Triple<TSource> triple, Func<TSource, TResult> func, bool first, bool second, bool third) {

            var tmp_first = func(triple.First);
            var tmp_second = func(triple.Second);
            var tmp_third = func(triple.Third);
            var ret = new Triple<TResult>(tmp_first, tmp_second, tmp_third);
            return ret;
        }

    }

    /*       Autogenerated: Tuple.pl      */
    public static class Quad
    {

        static public T[] To_Array<T>(this Quad<T> quad) {
            var ret = new T[] { quad.First, quad.Second, quad.Third, quad.Fourth };

            return ret;

        }


        static public Quad<T1, T2, T3, T4>
        Make<T1, T2, T3, T4>(T1 first, T2 second, T3 third, T4 fourth) {

            var ret = new Quad<T1, T2, T3, T4>(first, second, third, fourth);
            return ret;

        }
        static public Mutable_Quad<T1, T2, T3, T4>
        Make_Mutable<T1, T2, T3, T4>(T1 first, T2 second, T3 third, T4 fourth) {

            var ret = new Mutable_Quad<T1, T2, T3, T4>(first, second, third, fourth);
            return ret;

        }


        static public void
        Apply<T>(Quad<T> quad, Action<T> act) {

            act(quad.First);
            act(quad.Second);
            act(quad.Third);
            act(quad.Fourth);

        }


        static public void
        Apply<T1, T2>(Quad<T1> quad1,
                      Quad<T2> quad2,
                      Action<T1, T2> act) {

            act(quad1.First, quad2.First);
            act(quad1.Second, quad2.Second);
            act(quad1.Third, quad2.Third);
            act(quad1.Third, quad2.Third);
            act(quad1.Fourth, quad2.Fourth);

        }

        static public Quad<TResult>
        Fmap<TSource, TResult>(Quad<TSource> quad, Func<TSource, TResult> func) {

            return new
            Quad<TResult>(func(quad.First),
                            func(quad.Second),
                            func(quad.Third),
                            func(quad.Fourth));

        }

        static public Quad<TResult>
        Fmap<TSource1, TSource2, TResult>(Quad<TSource1> quad1,
                                          Quad<TSource2> quad2,
                                          Func<TSource1, TSource2, TResult> func) {

            return new Quad<TResult>(func(quad1.First, quad2.First),
                                       func(quad1.Second, quad2.Second),
                                       func(quad1.Third, quad2.Third),
                                       func(quad1.Fourth, quad2.Fourth));

        }

        public static Quad<T>
        Fmap<T>
        (Quad<T> quad, Func<T, T> func, bool first, bool second, bool third, bool fourth) {

            var tmp_first = quad.First;
            var tmp_second = quad.Second;
            var tmp_third = quad.Third;
            var tmp_fourth = quad.Fourth;
            if (first) {
                tmp_first = func(tmp_first);
            }
            if (second) {
                tmp_second = func(tmp_second);
            }
            if (third) {
                tmp_third = func(tmp_third);
            }
            if (fourth) {
                tmp_fourth = func(tmp_fourth);
            }
            var ret = new Quad<T>(tmp_first, tmp_second, tmp_third, tmp_fourth);
            return ret;
        }

        public static Quad<TResult>
        Fmap<TSource, TResult>
        (Quad<TSource> quad, Func<TSource, TResult> func, bool first, bool second, bool third, bool fourth) {

            var tmp_first = func(quad.First);
            var tmp_second = func(quad.Second);
            var tmp_third = func(quad.Third);
            var tmp_fourth = func(quad.Fourth);
            var ret = new Quad<TResult>(tmp_first, tmp_second, tmp_third, tmp_fourth);
            return ret;
        }

    }

}