import mapscript

from django.conf import settings

from .symbols import WmsSymbolSet


class WmsMap(object):
    """
    Map objects representing mapserver map files.
    """

    layer_classes = []
    symbolset_class = WmsSymbolSet
    title = 'Django-wms service'
    srs = ['4326', '3086', '3857']
    enable_requests = ['GetMap', 'GetLegendGraphic', 'GetCapabilities']
    legend_size = (20, 20)

    def __init__(self, request, **kwargs):
        """
        Method to setup map object based on the input parameters. The map
        object represents the mapserver mapfile and is used to render
        the wms requests.
        """
        # Store arguments
        self.request = request
        self.kwargs = kwargs

        # Create mapobject
        self.map_object = mapscript.mapObj()

        self.register_symbolset()
        self.register_layers()

        # Set map object properties
        self.map_object.setProjection('init=epsg:3857')
        self.map_object.setExtent(-180, -90, 180, 90)
        self.map_object.setSize(256, 256)
        self.map_object.setMetaData('wms_title', self.title)
        self.map_object.setMetaData('wms_srs', 'epsg:' + ' epsg:'.join(self.srs))
        self.map_object.setMetaData('wms_enable_request',
                               ' '.join(self.enable_requests))
        self.map_object.outputformat.transparent = mapscript.MS_ON

        # Set legend item size
        self.map_object.legend.keysizex = self.legend_size[0]
        self.map_object.legend.keysizey = self.legend_size[1]

        # Allow debugging
        if settings.DEBUG:
            self.map_object.debug = mapscript.MS_ON

    def get_layers(self):
        """
        Instantiates and returns a list of layers for this map.
        """
        # Create layer instances
        return [layer(self.request, **self.kwargs) for layer in self.layer_classes]

    def register_layers(self):
        """
        Registers all layer objects into a map object.
        """
        # Get layers
        layers = self.get_layers()

        # Check for naming consistency
        names = [layer.name for layer in layers]
        if len(names) > 1 and len(set(names)) != len(names):
            raise ValueError(
                'Found two identical layer names in single map. '
                'Specify unique names for layers. This error be due to '
                'automatic naming which uses the model name as layer name '
                'by default.'
            )

        # Register layers
        for layer in layers:
            # Get layer
            dispatched_layer = layer.dispatch_by_type()

            # Update symbol index if symbol name was given
            # This is necessary because mapscript links the symbol index from
            # the map level symbolset with the layer level style object. So
            # this step can not be executed when instantiating the layer.
            i = 0
            while dispatched_layer.getClass(i):
                style = dispatched_layer.getClass(i).getStyle(0)
                if style.symbolname:
                    style.setSymbolByName(self.map_object, style.symbolname)
                i += 1

            # Insert layer object into map
            self.map_object.insertLayer(dispatched_layer)

    def register_symbolset(self):
        """
        Registers a symbol set in the current map.
        """

        symbolset = self.symbolset_class()

        # Add symbols
        for symb in symbolset.get_symbols():
            self.map_object.symbolset.appendSymbol(symb)
