from layout.bbox_sort import X0_EXT_IDX, X0_IDX, X1_EXT_IDX, X1_IDX, Y0_EXT_IDX, Y0_IDX, Y1_EXT_IDX, Y1_IDX
from libs.boxbase import _is_bottom_full_overlap, _left_intersect, _right_intersect


def find_all_left_bbox_direct(this_bbox, all_bboxes) -> list:
    """
    在all_bboxes里找到所有右侧垂直方向上和this_bbox有重叠的bbox， 不用延长线
    并且要考虑两个box左右相交的情况，如果相交了，那么右侧的box就不算最左侧。
    """
    left_boxes = [box for box in all_bboxes if box[X1_IDX] <= this_bbox[X0_IDX] 
         and any([
         box[Y0_IDX] < this_bbox[Y0_IDX] < box[Y1_IDX], box[Y0_IDX] < this_bbox[Y1_IDX] < box[Y1_IDX],
         this_bbox[Y0_IDX] < box[Y0_IDX] < this_bbox[Y1_IDX], this_bbox[Y0_IDX] < box[Y1_IDX] < this_bbox[Y1_IDX],
         box[Y0_IDX]==this_bbox[Y0_IDX] and box[Y1_IDX]==this_bbox[Y1_IDX]]) or _left_intersect(box[:4], this_bbox[:4])]
        
    # 然后再过滤一下，找到水平上距离this_bbox最近的那个——x1最大的那个
    if len(left_boxes) > 0:
        left_boxes.sort(key=lambda x: x[X1_EXT_IDX] if x[X1_EXT_IDX] else x[X1_IDX], reverse=True)
        left_boxes = left_boxes[0]
    else:
        left_boxes = None
    return left_boxes

def find_all_right_bbox_direct(this_bbox, all_bboxes) -> list:
    """
    找到在this_bbox右侧且距离this_bbox距离最近的bbox.必须是直接遮挡的那种
    """
    right_bboxes = [box for box in all_bboxes if box[X0_IDX] >= this_bbox[X1_IDX] 
        and any([
        this_bbox[Y0_IDX] < box[Y0_IDX] < this_bbox[Y1_IDX], this_bbox[Y0_IDX] < box[Y1_IDX] < this_bbox[Y1_IDX],
        box[Y0_IDX] < this_bbox[Y0_IDX] < box[Y1_IDX], box[Y0_IDX] < this_bbox[Y1_IDX] < box[Y1_IDX],
        box[Y0_IDX]==this_bbox[Y0_IDX] and box[Y1_IDX]==this_bbox[Y1_IDX]]) or _right_intersect(this_bbox[:4], box[:4])]
    
    if len(right_bboxes)>0:
        right_bboxes.sort(key=lambda x: x[X0_EXT_IDX] if x[X0_EXT_IDX] else x[X0_IDX])
        right_bboxes = right_bboxes[0]
    else:
        right_bboxes = None
    return right_bboxes

def find_all_top_bbox_direct(this_bbox, all_bboxes) -> list:
    """
    找到在this_bbox上侧且距离this_bbox距离最近的bbox.必须是直接遮挡的那种
    """
    top_bboxes = [box for box in all_bboxes if box[Y1_IDX] <= this_bbox[Y0_IDX] and any([
        box[X0_IDX] < this_bbox[X0_IDX] < box[X1_IDX], box[X0_IDX] < this_bbox[X1_IDX] < box[X1_IDX],
        this_bbox[X0_IDX] < box[X0_IDX] < this_bbox[X1_IDX], this_bbox[X0_IDX] < box[X1_IDX] < this_bbox[X1_IDX],
        box[X0_IDX]==this_bbox[X0_IDX] and box[X1_IDX]==this_bbox[X1_IDX]])]
    
    if len(top_bboxes)>0:
        top_bboxes.sort(key=lambda x: x[Y1_EXT_IDX] if x[Y1_EXT_IDX] else x[Y1_IDX], reverse=True)
        top_bboxes = top_bboxes[0]
    else:
        top_bboxes = None
    return top_bboxes

