# Path: lib/exception.py
# class MissingException(Exception):
# 
#     def __init__(self, message):
#         # Call the base class constructor with the parameters it needs
#         super(MissingException, self).__init__(message)
#         self.returncode = 4
# 
#         logg = Logger('MissingException')
#         logg.error(message)
# 
# Path: lib/sitkaAPI.py
# def latestMetricInstances(insts, single=False):
#     """
#     Take a list of instances from the API and return the latest one with a bit of fancy formatting
#     :param instances: list of instances
#     :return:
#     """
#     if len(insts) == 0:
#         return None
# 
#     # Filter out the instances without dates
# 
# 
#     # First create a "sortdate" helper. Setting the second and microsecond to zero is a hack to cover slight timing
#     # differences
#     for idx, inst in enumerate(insts):
#         gendate = filter(lambda x: x['name']==DATECREATEDFIELD, inst['values'])
#         try:
#             inst['date'] = dateutil.parser.parse(gendate[0]['value'])
#             if not single:
#                 inst['date'] = inst['date'].replace(second=0, microsecond=0)
#         except Exception, e:
#             inst['date'] = None
# 
#     filteredinsts = filter(lambda x: x['date'] is not None, insts)
# 
#     if len(filteredinsts) == 0:
#         return None
# 
#     # Sort by the field we just created
#     latestDate = max(x['date'] for x in filteredinsts)
# 
#     # Now filter out the ones with the right date
#     filteredInstances = filter(lambda x: x['date'] == latestDate , filteredinsts)
# 
#     # Only cast things to floating point where necessary
#     formatter = lambda x: float(x['value']) if x['type'] == "Numeric" and x['value'] is not None else x['value']
# 
#     # Now turn it inside out so it's a proper {name: value} pair
#     results = []
#     for inst in filteredInstances:
#         result = {}
#         for metric in inst['values']:
#             result[metric['name']] = formatter(metric)
#         results.append(result)
# 
#     return results
# 
# Path: lib/metrics.py
# class CHaMPMetric(object):
# 
#     # This is the dictionary representation of the object
#     # in its null state.
#     TEMPLATE = {}
# 
#     def __init__(self, *args, **kwargs):
#         # First initialize our logger and our empty metrics
#         self.log = Logger(self.__module__)
#         self.metrics = deepcopy(self.TEMPLATE)
# 
#         # Now try a calculation
#         try:
#             self.calc(*args, **kwargs)
#         except (DataException, MissingException), e:
#             self.log.warning("Could not complete metric calculation")
#             self.metrics = deepcopy(self.TEMPLATE)
# 
#     def calc(self, *args, **kwargs):
#         """
#         Needs to be overloaded in the children
#         :return:
#         """
#         raise Exception("YOU MUST IMPLEMENT THIS")


from lib.exception import MissingException
from lib.sitkaAPI import latestMetricInstances
from lib.metrics import CHaMPMetric
from metricsbychannelunit import metricsByChannelUnit, emptiesByChannelUnit
        'LW': (['LWDFC'], True),
        'TVeg': (['VegetationFC'], True),
        'Ucut': (['UndercutBanksFC'], True),
        'Art': (['ArtificialFC'], True),
        'AqVeg': (['AquaticVegetationFC'], True),
        'None': (['TotalNoFC'], False)
    }

    def __init__(self, apiData):
        if FishcoverMetrics.TEMPLATE == {}:
            FishcoverMetrics.TEMPLATE = emptiesByChannelUnit(FishcoverMetrics.fishCoverClasses)
        super(FishcoverMetrics, self).__init__(apiData)

    def calc(self, apiData):

        """
        Calculate fish cover metrics
        :param apiData: dictionary of API data. Key is API call name. Value is API data
        :return: metrics dictionary
        """

        self.log.info("Running Fish Cover Metrics")

        if 'FishCover' not in apiData:
            raise MissingException("FishCover missing from apiData")

        # Retrieve the undercut API data
        fishCoverVals = [val['value'] for val in apiData['FishCover']['values'] ]

        if 'ChannelUnitMetrics' not in apiData:

