/// <summary>子ノード郡の間に新しいPaneを挿入します</summary>
        /// <param name="idx">後輩ノードになるPaneのインデックス</param>
        public override void Add(DockPaneLayoutEngine pane, DockDirection align, int idx)
        {
            if (pane == null)
                throw new ArgumentNullException("第1引数のneighをnullにする事はできません。");
            if (pane.Owner != null)
                throw new ArgumentException("第1引数のneighは使用中です。");
            if (align == DockDirection.None)
                throw new ArgumentException("第2引数のalignをDockDirection.Noneにすることはできません。");
            if (idx < 0 || idx > Children.Count)
                throw new ArgumentOutOfRangeException("第3引数のinsertIndexが有効範囲外です。");

            if (align != DockDirection.Top)
            {
                var btm = GetChildrenOf(DockDirection.Bottom, idx).FirstOrDefault();
                if (btm != null)
                    foreach (var e in pane.GetChildrenOf(DockDirection.Bottom))
                        e.Bottom = btm.Bottom;
            }
            if (align != DockDirection.Bottom)
            {
                var top = GetChildrenOf(DockDirection.Top, idx).FirstOrDefault();
                if (top != null)
                    foreach (var e in pane.GetChildrenOf(DockDirection.Top))
                        e.Top = top.Top;
            }
            if (align != DockDirection.Left)
            {
                var rgh = GetChildrenOf(DockDirection.Right, idx).FirstOrDefault();
                if (rgh != null)
                    foreach (var e in pane.GetChildrenOf(DockDirection.Right))
                        e.Right = rgh.Right;
            }
            if (align != DockDirection.Right)
            {
                var lft = GetChildrenOf(DockDirection.Left, idx).FirstOrDefault();
                if (lft != null)
                    foreach (var e in pane.GetChildrenOf(DockDirection.Left))
                        e.Left = lft.Left;
            }
            switch (align)
            {
                case DockDirection.Top:
                    foreach (var paneInner in pane.GetChildrenOf(~align))
                        paneInner.Bottom = pane;
                    foreach (var thisInner in GetChildrenOf(align, idx))
                        thisInner.Top = pane;
                    break;
                case DockDirection.Bottom:
                    foreach (var paneInner in pane.GetChildrenOf(~align))
                        paneInner.Top = pane;
                    foreach (var thisInner in GetChildrenOf(align, idx))
                        thisInner.Bottom = pane;
                    break;
                case DockDirection.Left:
                    foreach (var paneInner in pane.GetChildrenOf(~align))
                        paneInner.Right = pane;
                    foreach (var thisInner in GetChildrenOf(align, idx))
                        thisInner.Left = pane;
                    break;
                case DockDirection.Right:
                    foreach (var paneInner in pane.GetChildrenOf(~align))
                        paneInner.Left = pane;
                    foreach (var thisInner in GetChildrenOf(align, idx))
                        thisInner.Right = pane;
                    break;
            }
            pane.Initialize(this, Owner, align);

            //base.Addを初めに呼びだしてしまうと、Childrenが更新されるために
            //GetChildrenOfの挙動に以上が生じる。そのため、base.Addは最後に呼ぶ
            base.Add(pane, align, idx);
        }
        public override void Remove(DockPaneLayoutEngine pane)
        {
            if (!Children.Contains(pane))
                throw new ArgumentException("引数paneはこの要素の子要素ではありません。");

            var paneRmvAlign = pane.GetSucceedingDireWhenDeletingPane();

            #region Debug時用状態チェックコード
#if DEBUG
            if (pane.Align == DockDirection.None)
            {
                System.Diagnostics.Debug.Fail(
                    "StatusError", "自身の挿入方向が分かりません。");
                if (System.Diagnostics.Debugger.IsAttached)
                    System.Diagnostics.Debugger.Break();
            }
            if (paneRmvAlign == DockDirection.None)
            {
                System.Diagnostics.Debug.Fail(
                    "StatusError", "自身を消去した後の領域を受け継ぐノードが存在しません。");
                if (System.Diagnostics.Debugger.IsAttached)
                    System.Diagnostics.Debugger.Break();
            }
#endif
            #endregion

            if (pane.Children.Count > 0)
            {
                var newParent = pane.Children.Last();
                //newParent.Align = pane.Align;
                switch (pane.Align)
                {
                    case DockDirection.Top:
                        foreach (var p in pane.GetChildrenOf(~pane.Align))
                            p.Bottom = newParent;
                        foreach (var p in GetChildrenOf(pane.Align, Children.IndexOf(pane) + 1))
                            p.Top = newParent;
                        break;
                    case DockDirection.Bottom:
                        foreach (var p in pane.GetChildrenOf(~pane.Align))
                            p.Top = newParent;
                        foreach (var p in GetChildrenOf(pane.Align, Children.IndexOf(pane) + 1))
                            p.Bottom = newParent;
                        break;
                    case DockDirection.Left:
                        foreach (var p in pane.GetChildrenOf(~pane.Align))
                            p.Right = newParent;
                        foreach (var p in GetChildrenOf(pane.Align, Children.IndexOf(pane) + 1))
                            p.Left = newParent;
                        break;
                    case DockDirection.Right:
                        foreach (var p in pane.GetChildrenOf(~pane.Align))
                            p.Left = newParent;
                        foreach (var p in GetChildrenOf(pane.Align, Children.IndexOf(pane) + 1))
                            p.Right = newParent;
                        break;
                }
                //代替用子要素が持つ、自身と消去要素(paneの事)が接触している部分の
                //SplitPane情報を消去要素が同じ方向に持っているSplitPane情報に差し替え
                switch (paneRmvAlign)
                {
                    case DockDirection.Top:
                        newParent.Bottom = pane.Bottom;
                        break;
                    case DockDirection.Bottom:
                        newParent.Top = pane.Top;
                        break;
                    case DockDirection.Left:
                        newParent.Right = pane.Right;
                        break;
                    case DockDirection.Right:
                        newParent.Left = pane.Left;
                        break;
                }
            }
            else
            {
                //最初要素にも新親要素にもならない独身要素が消える際には削除方向にあるpaneの
                //splitPane情報の自身を参照する方向を自身をまたいだ方向にあるpaneに差し替える
                foreach (var pLayoutEngine in GetChildrenOf(paneRmvAlign, Children.IndexOf(pane) + 1))
                    switch (paneRmvAlign)
                    {
                        case DockDirection.Top:
                            pLayoutEngine.Bottom = pane.Bottom;
                            break;
                        case DockDirection.Bottom:
                            pLayoutEngine.Top = pane.Top;
                            break;
                        case DockDirection.Left:
                            pLayoutEngine.Right = pane.Right;
                            break;
                        case DockDirection.Right:
                            pLayoutEngine.Left = pane.Left;
                            break;
                    }
            }
            base.Remove(pane);
        }
        public void GetChildrenOfTest()
        {
            var target = new DockPaneLayoutEngine(new DockPaneBase());
            var lv1A = new DockPaneLayoutEngine(new DockPaneBase());
            var lv1B = new DockPaneLayoutEngine(new DockPaneBase());
            var lv1C = new DockPaneLayoutEngine(new DockPaneBase());
            var lv2A = new DockPaneLayoutEngine(new DockPaneBase());

            target.Add(lv1A, DockDirection.Top);
            target.Add(lv1B, DockDirection.Left);
            target.Add(lv1C, DockDirection.Top);
            lv1C.Add(lv2A, DockDirection.Right);

            //自ノードを含まない
            var testA = target.GetChildrenOf(DockDirection.Left, deep: false).ToArray();
            Assert.IsTrue(testA.Contains(lv1A));
            Assert.IsTrue(testA.Contains(lv1B));
            Assert.AreEqual(2, testA.Length);

            //自ノードを含む
            var testB = target.GetChildrenOf(DockDirection.Right, deep: false).ToArray();
            Assert.IsTrue(testB.Contains(lv1A));
            Assert.IsTrue(testB.Contains(lv1C));
            Assert.IsTrue(testB.Contains(target));
            Assert.AreEqual(3, testB.Length);

            //自ノードを含み、かつ実質接触要素
            var testC = target.GetChildrenOf(DockDirection.Right, deep: true).ToArray();
            Assert.IsTrue(testC.Contains(target));
            Assert.IsTrue(testC.Contains(lv1A));
            Assert.IsTrue(testC.Contains(lv2A));
            Assert.AreEqual(3, testC.Length);

            //自ノードを含み、スキップ2使用(lv1Cから探索)
            var testD = target.GetChildrenOf(DockDirection.Right, 2).ToArray();
            Assert.IsTrue(testD.Contains(target));
            Assert.IsTrue(testD.Contains(lv2A));
            Assert.AreEqual(2, testD.Length);
        }
        public void AddTest()
        {
            var target = new DockPaneLayoutEngine(new DockPaneBase());

            //AddTest
            //DockPaneNeighs
            var tmp = new[]
                {
                    new { LayoutEngine = new DockPaneLayoutEngine(new DockPaneBase()), Align = DockDirection.Left, Index = 0, Count = 1 },
                    new { LayoutEngine = new DockPaneLayoutEngine(new DockPaneBase()), Align = DockDirection.Top, Index = 1, Count = 2 },
                    new { LayoutEngine = new DockPaneLayoutEngine(new DockPaneBase()), Align = DockDirection.Right, Index = 2, Count = 3 },
                    new { LayoutEngine = new DockPaneLayoutEngine(new DockPaneBase()), Align = DockDirection.Bottom, Index = 3, Count = 4 },
                    new { LayoutEngine = new DockPaneLayoutEngine(new DockPaneBase()), Align = DockDirection.Right, Index = 3, Count = 5 },
                }
                .ToArray();
            //TestDatas
            var testDtIdx = 0;
            var testDt = new[]
                {
                    new { Top = (DockPaneLayoutEngine)null, Bottom = (DockPaneLayoutEngine)null, Left = (DockPaneLayoutEngine)null, Right = tmp[0].LayoutEngine },
                    new { Top = (DockPaneLayoutEngine)null, Bottom = tmp[1].LayoutEngine, Left = tmp[0].LayoutEngine, Right = (DockPaneLayoutEngine)null },
                    new { Top = tmp[1].LayoutEngine, Bottom = (DockPaneLayoutEngine)null, Left = tmp[2].LayoutEngine, Right = (DockPaneLayoutEngine)null },
                    new { Top = tmp[3].LayoutEngine, Bottom = (DockPaneLayoutEngine)null, Left = tmp[0].LayoutEngine, Right = tmp[2].LayoutEngine },
                    new { Top = tmp[1].LayoutEngine, Bottom = (DockPaneLayoutEngine)null, Left = tmp[4].LayoutEngine, Right = tmp[2].LayoutEngine },
                };
            //MargeCollection
            var children = tmp
                .Select(n => new
                {
                    Align = n.Align,
                    LayoutEngine = n.LayoutEngine,
                    TestData = testDt[testDtIdx++],
                    Index = n.Index,
                    Count = n.Count,
                })
                .ToArray();
            foreach (var item in children)
            {
                target.Add(item.LayoutEngine, item.Align, item.Index);

                Assert.AreEqual(target, item.LayoutEngine.Parent);
                Assert.AreEqual(item.Align, item.LayoutEngine.Align);
                Assert.AreEqual(target, item.LayoutEngine.Parent);
                Assert.IsNull(item.LayoutEngine.Owner);
                Assert.AreEqual(item.Index, target.Children.IndexOf(item.LayoutEngine));
                Assert.AreEqual(item.Count, target.Children.Count);

                Assert.AreEqual(item.TestData.Top, item.LayoutEngine.Top);
                Assert.AreEqual(item.TestData.Bottom, item.LayoutEngine.Bottom);
                Assert.AreEqual(item.TestData.Left, item.LayoutEngine.Left);
                Assert.AreEqual(item.TestData.Right, item.LayoutEngine.Right);
                switch (item.Align)
                {
                    case DockDirection.Top:
                        Assert.AreEqual(0,
                            target.GetChildrenOf(item.Align, target.Children.IndexOf(item.LayoutEngine) + 1)
                            .Select(n => n.Top)
                            .Where(n => n != item.LayoutEngine)
                            .Count());
                        break;
                    case DockDirection.Bottom:
                        Assert.AreEqual(0,
                            target.GetChildrenOf(item.Align, target.Children.IndexOf(item.LayoutEngine) + 1)
                            .Select(n => n.Bottom)
                            .Where(n => n != item.LayoutEngine)
                            .Count());
                        break;
                    case DockDirection.Left:
                        Assert.AreEqual(0,
                            target.GetChildrenOf(item.Align, target.Children.IndexOf(item.LayoutEngine) + 1)
                            .Select(n => n.Left)
                            .Where(n => n != item.LayoutEngine)
                            .Count());
                        break;
                    case DockDirection.Right:
                        Assert.AreEqual(0,
                            target.GetChildrenOf(item.Align, target.Children.IndexOf(item.LayoutEngine) + 1)
                            .Select(n => n.Right)
                            .Where(n => n != item.LayoutEngine)
                            .Count());
                        break;
                }
            }

            //InsertTest
            var lyout = new DockPaneLayoutEngine(new DockPaneBase());
            target.Add(lyout, DockDirection.Left, 3);
            Assert.AreEqual(tmp[1].LayoutEngine, lyout.Top);
            Assert.AreEqual(tmp[0].LayoutEngine, lyout.Left);
            Assert.AreEqual(lyout, lyout.Right);
            Assert.AreEqual(null, lyout.Bottom);
            Assert.AreEqual(target.Left, lyout);
            Assert.AreEqual(tmp[3].LayoutEngine.Left, lyout);
            Assert.AreEqual(target, lyout.Parent);

            var bay = new DockBayLayoutEngine(new DockBayBase());
            bay.Add(target, DockDirection.Top);
            foreach (var item in children)
                Assert.AreEqual(bay, item.LayoutEngine.Owner);

            //不正引数用
            var exCnter = 0;
            try { target.Add((DockPaneLayoutEngine)null, DockDirection.Top, 0); }
            catch (ArgumentNullException) { exCnter++; }
            catch { }

            try { target.Add(children[0].LayoutEngine, DockDirection.Bottom, 0); }
            catch (ArgumentException) { exCnter++; }
            catch { }

            try { target.Add(new DockPaneLayoutEngine(new DockPaneBase()), DockDirection.None, 0); }
            catch (ArgumentException) { exCnter++; }
            catch { }

            try { target.Add(new DockPaneLayoutEngine(new DockPaneBase()), DockDirection.Left, -1); }
            catch (ArgumentException) { exCnter++; }
            catch { }
            Assert.AreEqual(4, exCnter, "無効な引数に対して適切な対処が取れていません。");
        }
        public override void Remove(DockPaneLayoutEngine pane)
        {
            if (!Children.Contains(pane))
                throw new ArgumentException("引数paneはこの要素の子要素ではありません。");

            var paneRmvAlign = pane.GetSucceedingDireWhenDeletingPane();

            #region Debug時用状態チェックコード
#if DEBUG
            if (pane.Align == DockDirection.None)
            {
                System.Diagnostics.Debug.Fail(
                    "StatusError", "自身の挿入方向が分かりません。");
                if (System.Diagnostics.Debugger.IsAttached)
                    System.Diagnostics.Debugger.Break();
            }
            if (paneRmvAlign == DockDirection.None)
            {
                System.Diagnostics.Debug.Fail(
                    "StatusError", "自身を消去した後の領域を受け継ぐノードが存在しません。");
                if (System.Diagnostics.Debugger.IsAttached)
                    System.Diagnostics.Debugger.Break();
            }
#endif
            #endregion

            if (pane.Children.Count > 0)
            {
                //子要素を自身の代替要素とする場合、各方向のSplitPane情報の更新が必要。
                //よって自身をSplitPaneとして参照する要素のSplitPaneを子要素へ更新する。
                var newParent = pane.Children.Last();
                switch (pane.Align)
                {
                    case DockDirection.Top:
                        foreach (var p in pane.GetChildrenOf(~pane.Align))
                            p.Bottom = newParent;

                        //BayではChildrenの順番がPaneの逆であると同時に要素が1多い。その
                        //ため、Childrenの要素数からindexを引く事でPane時と同じ順番にし、
                        //Pane.Removeでやってるidx+1はしない事で同じ入力をする
                        foreach (var p in GetChildrenOf(pane.Align, Children.Count - Children.IndexOf(pane)))
                            p.Top = newParent;
                        break;
                    case DockDirection.Bottom:
                        foreach (var p in pane.GetChildrenOf(~pane.Align))
                            p.Top = newParent;

                        //※case DockDirection.Topと同様の注意事項
                        foreach (var p in GetChildrenOf(pane.Align, Children.Count - Children.IndexOf(pane)))
                            p.Bottom = newParent;
                        break;
                    case DockDirection.Left:
                        foreach (var p in pane.GetChildrenOf(~pane.Align))
                            p.Right = newParent;

                        //※case DockDirection.Topと同様の注意事項
                        foreach (var p in GetChildrenOf(pane.Align, Children.Count - Children.IndexOf(pane)))
                            p.Left = newParent;
                        break;
                    case DockDirection.Right:
                        foreach (var p in pane.GetChildrenOf(~pane.Align))
                            p.Left = newParent;

                        //※case DockDirection.Topと同様の注意事項
                        foreach (var p in GetChildrenOf(pane.Align, Children.Count - Children.IndexOf(pane)))
                            p.Right = newParent;
                        break;
                }
                //代替用子要素が持つ、自身と消去要素(paneの事)が接触している部分の
                //SplitPane情報を消去要素が同じ方向に持っているSplitPane情報に差し替え
                switch (paneRmvAlign)
                {
                    case DockDirection.Top:
                        newParent.Bottom = pane.Bottom;
                        break;
                    case DockDirection.Bottom:
                        newParent.Top = pane.Top;
                        break;
                    case DockDirection.Left:
                        newParent.Right = pane.Right;
                        break;
                    case DockDirection.Right:
                        newParent.Left = pane.Left;
                        break;
                }
            }
            else if (Children.IndexOf(pane) == 0 && Children.Count > 1)
            {
                //Bayで最初に挿入した子要素は全方向に広がり、Splitterを持たない。そのため、
                //他要素にSplitPaneで参照されることはない。
                //この条件によってBayの最初要素が削除される時に代替要素となる2番目は他要素
                //からのSplitPane参照を消す必要がある。
                var newFillPane = Children[1];
                foreach (var item in newFillPane.GetChildrenOf(~newFillPane.Align))
                    switch (newFillPane.Align)
                    {
                        case DockDirection.Top:
                            item.Bottom = null;
                            break;
                        case DockDirection.Bottom:
                            item.Top = null;
                            break;
                        case DockDirection.Left:
                            item.Right = null;
                            break;
                        case DockDirection.Right:
                            item.Left = null;
                            break;
                    }
            }
            else
            {
                //最初要素にも新親要素にもならない独身要素が消える際には削除方向にあるpaneの
                //splitPane情報の自身を参照する方向を自身をまたいだ方向にあるpaneに差し替える
                foreach (var pLayoutEngine in GetChildrenOf(paneRmvAlign, Children.Count - Children.IndexOf(pane)))
                    switch (paneRmvAlign)
                    {
                        case DockDirection.Top:
                            pLayoutEngine.Bottom = pane.Bottom;
                            break;
                        case DockDirection.Bottom:
                            pLayoutEngine.Top = pane.Top;
                            break;
                        case DockDirection.Left:
                            pLayoutEngine.Right = pane.Right;
                            break;
                        case DockDirection.Right:
                            pLayoutEngine.Left = pane.Left;
                            break;
                    }
            }

            base.Remove(pane);
        }