from safe.impact_functions.core import FunctionProvider
from safe.impact_functions.core import get_hazard_layer, get_exposure_layer
from safe.impact_functions.core import get_question
from safe.storage.vector import Vector
from safe.common.utilities import ugettext as tr
from safe.common.tables import Table, TableRow
from safe.engine.interpolation import assign_hazard_values_to_exposure_data


class FloodBuildingImpactFunction(FunctionProvider):
    """Inundation impact on building data

    :param requires category=='hazard' and \
                    subcategory in ['flood', 'tsunami']

    :param requires category=='exposure' and \
                    subcategory=='structure' and \
                    layertype=='vector'
    """

    target_field = 'INUNDATED'
    title = tr('Be flooded')

    def run(self, layers):
        """Flood impact to buildings (e.g. from Open Street Map)
        """

        threshold = 1.0  # Flood threshold [m]

        # Extract data
        H = get_hazard_layer(layers)    # Depth
        E = get_exposure_layer(layers)  # Building locations

        question = get_question(H.get_name(),
                                E.get_name(),
                                self)

        # Determine attribute name for hazard levels
        if H.is_raster:
            hazard_attribute = 'depth'
        else:
            hazard_attribute = 'FLOODPRONE'

        # Interpolate hazard level to building locations
        I = assign_hazard_values_to_exposure_data(H, E,
                                             attribute_name=hazard_attribute)

        # Extract relevant exposure data
        attribute_names = I.get_attribute_names()
        attributes = I.get_data()
        N = len(I)

        # Calculate building impact
        count = 0
        buildings = {}
        affected_buildings = {}
        for i in range(N):
            if hazard_attribute == 'depth':
                # Get the interpolated depth
                x = float(attributes[i]['depth'])
                x = x > threshold
            elif hazard_attribute == 'FLOODPRONE':
                # Use interpolated polygon attribute
                atts = attributes[i]

                if 'FLOODPRONE' in atts:
                    res = atts['FLOODPRONE']
                    if res is None:
                        x = False
                    else:
                        x = res.lower() == 'yes'
                else:
                    # If there isn't a flood prone attribute,
                    # assume that building is wet if inside polygon
                    # as flag by generic attribute AFFECTED
                    res = atts['Affected']
                    if res is None:
                        x = False
                    else:
                        x = res
            else:
                msg = (tr('Unknown hazard type %s. '
                         'Must be either "depth" or "floodprone"')
                       % hazard_attribute)
                raise Exception(msg)

            # Count affected buildings by usage type if available
            if 'type' in attribute_names:
                usage = attributes[i]['type']
            else:
                usage = None

            if usage is not None and usage != 0:
                key = usage
            else:
                key = 'unknown'

            if key not in buildings:
                buildings[key] = 0
                affected_buildings[key] = 0

            # Count all buildings by type
            buildings[key] += 1
            if x is True:
                # Count affected buildings by type
                affected_buildings[key] += 1

                # Count total affected buildings
                count += 1

            # Add calculated impact to existing attributes
            attributes[i][self.target_field] = x

        # Lump small entries and 'unknown' into 'other' category
        for usage in buildings.keys():
            x = buildings[usage]
            if x < 25 or usage == 'unknown':
                if 'other' not in buildings:
                    buildings['other'] = 0
                    affected_buildings['other'] = 0

                buildings['other'] += x
                affected_buildings['other'] += affected_buildings[usage]
                del buildings[usage]
                del affected_buildings[usage]

        # Generate csv file of results
##        fid = open('C:\dki_table_%s.csv' % H.get_name(), 'wb')
##        fid.write('%s, %s, %s\n' % (tr('Building type'),
##                                    tr('Temporarily closed'),
##                                    tr('Total')))
##        fid.write('%s, %i, %i\n' % (tr('All'), count, N))

        # Generate simple impact report
        table_body = [question,
                      TableRow([tr('Building type'),
                                tr('Temporarily closed'),
                                tr('Total')],
                               header=True),
                      TableRow([tr('All'), count, N])]

##        fid.write('%s, %s, %s\n' % (tr('Building type'),
##                                    tr('Temporarily closed'),
##                                    tr('Total')))

        school_closed = 0
        hospital_closed = 0
        # Generate break down by building usage type is available
        if 'type' in attribute_names:
            # Make list of building types
            building_list = []
            for usage in buildings:

                building_type = usage.replace('_', ' ')

                # Lookup internationalised value if available
                building_type = tr(building_type)
                #==============================================================
                # print ('WARNING: %s could not be translated'
                #        % building_type)
                #==============================================================

                building_list.append([building_type.capitalize(),
                                      affected_buildings[usage],
                                      buildings[usage]])
                if building_type == 'school':
                    school_closed = affected_buildings[usage]
                if building_type == 'hospital':
                    hospital_closed = affected_buildings[usage]
##                fid.write('%s, %i, %i\n' % (building_type.capitalize(),
##                                            affected_buildings[usage],
##                                            buildings[usage]))

            # Sort alphabetically
            building_list.sort()

            #table_body.append(TableRow([tr('Building type'),
            #                            tr('Temporarily closed'),
            #                            tr('Total')], header=True))
            table_body.append(TableRow(tr('Breakdown by building type'),
                                       header=True))
            for row in building_list:
                s = TableRow(row)
                table_body.append(s)

##        fid.close()
        table_body.append(TableRow(tr('Action Checklist:'), header=True))
        table_body.append(TableRow(tr('Are the critical facilities still '
                                     'open?')))
        table_body.append(TableRow(tr('Which structures have warning capacity '
                                     '(eg. sirens, speakers, etc.)?')))
        table_body.append(TableRow(tr('Which buildings will be evacuation '
                                     'centres?')))
        table_body.append(TableRow(tr('Where will we locate the operations '
                                     'centre?')))
        table_body.append(TableRow(tr('Where will we locate warehouse and/or '
                                     'distribution centres?')))
        if school_closed > 0:
            table_body.append(TableRow(tr('Where will the students from the %d'
                                         ' closed schools go to study?') %
                                         school_closed))
        if hospital_closed > 0:
            table_body.append(TableRow(tr('Where will the patients from the %d'
                                         ' closed hospitals go for treatment '
                                         'and how will we transport them?') %
                                         hospital_closed))

        table_body.append(TableRow(tr('Notes'), header=True))
        assumption = tr('Buildings are said to be flooded when ')
        if hazard_attribute == 'depth':
            assumption += tr('flood levels exceed %.1f m') % threshold
        else:
            assumption += tr('in areas marked as flood prone')
        table_body.append(assumption)

        impact_summary = Table(table_body).toNewlineFreeString()
        impact_table = impact_summary
        map_title = tr('Buildings inundated')

        # Create style
        style_classes = [dict(label=tr('Not Flooded'), min=0, max=0,
                              colour='#1EFC7C', transparency=0, size=1),
                         dict(label=tr('Flooded'), min=1, max=1,
                              colour='#F31A1C', transparency=0, size=1)]
        style_info = dict(target_field=self.target_field,
                          style_classes=style_classes)

        # Create vector layer and return
        V = Vector(data=attributes,
                   projection=I.get_projection(),
                   geometry=I.get_geometry(),
                   name=tr('Estimated buildings affected'),
                   keywords={'impact_summary': impact_summary,
                             'impact_table': impact_table,
                             'map_title': map_title},
                   style_info=style_info)
        return V