# Path: lib/exception.py
# class MissingException(Exception):
# 
#     def __init__(self, message):
#         # Call the base class constructor with the parameters it needs
#         super(MissingException, self).__init__(message)
#         self.returncode = 4
# 
#         logg = Logger('MissingException')
#         logg.error(message)
# 
# Path: lib/sitkaAPI.py
# def latestMetricInstances(insts, single=False):
#     """
#     Take a list of instances from the API and return the latest one with a bit of fancy formatting
#     :param instances: list of instances
#     :return:
#     """
#     if len(insts) == 0:
#         return None
# 
#     # Filter out the instances without dates
# 
# 
#     # First create a "sortdate" helper. Setting the second and microsecond to zero is a hack to cover slight timing
#     # differences
#     for idx, inst in enumerate(insts):
#         gendate = filter(lambda x: x['name']==DATECREATEDFIELD, inst['values'])
#         try:
#             inst['date'] = dateutil.parser.parse(gendate[0]['value'])
#             if not single:
#                 inst['date'] = inst['date'].replace(second=0, microsecond=0)
#         except Exception, e:
#             inst['date'] = None
# 
#     filteredinsts = filter(lambda x: x['date'] is not None, insts)
# 
#     if len(filteredinsts) == 0:
#         return None
# 
#     # Sort by the field we just created
#     latestDate = max(x['date'] for x in filteredinsts)
# 
#     # Now filter out the ones with the right date
#     filteredInstances = filter(lambda x: x['date'] == latestDate , filteredinsts)
# 
#     # Only cast things to floating point where necessary
#     formatter = lambda x: float(x['value']) if x['type'] == "Numeric" and x['value'] is not None else x['value']
# 
#     # Now turn it inside out so it's a proper {name: value} pair
#     results = []
#     for inst in filteredInstances:
#         result = {}
#         for metric in inst['values']:
#             result[metric['name']] = formatter(metric)
#         results.append(result)
# 
#     return results
# 
# Path: lib/metrics.py
# class CHaMPMetric(object):
# 
#     # This is the dictionary representation of the object
#     # in its null state.
#     TEMPLATE = {}
# 
#     def __init__(self, *args, **kwargs):
#         # First initialize our logger and our empty metrics
#         self.log = Logger(self.__module__)
#         self.metrics = deepcopy(self.TEMPLATE)
# 
#         # Now try a calculation
#         try:
#             self.calc(*args, **kwargs)
#         except (DataException, MissingException), e:
#             self.log.warning("Could not complete metric calculation")
#             self.metrics = deepcopy(self.TEMPLATE)
# 
#     def calc(self, *args, **kwargs):
#         """
#         Needs to be overloaded in the children
#         :return:
#         """
#         raise Exception("YOU MUST IMPLEMENT THIS")


# Path: tools/topoauxmetrics/methods/fishcover.py
from lib.exception import MissingException
from lib.sitkaAPI import latestMetricInstances
from lib.metrics import CHaMPMetric
from metricsbychannelunit import metricsByChannelUnit, emptiesByChannelUnit

        'LW': (['LWDFC'], True),
        'TVeg': (['VegetationFC'], True),
        'Ucut': (['UndercutBanksFC'], True),
        'Art': (['ArtificialFC'], True),
        'AqVeg': (['AquaticVegetationFC'], True),
        'None': (['TotalNoFC'], False)
    }

    def __init__(self, apiData):
        if FishcoverMetrics.TEMPLATE == {}:
            FishcoverMetrics.TEMPLATE = emptiesByChannelUnit(FishcoverMetrics.fishCoverClasses)
        super(FishcoverMetrics, self).__init__(apiData)

    def calc(self, apiData):

        """
        Calculate fish cover metrics
        :param apiData: dictionary of API data. Key is API call name. Value is API data
        :return: metrics dictionary
        """

        self.log.info("Running Fish Cover Metrics")

        if 'FishCover' not in apiData:
            raise MissingException("FishCover missing from apiData")

        # Retrieve the undercut API data
        fishCoverVals = [val['value'] for val in apiData['FishCover']['values'] ]

        if 'ChannelUnitMetrics' not in apiData:

            raise MissingException('Missing channel metric instances')