""" Copyright (c) 2020 Daniel Bolya, based on https://github.com/dbolya/tide """

import os
import sys

import numpy as np


def mean(arr: list):
    if len(arr) == 0:
        return 0
    return sum(arr) / len(arr)


def find_first(arr: np.array) -> int:
    """Finds the index of the first instance of true in a vector or None if not found."""
    if len(arr) == 0:
        return None
    idx = arr.argmax()

    # Numpy argmax will return 0 if no True is found
    if idx == 0 and not arr[0]:
        return None

    return idx


def isiterable(x):
    try:
        iter(x)
        return True
    except:
        return False


def recursive_sum(x):
    if isinstance(x, dict):
        return sum([recursive_sum(v) for v in x.values()])
    elif isiterable(x):
        return sum([recursive_sum(v) for v in x])
    else:
        return x


def apply_messy(x: list, func):
    return [([func(y) for y in e] if isiterable(e) else func(e)) for e in x]


def apply_messy2(x: list, y: list, func):
    return [
        [func(i, j) for i, j in zip(a, b)] if isiterable(a) else func(a, b)
        for a, b in zip(x, y)
    ]


def multi_len(x):
    try:
        return len(x)
    except TypeError:
        return 1


def unzip(l):
    return map(list, zip(*l))


def points(bbox):
    bbox = [int(x) for x in bbox]
    return (bbox[0], bbox[1]), (bbox[0] + bbox[2], bbox[1] + bbox[3])


def nonepack(t):
    if t is None:
        return None, None
    else:
        return t


class HiddenPrints:
    """From https://stackoverflow.com/questions/8391411/suppress-calls-to-print-python"""

    def __enter__(self):
        self._original_stdout = sys.stdout
        sys.stdout = open(os.devnull, "w")

    def __exit__(self, exc_type, exc_val, exc_tb):
        sys.stdout.close()
        sys.stdout = self._original_stdout


def polyToBox(poly: list):
    """Converts a polygon in COCO lists of lists format to a bounding box in [x, y, w, h]."""

    xmin = 1e10
    xmax = -1e10
    ymin = 1e10
    ymax = -1e10

    for poly_comp in poly:
        for i in range(len(poly_comp) // 2):
            x = poly_comp[2 * i + 0]
            y = poly_comp[2 * i + 1]

            xmin = min(x, xmin)
            xmax = max(x, xmax)
            ymin = min(y, ymin)
            ymax = max(y, ymax)

    return [xmin, ymin, (xmax - xmin), (ymax - ymin)]
