''' mbinary
#########################################################################
# File : intervalTree.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-11-18  10:48
# Description:
#########################################################################
'''
from random import randint, shuffle
from redBlackTree import redBlackTree

from functools import total_ordering


@total_ordering
class node:
    def __init__(self, low, high, left=None, right=None, isBlack=False):
        self.val = low   # self.val is the low
        self.high = high
        self.max = high
        self.left = left
        self.right = right
        self.parent = None
        self.isBlack = isBlack

    def __lt__(self, nd):
        return self.val < nd.val

    def __eq__(self, nd):
        return nd is not None and self.val == nd.val

    def setChild(self, nd, isLeft=True):
        if isLeft:
            self.left = nd
        else:
            self.right = nd
        if nd is not None:
            nd.parent = self

    def getChild(self, isLeft):
        if isLeft:
            return self.left
        else:
            return self.right

    def __bool__(self):
        return self.val is not None

    def __str__(self):
        color = 'B' if self.isBlack else 'R'
        return f'{color}[{self.val},{self.high}]-{self.max}'

    def __repr__(self):
        return f'intervalNode({self.val},{self.high},{self.max},isBlack={self.isBlack})'

    def overlap(self, low, high):
        return self.val <= high and self.high >= low

    def setMax(self):
        l = 0 if self.left is None else self.left.max
        r = 0 if self.right is None else self.right.max
        self.max = max(self.high, l, r)
        return self.max


class intervalTree(redBlackTree):
    def search(self, low, high):
        nd = self.root
        while nd is not None and not nd.overlap(low, high):
            if nd.left is not None and nd.left.max >= low:
                nd = nd.left
            else:
                nd = nd.right
        return nd

    def insert(self, nd):
        super(intervalTree, self).insert(nd)
        while nd is not None:
            nd.setMax()
            nd = nd.parent

    def delete(self, val):
        nd = self.find(val)
        if nd is not None:
            nd.max = 0
            tmp = nd.parent
            while tmp is not None:
                tmp.setMax()
                tmp = tmp.parent
            super(intervalTree, self).delete(val)

    def rotate(self, prt, chd):
        '''rotate prt, and return new prt, namyly the original chd'''
        super(intervalTree, self).rotate(prt, chd)
        prt.setMax()
        chd.setMax()

    def copyNode(self, src, des):
        des.val = src.val
        des.high = src.high
        des.setMax()


def genNum(n=10, upper=10):
    nums = {}
    for i in range(n):
        while 1:
            d = randint(0, 100)
            if d not in nums:
                nums[d] = (d, randint(d, d+upper))
                break
    return nums.values()


def buildTree(n=10, nums=None, visitor=None):
    #if nums is None or nums ==[]: nums = genNum(n)
    tree = intervalTree()
    print(f'build a red-black tree using {nums}')
    for i in nums:
        tree.insert(node(*i))
        if visitor:
            visitor(tree, i)
    return tree, nums


def testInsert(nums=None):
    def visitor(t, val):
        print('inserting', val)
        print(t)
    tree, nums = buildTree(visitor=visitor, nums=nums)
    print('-'*5 + 'in-order visit' + '-'*5)
    for i, j in enumerate(tree.sort()):
        print(f'{i+1}: {j}')
    return tree


def testSuc(nums=None):
    tree, nums = buildTree(nums=nums)
    for i in tree.sort():
        print(f'{i}\'s suc is {tree.getSuccessor(i)}')


def testDelete(nums=None):
    tree, nums = buildTree(nums=nums)
    print(tree)
    for i in nums:
        print(f'deleting {i}')
        tree.delete(i[0])
        print(tree)
    return tree


if __name__ == '__main__':
    lst = [(0, 3), (5, 8), (6, 10), (26, 26), (25, 30),
           (8, 9), (19, 20), (15, 23), (16, 21), (17, 19)]
    #lst = None
    # testSuc(lst)
    tree = testInsert(lst)
    #tree,_= buildTree(lst)
    while 1:
        a = int(input('low:'))
        b = int(input('high:'))
        res = tree.search(a, b)
        print(res)