def find_all_bottom_bbox_direct(this_bbox, all_bboxes) -> list:
    """
    找到在this_bbox下侧且距离this_bbox距离最近的bbox.必须是直接遮挡的那种
    """
    bottom_bboxes = [box for box in all_bboxes if box[Y0_IDX] >= this_bbox[Y1_IDX] and any([
        this_bbox[X0_IDX] < box[X0_IDX] < this_bbox[X1_IDX], this_bbox[X0_IDX] < box[X1_IDX] < this_bbox[X1_IDX],
        box[X0_IDX] < this_bbox[X0_IDX] < box[X1_IDX], box[X0_IDX] < this_bbox[X1_IDX] < box[X1_IDX],
        box[X0_IDX]==this_bbox[X0_IDX] and box[X1_IDX]==this_bbox[X1_IDX]])]
    
    if len(bottom_bboxes)>0:
        bottom_bboxes.sort(key=lambda x:  x[Y0_IDX])
        bottom_bboxes = bottom_bboxes[0]
    else:
        bottom_bboxes = None
    return bottom_bboxes

# ===================================================================================================================
def find_bottom_bbox_direct_from_right_edge(this_bbox, all_bboxes) -> list:
    """
    找到在this_bbox下侧且距离this_bbox距离最近的bbox.必须是直接遮挡的那种
    """
    bottom_bboxes = [box for box in all_bboxes if box[Y0_IDX] >= this_bbox[Y1_IDX] and any([
        this_bbox[X0_IDX] < box[X0_IDX] < this_bbox[X1_IDX], this_bbox[X0_IDX] < box[X1_IDX] < this_bbox[X1_IDX],
        box[X0_IDX] < this_bbox[X0_IDX] < box[X1_IDX], box[X0_IDX] < this_bbox[X1_IDX] < box[X1_IDX],
        box[X0_IDX]==this_bbox[X0_IDX] and box[X1_IDX]==this_bbox[X1_IDX]])]
    
    if len(bottom_bboxes)>0:
        # y0最小， X1最大的那个,也就是box上边缘最靠近this_bbox的那个,并且还最靠右
        bottom_bboxes.sort(key=lambda x: x[Y0_IDX])
        bottom_bboxes = [box for box in bottom_bboxes if box[Y0_IDX]==bottom_bboxes[0][Y0_IDX]]
        # 然后再y1相同的情况下，找到x1最大的那个
        bottom_bboxes.sort(key=lambda x: x[X1_IDX], reverse=True)
        bottom_bboxes = bottom_bboxes[0]
    else:
        bottom_bboxes = None
    return bottom_bboxes

def find_bottom_bbox_direct_from_left_edge(this_bbox, all_bboxes) -> list:
    """
    找到在this_bbox下侧且距离this_bbox距离最近的bbox.必须是直接遮挡的那种
    """
    bottom_bboxes = [box for box in all_bboxes if box[Y0_IDX] >= this_bbox[Y1_IDX] and any([
        this_bbox[X0_IDX] < box[X0_IDX] < this_bbox[X1_IDX], this_bbox[X0_IDX] < box[X1_IDX] < this_bbox[X1_IDX],
        box[X0_IDX] < this_bbox[X0_IDX] < box[X1_IDX], box[X0_IDX] < this_bbox[X1_IDX] < box[X1_IDX],
        box[X0_IDX]==this_bbox[X0_IDX] and box[X1_IDX]==this_bbox[X1_IDX]])]
    
    if len(bottom_bboxes)>0:
        # y0最小， X0最小的那个
        bottom_bboxes.sort(key=lambda x: x[Y0_IDX])
        bottom_bboxes = [box for box in bottom_bboxes if box[Y0_IDX]==bottom_bboxes[0][Y0_IDX]]
        # 然后再y0相同的情况下，找到x0最小的那个
        bottom_bboxes.sort(key=lambda x: x[X0_IDX])
        bottom_bboxes = bottom_bboxes[0]
    else:
        bottom_bboxes = None
    return bottom_bboxes

