import logging

logger = logging.getLogger('wntr.metrics.fraction_delivered')

def fdv(node_results, average_times=False, average_nodes=False):
    """
    Compute fraction delivered volume (FDV), equations modified from [1]. 
    The metric can be averaged over times and/or nodes.
    
    Parameters
    ----------
    node_results : pd.Panel
        A pandas Panel containing node results. 
        Items axis = attributes, Major axis = times, Minor axis = node names
        FDV uses 'expected demand' and 'demand' attrbutes.
        
    average_times : bool (default = False)
        Flag to determine if calculations are to be averaged over each time
        step. If false, FDV calculations will be performed for each time step.
        If true, FDV calculations will be averaged over all time steps.
    
    average_nodes : bool (default = False)
        Flag to determine if calculations are to be averaged over each node. 
        If false, FDV calculations will be performed for each node. If true, FDV
        calculations will be averaged over all nodes.

    Returns 
    -------    
    fdv : pd.DataFrame, pd.Series, or scalar (depending on node and time averaging)
        Fraction of delivered volume
        
    References
    ----------
    [1] Ostfeld A, Kogan D, Shamir U. (2002). Reliability simulation of water
    distribution systems - single and multiquality, Urban Water, 4, 53-61
    """

    exp_demand = _average_attribute(node_results['expected_demand'], average_times, average_nodes)
    act_received = _average_attribute(node_results['demand'], average_times, average_nodes)

    # Calculate FDV    
    fdv = act_received / exp_demand
    
    # Replace NaNs (generated by nodes with 0 demand) 
    try:
        fdv = fdv.fillna(1) 
    except:
        if exp_demand == 0:
            fdv = 1
    
    return fdv
    
def fdd(node_results, Dstar, average_times=False, average_nodes=False):
    """
    Compute fraction delivered demand (FDD), equations modified from [1]. 
    The metric can be averaged over times and/or nodes.
    
    Parameters
    ----------
    node_results : pd.Panel
        A pandas Panel containing node results. 
        Items axis = attributes, Major axis = times, Minor axis = node names
        FDD uses 'expected demand' and 'demand' attrbutes.
        
    Dstar : float
        Threshold demand factor
        
    average_times : bool (default = False)
        Flag to determine if calculations are to be averaged over each time
        step. If false, FDV calculations will be performed for each time step.
        If true, FDV calculations will be averaged over all time steps.
    
    average_nodes : bool (default = False)
        Flag to determine if calculations are to be averaged over each node. 
        If false, FDV calculations will be performed for each node. If true, FDV
        calculations will be averaged over all nodes.

    Returns 
    -------    
    fdd : pd.DataFrame, pd.Series, or scalar (depending on node and time averaging)
        Fraction of delivered demand
        
    References
    ----------
    [1] Ostfeld A, Kogan D, Shamir U. (2002). Reliability simulation of water
    distribution systems - single and multiquality, Urban Water, 4, 53-61
    """

    fdv_metric = fdv(node_results, average_times, average_nodes)
        
    # Calculate FDD
    fdd = (fdv_metric >= Dstar)+0 
    
    return fdd
    
def fdq(node_results, Qstar, average_times=False, average_nodes=False):
    """
    Compute fraction delivered quality (FDQ), equations modified from [1]. 
    The metric can be averaged over times and/or nodes.
    
    Parameters
    ----------
    node_results : pd.Panel
        A pandas Panel containing node results. 
        Items axis = attributes, Major axis = times, Minor axis = node names
        FDQ uses 'quality' attrbute.
        
    Qstar : float
        Water quality threshold.
        
    average_times : bool (default = False)
        Flag to determine if calculations are to be averaged over each time
        step. If false, FDV calculations will be performed for each time step.
        If true, FDV calculations will be averaged over all time steps.
    
    average_nodes : bool (default = False)
        Flag to determine if calculations are to be averaged over each node. 
        If false, FDV calculations will be performed for each node. If true, FDV
        calculations will be averaged over all nodes.

    Returns 
    -------    
    fdq : pd.DataFrame, pd.Series, or scalar (depending on node and time averaging)
        Fraction of delivered quality
        
    References
    ----------
    [1] Ostfeld A, Kogan D, Shamir U. (2002). Reliability simulation of water
    distribution systems - single and multiquality, Urban Water, 4, 53-61
    """

    quality = _average_attribute(node_results['quality'], average_times, average_nodes)
    
    fdq = (quality >= Qstar)+0 
            
    return fdq
    
def _average_attribute(attribute, average_times, average_nodes):
     # FDV for all times and nodes
    if average_times==False and average_nodes==False:
        pass
        
    # FDV for all nodes (averaged over all times)    
    if average_times==True and average_nodes==False:
        attribute = attribute.sum(axis=0)
        
    # FDV for all time (averaged over all nodes)        
    if average_times==False and average_nodes==True:
        attribute = attribute.sum(axis=1)
       
    # FDV for scenario (averaged over all times and nodes)   
    if average_times==True and average_nodes==True:
        attribute = attribute.sum().sum()
        
    return attribute
