# This file is part of the MapProxy project.
# Copyright (C) 2010 Omniscale <http://omniscale.de>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from collections import OrderedDict

from PIL import Image
from mapproxy.grid.tile_grid import tile_grid
from mapproxy.image import BlankImageResult
from mapproxy.image import ImageResult
from mapproxy.image.opts import ImageOptions
from mapproxy.layer.map_layer import MapLayer
from mapproxy.extent import DefaultMapExtent
from mapproxy.service.base import Server
from mapproxy.service.tile import TileServer
from mapproxy.service.wms import WMSGroupLayer, WMSServer
from mapproxy.service.wmts import WMTSServer
from mapproxy.test.http import make_wsgi_env


class DummyLayer(MapLayer):
    transparent = True
    extent = DefaultMapExtent()
    has_legend = False
    queryable = False

    def __init__(self, name):
        super().__init__()
        self.name = name
        self.requested = False
        self.queried = False
        self.nominal_scale = None

    def get_map(self, query):
        self.requested = True

    def get_info(self, query):
        self.queried = True

    def map_layers_for_query(self, query):
        return [(self.name, self)]

    def info_layers_for_query(self, query):
        return [(self.name, self)]


class DummyTileLayer(object):
    def __init__(self, name):
        self.requested = False
        self.name = name
        self.grid = tile_grid(900913)

    def tile_bbox(self, request, use_profiles=False):
        # this dummy code does not handle profiles and different tile origins!
        return self.grid.tile_bbox(request.tile)

    def render(self, tile_request, use_profiles=None, coverage=None, decorate_img=None):
        self.requested = True
        resp = BlankImageResult((256, 256), image_opts=ImageOptions(format='image/png'))
        resp.timestamp = 0
        return resp


class TestDecorateImg(object):

    def setup_method(self):
        # Base server
        self.server = Server()
        # WMS Server
        root_layer = WMSGroupLayer(None, 'root layer', None, [DummyLayer('wms_cache')])
        self.wms_server = WMSServer(
            md={}, root_layer=root_layer, srs=['EPSG:4326'],
            image_formats={'image/png': ImageOptions(format='image/png')}
        )
        # Tile Servers
        layers = OrderedDict()
        layers["wms_cache_EPSG900913"] = DummyTileLayer('wms_cache')
        self.tile_server = TileServer(layers, {})
        self.wmts_server = WMTSServer(layers, {})
        # Common arguments
        self.query_extent = ('EPSG:27700', (0, 0, 700000, 1300000))

    def test_original_imageresult_returned_when_no_callback(self):
        img_src1 = ImageResult(Image.new('RGBA', (100, 100)))
        env = make_wsgi_env('', extra_environ={})
        img_src2 = self.server.decorate_img(
            img_src1, 'wms.map', ['layer1'],
            env, self.query_extent
        )
        assert img_src1 == img_src2

    def test_returns_imageresult(self):
        img_src1 = ImageResult(Image.new('RGBA', (100, 100)))
        env = make_wsgi_env('', extra_environ={})
        img_src2 = self.server.decorate_img(
            img_src1, 'wms.map', ['layer1'],
            env, self.query_extent
        )
        assert isinstance(img_src2, ImageResult)

    def set_called_callback(self, img_src, service, layers, **kw):
        self.called = True
        return img_src

    def test_calls_callback(self):
        img_src1 = ImageResult(Image.new('RGBA', (100, 100)))
        self.called = False
        env = make_wsgi_env('', extra_environ={'mapproxy.decorate_img': self.set_called_callback})
        self.server.decorate_img(
            img_src1, 'wms.map', ['layer1'],
            env, self.query_extent
        )
        assert self.called is True

    def return_new_imageresult_callback(self, img_src, service, layers, **kw):
        new_img_src = ImageResult(Image.new('RGBA', (100, 100)))
        self.new_img_src = new_img_src
        return new_img_src

    def test_returns_callbacks_return_value(self):
        img_src1 = ImageResult(Image.new('RGBA', (100, 100)))
        env = make_wsgi_env('', extra_environ={'mapproxy.decorate_img': self.return_new_imageresult_callback})
        self.new_img_src = None
        img_src2 = self.server.decorate_img(
            img_src1, 'wms.map', ['layer1'],
            env, self.query_extent
        )
        assert img_src2 == self.new_img_src

    def test_wms_server(self):
        ''' Test that the decorate_img method is available on a WMSServer instance '''
        img_src1 = ImageResult(Image.new('RGBA', (100, 100)))
        self.called = False
        env = make_wsgi_env('', extra_environ={'mapproxy.decorate_img': self.set_called_callback})
        self.wms_server.decorate_img(
            img_src1, 'wms.map', ['layer1'],
            env, self.query_extent
        )
        assert self.called is True

    def test_tile_server(self):
        ''' Test that the decorate_img method is available on a TileServer instance '''
        img_src1 = ImageResult(Image.new('RGBA', (100, 100)))
        self.called = False
        env = make_wsgi_env('', extra_environ={'mapproxy.decorate_img': self.set_called_callback})
        self.tile_server.decorate_img(
            img_src1, 'tms', ['layer1'],
            env, self.query_extent
        )
        assert self.called is True

    def test_wmts_server(self):
        ''' Test that the decorate_img method is available on a WMTSServer instance '''
        img_src1 = ImageResult(Image.new('RGBA', (100, 100)))
        self.called = False
        env = make_wsgi_env('', extra_environ={'mapproxy.decorate_img': self.set_called_callback})
        self.wmts_server.decorate_img(
            img_src1, 'wmts', ['layer1'],
            env, self.query_extent
        )
        assert self.called is True

    def test_args(self):
        def callback(img_src, service, layers, environ, query_extent, **kw):
            assert isinstance(img_src, ImageResult)
            assert 'wms.map' == service
            assert isinstance(layers, list)
            assert isinstance(environ, dict)
            assert len(query_extent) == 2
            assert len(query_extent[1]) == 4
            return img_src
        img_src1 = ImageResult(Image.new('RGBA', (100, 100)))
        env = make_wsgi_env('', extra_environ={'mapproxy.decorate_img': callback})
        self.tile_server.decorate_img(
            img_src1, 'wms.map', ['layer1'],
            env, self.query_extent
        )
