public R_Tree(CacheManager cache)
 {
     Cache = cache;
     Leaf rootNode = new Leaf(Address.Empty);
     root = rootNode.Address;
     Cache.WritePageData(rootNode);
     TreeHeight = 1;
     Cache.FlushCache();
 }
 protected virtual PageData LookupPageData(Address address)
 {
     PageData data;
     Page page = LookupPage(address);
     Byte type = page.Data[0], childType = page.Data[1];
     if (type == (Byte)PageDataType.Node || type == (Byte)PageDataType.Leaf)
         if (childType == (Byte)NodeChildType.Leaf)
             data = new Node(address, typeof(Leaf), page.Data);
         else if (childType == (Byte)NodeChildType.Node)
             data = new Node(address, typeof(Node), page.Data);
         else if (childType == (Byte)NodeChildType.Record)
             data = new Leaf(address, page.Data);
         else
             throw new Exception("Not a node");
     else if (type == (Byte)PageDataType.Record)
         data = new Record(address, page.Data);
     else if (type == (Byte)PageDataType.IndexUnitSector)
         data = new Sector(address, page.Data);
     else
         throw new Exception("Not valid Page Data");
     CacheOverflowCheck();
     return data;
 }
        protected override List<Node> Split(Node nodeToBeSplit)
        {
            //
            //Determine Axis
            //

            //Sort each axis by upper and lower corners
            List<NodeEntry> xLowerSorted = new List<NodeEntry>(nodeToBeSplit.NodeEntries),
                xUpperSorted = new List<NodeEntry>(nodeToBeSplit.NodeEntries),
                yLowerSorted = new List<NodeEntry>(nodeToBeSplit.NodeEntries),
                yUpperSorted = new List<NodeEntry>(nodeToBeSplit.NodeEntries);

            xLowerSorted.Sort(new NodeEntryLowerAxisComparerX());
            xUpperSorted.Sort(new NodeEntryUpperAxisComparerX());
            yLowerSorted.Sort(new NodeEntryLowerAxisComparerY());
            yUpperSorted.Sort(new NodeEntryUpperAxisComparerY());

            //Generate Distributions
            List<Pair<Node, Node>> xLowerDistributions = new List<Pair<Node, Node>>(),
                xUpperDistributions = new List<Pair<Node, Node>>(),
                yLowerDistributions = new List<Pair<Node, Node>>(),
                yUpperDistributions = new List<Pair<Node, Node>>();

            Dictionary<List<NodeEntry>, List<Pair<Node, Node>>> axii =
                new Dictionary<List<NodeEntry>, List<Pair<Node, Node>>>();

            axii.Add(xLowerSorted, xLowerDistributions);
            axii.Add(xUpperSorted, xUpperDistributions);
            axii.Add(yLowerSorted, yLowerDistributions);
            axii.Add(yUpperSorted, yUpperDistributions);

            foreach (KeyValuePair<List<NodeEntry>, List<Pair<Node, Node>>> axis in axii)
                for (int i = 0; i < Constants.MAXIMUM_ENTRIES_PER_NODE - 2 * Constants.MINIMUM_ENTRIES_PER_NODE + 2; i++)
                {
                    Node group1, group2;
                    if (nodeToBeSplit is Leaf)
                    {
                        group1 = new Leaf(nodeToBeSplit.Parent);
                        group2 = new Leaf(nodeToBeSplit.Parent);
                    }
                    else
                    {
                        group1 = new Node(nodeToBeSplit.Parent, nodeToBeSplit.ChildType);
                        group2 = new Node(nodeToBeSplit.Parent, nodeToBeSplit.ChildType);
                    }
                    foreach (NodeEntry entry in axis.Key.GetRange(0, Constants.MINIMUM_ENTRIES_PER_NODE+ i))
                        group1.AddNodeEntry(entry);
                    foreach (NodeEntry entry in axis.Key.GetRange(Constants.MINIMUM_ENTRIES_PER_NODE + i, axis.Key.Count - (Constants.MINIMUM_ENTRIES_PER_NODE+ i)))
                        group2.AddNodeEntry(entry);
                    axis.Value.Add(new Pair<Node, Node>(group1, group2));
                }

            //Sum margins
            Single xLowerMarginSum = 0, xUpperMarginSum = 0, yLowerMarginSum = 0, yUpperMarginSum = 0;
            foreach (Pair<Node, Node> distribution in xLowerDistributions)
                xLowerMarginSum += GetMargin(distribution.Value1, distribution.Value2);
            foreach (Pair<Node, Node> distribution in xUpperDistributions)
                xUpperMarginSum += GetMargin(distribution.Value1, distribution.Value2);
            foreach (Pair<Node, Node> distribution in yLowerDistributions)
                yLowerMarginSum += GetMargin(distribution.Value1, distribution.Value2);
            foreach (Pair<Node, Node> distribution in yUpperDistributions)
                yUpperMarginSum += GetMargin(distribution.Value1, distribution.Value2);

            //Choose Axis
            List<Pair<Node, Node>> chosenAxis;
            if (xLowerMarginSum <= xUpperMarginSum && xLowerMarginSum <= yLowerMarginSum && xLowerMarginSum <= yUpperMarginSum)
                chosenAxis = xLowerDistributions;
            else if (xUpperMarginSum <= xLowerMarginSum && xUpperMarginSum <= yLowerMarginSum && xUpperMarginSum <= yUpperMarginSum)
                chosenAxis = xUpperDistributions;
            else if (yLowerMarginSum <= xUpperMarginSum && yLowerMarginSum <= xLowerMarginSum && yLowerMarginSum <= yUpperMarginSum)
                chosenAxis = yLowerDistributions;
            else
                chosenAxis = yUpperDistributions;

            //
            //Determine Distribution
            //

            Pair<Node, Node> chosenDistribution = chosenAxis[0];
            Single minimumOverlapArea = GetOverlap(chosenDistribution.Value1, chosenDistribution.Value2);
            foreach (Pair<Node, Node> distribution in chosenAxis)
            {
                Single overlapArea = GetOverlap(distribution.Value1, distribution.Value2);
                if ((overlapArea == minimumOverlapArea &&
                    GetFutureSize(distribution.Value1.CalculateMinimumBoundingBox(), distribution.Value2.CalculateMinimumBoundingBox()) <
                    GetFutureSize(chosenDistribution.Value1.CalculateMinimumBoundingBox(), chosenDistribution.Value2.CalculateMinimumBoundingBox())
                    ) ||
                    overlapArea < minimumOverlapArea)
                {
                    chosenDistribution = distribution;
                    minimumOverlapArea = overlapArea;
                }
            }

            //
            //Distribute
            //

            List<Node> newNodes = new List<Node>();
            newNodes.Add(chosenDistribution.Value1);
            newNodes.Add(chosenDistribution.Value2);
            foreach (Node newNode in newNodes)
            {
                if (!(newNode is Leaf))
                    foreach (NodeEntry entry in newNode.NodeEntries)
                    {
                        Node child = Cache.LookupNode(entry.Child);
                        child.Parent = newNode.Address;
                        Cache.WritePageData(child);
                    }
                Cache.WritePageData(newNode);
            }
            return newNodes;
        }
        protected virtual List<Node> Split(Node nodeToBeSplit)
        {
            List<NodeEntry> entries = new List<NodeEntry>(nodeToBeSplit.NodeEntries);
            List<NodeEntry> seeds = PickSeeds(entries);
            entries.Remove(seeds[0]);
            entries.Remove(seeds[1]);
            Node node1, node2;
            if (nodeToBeSplit is Leaf)
            {
                node1 = new Leaf(nodeToBeSplit.Parent);
                node2 = new Leaf(nodeToBeSplit.Parent);
            }
            else
            {
                node1 = new Node(nodeToBeSplit.Parent, nodeToBeSplit.ChildType);
                node2 = new Node(nodeToBeSplit.Parent, nodeToBeSplit.ChildType);
            }
            node1.AddNodeEntry(seeds[0]);
            node2.AddNodeEntry(seeds[1]);
            if (!(seeds[0] is LeafEntry))
            {
                Node child = Cache.LookupNode(seeds[0].Child);
                child.Parent = node1.Address;
                Cache.WritePageData(child);
            }
            if (!(seeds[1] is LeafEntry))
            {
                Node child = Cache.LookupNode(seeds[1].Child);
                child.Parent = node2.Address;
                Cache.WritePageData(child);
            }
            while (entries.Count > 0)
            {
                if (node1.NodeEntries.Count + entries.Count == Constants.MINIMUM_ENTRIES_PER_NODE)
                {
                    foreach (NodeEntry entry in entries)
                    {
                        node1.AddNodeEntry(entry);
                        if(!(entry is LeafEntry))
                        {
                            Node child = Cache.LookupNode(entry.Child);
                            child.Parent = node1.Address;
                            Cache.WritePageData(child);
                        }
                    }
                    break;
                }
                else if (node2.NodeEntries.Count + entries.Count == Constants.MINIMUM_ENTRIES_PER_NODE)
                {
                    foreach (NodeEntry entry in entries)
                    {
                        node2.AddNodeEntry(entry);
                        if (!(entry is LeafEntry))
                        {
                            Node child = Cache.LookupNode(entry.Child);
                            child.Parent = node2.Address;
                            Cache.WritePageData(child);
                        }
                    }
                    break;
                }
                MinimumBoundingBox minimumBoundingBox1 = node1.CalculateMinimumBoundingBox(),
                minimumBoundingBox2 = node2.CalculateMinimumBoundingBox();
                NodeEntry nextEntry = PickNext(entries, minimumBoundingBox1, minimumBoundingBox2);
                entries.Remove(nextEntry);
                Node nodeToEnter;
                if (GetFutureSize(nextEntry.MinimumBoundingBox, minimumBoundingBox1) ==
                    GetFutureSize(nextEntry.MinimumBoundingBox, minimumBoundingBox2))
                {
                    if (minimumBoundingBox1.GetArea() == minimumBoundingBox2.GetArea())
                        if (node1.NodeEntries.Count <= node2.NodeEntries.Count)
                            nodeToEnter = node1;
                        else
                            nodeToEnter = node2;
                    else if (minimumBoundingBox1.GetArea() < minimumBoundingBox2.GetArea())
                        nodeToEnter = node1;
                    else
                        nodeToEnter = node2;
                }
                else if (GetFutureSize(nextEntry.MinimumBoundingBox, minimumBoundingBox1) <
                    GetFutureSize(nextEntry.MinimumBoundingBox, minimumBoundingBox2))
                    nodeToEnter = node1;
                else
                    nodeToEnter = node2;
                nodeToEnter.AddNodeEntry(nextEntry);

                if (!(nextEntry is LeafEntry))
                {
                    Node child = Cache.LookupNode(nextEntry.Child);
                    child.Parent = nodeToEnter.Address;
                    Cache.WritePageData(child);
                }
            }
            List<Node> newNodes = new List<Node>();
            newNodes.Add(node1);
            newNodes.Add(node2);
            return newNodes;
        }
 protected virtual void Insert(Record record, Leaf leaf)
 {
     leaf.AddNodeEntry(new LeafEntry(record.BoundingBox, record.Address));
 }