import json

from feature import Feature, Orientation
from detection import Box, Detection

def load_features(yt_client, feature_table):
    feature_by_id = {}
    for row in yt_client.read_table(feature_table):
        feature = Feature(row)
        feature_by_id[feature.feature_id] = feature
    return feature_by_id

def load_detections(path):
    detection_by_feature_detection_id = {}
    for feature_detections in json.load(open(path))['features_objects']:
        feature_id = feature_detections['feature_id']
        orientation = Orientation.from_exif(feature_detections['orientation'])
        for detection in feature_detections['objects']:
            detection_id = detection['object_id']
            feature_detection_id = (feature_id, detection_id)
            x1 = detection['bbox'][0][0]
            y1 = detection['bbox'][0][1]
            x2 = detection['bbox'][1][0]
            y2 = detection['bbox'][1][1]
            box = Box(x1, y1, x2, y2)
            sign_type = detection['type']
            detection_by_feature_detection_id[feature_detection_id] = Detection(detection_id, box, sign_type, orientation)
    return detection_by_feature_detection_id

def load_clusters(path):
    clusters = []
    for cluster in json.load(open(path))['clusters']:
        detections = []
        for detection in cluster['objects']:
            feature_id = detection['feature_id']
            detection_id = detection['object_id']
            detections.append((feature_id, detection_id))
        clusters.append(detections)
    return clusters

def load_assignments(path):
    assignments = []
    for assignment in json.load(open(path)):
        input_values = assignment['inputValues']
        feature_id1 = input_values['feature_id1']
        detection_id1 = input_values['object_id1']
        feature_id2 = input_values['feature_id2']
        detection_id2 = input_values['object_id2']

        output_values = assignment['outputValues']
        state = output_values['state']

        assignments.append({
            'master_fdid': (feature_id1, detection_id1),
            'slave_fdid': (feature_id2, detection_id2),
            'state': state
        })
    return assignments

def select_base_feature_detection_id(cluster, feature_by_id, detection_by_feature_detection_id):
    DETECTION_SIZE_THRESHOLD = 100
    DETECTION_FEATURE_RATIO_THRESHOLD = 0.05

    detection_areas = []
    for feature_detection_id in cluster:
        area = detection_by_feature_detection_id[feature_detection_id].box.area()
        detection_areas.append({'fdid': feature_detection_id, 'area': area})
    detection_areas.sort(key=lambda x: x['area'], reverse=True)

    base_feature_detection_id = None

    for i in range(0, len(detection_areas)):
        feature_detection_id = detection_areas[i]['fdid']
        detection = detection_by_feature_detection_id[feature_detection_id]

        base_feature_detection_id = feature_detection_id

        max_size = max(detection.box.width(), detection.box.height())
        if max_size < DETECTION_SIZE_THRESHOLD:
            break

        feature_id, detection_id = feature_detection_id
        feature = feature_by_id[feature_id]

        ratio = max(
            detection.box.width() / float(feature.original_size().width),
            detection.box.height() / float(feature.original_size().height)
        )
        if ratio < DETECTION_FEATURE_RATIO_THRESHOLD:
            break
    return base_feature_detection_id
