"""Module for calculating annotated region metrics from ISI data"""
import numpy as np
import logging

# These scaling factors are derived from experimental geometry using
# screen width 52.0 cm, screen height 32.0 cm (16:10 24 inch monitor)
# mouse 10.0 cm from center of monitor
ALTITUDE_SCALE = 0.322
AZIMUTH_SCALE = 0.383


def eccentricity(az, alt, az_center, alt_center):
    """Compute eccentricity
    
    Parameters
    ----------
    az : numpy.ndarray
        Azimuth retinotopic map
    alt : numpy.ndarray
        Altitude retinotopic map
    az_center : float
        Azimuth value to use as center of eccentricity map
    alt_center : float
        Altitude value to use as center of eccentricity map

    Returns
    -------
    numpy.ndarray
        Eccentricity map
    """
    daz = az - az_center
    dalt = alt - alt_center
    ecc = np.arctan(np.sqrt(np.square(np.tan(dalt)) +
                            np.square(np.tan(daz))/np.square(np.cos(dalt))))
    return ecc


def retinotopy_metric(mask, isi_map):
    """Compute retinotopic metrics for a responding area
    
    Parameters
    ----------
    mask : numpy.ndarray
        Mask representing the area over which to calculate metrics
    isi_map : numpy.ndarray
        Retinotopic map

    Returns
    -------
    (float, float, float, float) tuple
        min, max, range, bias of retinotopic map over masked region
    """
    ind = np.where( mask > 0 )
    vals = isi_map[ind]
    maxv = np.degrees(np.max(vals))
    minv = np.degrees(np.min(vals))
    ret_range = float(maxv - minv)
    ret_bias = float(abs(minv + maxv))
    return float(minv), float(maxv), ret_range, ret_bias


def create_region_mask(image_shape, x, y, width, height, mask):
    """Create mask for region on retinotopic map

    Parameters
    ----------
    image_shape : tuple
        (height, width) of retinotopic map
    x : int
        x offset of region mask within retinotopic map
    y : int
        y offset of region mask within retinotopic map
    width : int
        width of region mask
    height : int
        height of region mask
    mask : list
        region mask as a list of lists
    
    Returns
    -------
    numpy.ndarray
        Region mask
    """
    bb = np.zeros((height,width), dtype=np.uint8)
    bb[np.asarray(mask)] = 1
    region_mask = np.zeros(image_shape, dtype=np.uint8)
    region_mask[y:y + height,x:x + width] = bb
    return region_mask


def get_metrics(altitude_phase, azimuth_phase, x=None, y=None, width=None,
                height=None, mask=None, altitude_scale=ALTITUDE_SCALE,
                azimuth_scale=AZIMUTH_SCALE):
    """Calculate annotated region metrics"""
    altitude = altitude_phase * altitude_scale
    azimuth = azimuth_phase * azimuth_scale

    eccentricity_ret_zero = np.degrees(
        eccentricity(azimuth, altitude, 0.0, 0.0))

    result = {}

    region_mask = create_region_mask(altitude.shape, x, y, width, height,
                                     mask)

    # compute centroid
    centroid = [np.mean(x_value) for x_value in np.where(region_mask)]
    result['y_centroid'] = centroid[0]
    result['x_centroid'] = centroid[1]

    # compute azimuth/altitude max,min,range and bias
    az_min, az_max, az_range, az_bias = retinotopy_metric(region_mask,
                                                          azimuth)
    alt_min, alt_max, alt_range, alt_bias = retinotopy_metric(region_mask,
                                                              altitude)
    result['azimuth_min'] = az_min
    result['azimuth_max'] = az_max
    result['azimuth_range'] = az_range
    result['azimuth_bias'] = az_bias
    result['altitude_min'] = alt_min
    result['altitude_max'] = alt_max
    result['altitude_range'] = alt_range
    result['altitude_bias'] = alt_bias

    # eccentricity at centroid
    cy = round(result['y_centroid'])
    cx = round(result['x_centroid'])
    result['eccentricity_at_centroid'] = float(eccentricity_ret_zero[cy,cx])

    return result