def find_top_bbox_direct_from_left_edge(this_bbox, all_bboxes) -> list:
    """
    找到在this_bbox上侧且距离this_bbox距离最近的bbox.必须是直接遮挡的那种
    """
    top_bboxes = [box for box in all_bboxes if box[Y1_IDX] <= this_bbox[Y0_IDX] and any([
        box[X0_IDX] < this_bbox[X0_IDX] < box[X1_IDX], box[X0_IDX] < this_bbox[X1_IDX] < box[X1_IDX],
        this_bbox[X0_IDX] < box[X0_IDX] < this_bbox[X1_IDX], this_bbox[X0_IDX] < box[X1_IDX] < this_bbox[X1_IDX],
        box[X0_IDX]==this_bbox[X0_IDX] and box[X1_IDX]==this_bbox[X1_IDX]])]
    
    if len(top_bboxes)>0:
        # y1最大， X0最小的那个
        top_bboxes.sort(key=lambda x: x[Y1_IDX], reverse=True)
        top_bboxes = [box for box in top_bboxes if box[Y1_IDX]==top_bboxes[0][Y1_IDX]]
        # 然后再y1相同的情况下，找到x0最小的那个
        top_bboxes.sort(key=lambda x: x[X0_IDX])
        top_bboxes = top_bboxes[0]
    else:
        top_bboxes = None
    return top_bboxes

def find_top_bbox_direct_from_right_edge(this_bbox, all_bboxes) -> list:
    """
    找到在this_bbox上侧且距离this_bbox距离最近的bbox.必须是直接遮挡的那种
    """
    top_bboxes = [box for box in all_bboxes if box[Y1_IDX] <= this_bbox[Y0_IDX] and any([
        box[X0_IDX] < this_bbox[X0_IDX] < box[X1_IDX], box[X0_IDX] < this_bbox[X1_IDX] < box[X1_IDX],
        this_bbox[X0_IDX] < box[X0_IDX] < this_bbox[X1_IDX], this_bbox[X0_IDX] < box[X1_IDX] < this_bbox[X1_IDX],
        box[X0_IDX]==this_bbox[X0_IDX] and box[X1_IDX]==this_bbox[X1_IDX]])]
    
    if len(top_bboxes)>0:
        # y1最大， X1最大的那个
        top_bboxes.sort(key=lambda x: x[Y1_IDX], reverse=True)
        top_bboxes = [box for box in top_bboxes if box[Y1_IDX]==top_bboxes[0][Y1_IDX]]
        # 然后再y1相同的情况下，找到x1最大的那个
        top_bboxes.sort(key=lambda x: x[X1_IDX], reverse=True)
        top_bboxes = top_bboxes[0]
    else:
        top_bboxes = None
    return top_bboxes
    
# ===================================================================================================================

def get_left_edge_bboxes(all_bboxes) -> list:
    """
    返回最左边的bbox
    """
    left_bboxes = [box for box in all_bboxes if find_all_left_bbox_direct(box, all_bboxes) is None]
    return left_bboxes
    
def get_right_edge_bboxes(all_bboxes) -> list:
    """
    返回最右边的bbox
    """
    right_bboxes = [box for box in all_bboxes if find_all_right_bbox_direct(box, all_bboxes) is None]
    return right_bboxes

def fix_vertical_bbox_pos(bboxes:list):
    """
    检查这批bbox在垂直方向是否有轻微的重叠，如果重叠了，就把重叠的bbox往下移动一点
    在x方向上必须一个包含或者被包含，或者完全重叠，不能只有部分重叠
    """
    bboxes.sort(key=lambda x: x[Y0_IDX]) # 从上向下排列
    for i in range(0, len(bboxes)):
        for j in range(i+1, len(bboxes)):
            if _is_bottom_full_overlap(bboxes[i][:4], bboxes[j][:4]):
                # 如果两个bbox有部分重叠，那么就把下面的bbox往下移动一点
                bboxes[j][Y0_IDX] = bboxes[i][Y1_IDX] + 2 # 2是个经验值
                break
    return bboxes
