private static ITwoThree <T> RedistributeRight(T first, T second, ITwoThree <T> left, ITwoThree <T> middle, ITwoThree <T> right)
        {
            // Case A
            if (left is TwoNode <T> && middle is TwoNode <T> )
            {
                var sm = (TwoNode <T>)middle;

                var l = left;
                var r = new ThreeNode <T>(sm.Value, second, sm.Left, sm.Right, right);

                return(new TwoNode <T>(first, l, r));
            }

            // Case B
            if (middle is ThreeNode <T> )
            {
                var sm = (ThreeNode <T>)middle;

                var l = left;
                var m = new TwoNode <T>(sm.First, sm.Left, sm.Middle);
                var r = new TwoNode <T>(second, sm.Right, right);

                return(new ThreeNode <T>(first, sm.Second, l, m, r));
            }

            // Case C
            if (left is ThreeNode <T> && middle is TwoNode <T> )
            {
                var sl = (ThreeNode <T>)left;
                var sm = (TwoNode <T>)middle;

                var l = new TwoNode <T>(sl.First, sl.Left, sl.Middle);
                var m = new TwoNode <T>(first, sl.Right, sm.Left);
                var r = new TwoNode <T>(second, sm.Right, right);

                return(new ThreeNode <T>(sl.Second, sm.Value, l, m, r));
            }

            throw new InvalidOperationException();
        }
        private static ITwoThree <T> RedistributeMiddle(T first, T second, ITwoThree <T> left, ITwoThree <T> middle, ITwoThree <T> right)
        {
            // Case A
            if (left is TwoNode <T> && right is TwoNode <T> )
            {
                var sl = (TwoNode <T>)left;

                var l = new ThreeNode <T>(sl.Value, first, sl.Left, sl.Right, middle);
                var r = right;

                return(new TwoNode <T>(second, l, r));
            }

            // Case B
            if (right is ThreeNode <T> )
            {
                var sr = (ThreeNode <T>)right;

                var l = left;
                var m = new TwoNode <T>(second, middle, sr.Left);
                var r = new TwoNode <T>(sr.Second, sr.Middle, sr.Right);

                return(new ThreeNode <T>(first, sr.First, l, m, r));
            }

            // Case C
            if (left is ThreeNode <T> && right is TwoNode <T> )
            {
                var sl = (ThreeNode <T>)left;

                var l = new TwoNode <T>(sl.First, sl.Left, sl.Middle);
                var m = new TwoNode <T>(first, sl.Right, middle);
                var r = right;

                return(new ThreeNode <T>(sl.Second, second, l, m, r));
            }

            throw new InvalidOperationException();
        }