def __init__(self, painter_manager, cached_pyramid, z_value=0, status=True, name=None):

        super(MosaicPainter, self).__init__(painter_manager, z_value, status, name)
        
        self._cached_pyramid = cached_pyramid # Fixme: mosaic / pyramid ?
        self._texture_cache = LruCache(constraint=1024**2) # Fixme
        
        self._viewport_area = self._glwidget.glortho2d.viewport_area
        self._shader_program = self._glwidget.shader_manager.texture_shader_program
        
        self._tile_list = []
        self._textures = []
        self._texture_dict = {}
        
        application = QtWidgets.QApplication.instance()
        self._loop = asyncio.get_event_loop()
    def test_memory(self):

        print('\nTest Memory Mode')

        live_objects.clear()

        lru_cache = LruCache(constraint=50)

        for i in range(8):
            lru_cache.add(ObjMemory(i))
        self.assertEqual(len(lru_cache), 8)
        self.assertEqual(lru_cache.size(), 4*(5+10))
        print(lru_cache)

        lru_cache.recycle()
        print(lru_cache)
        self.assertEqual(len(lru_cache), 7)
        self.assertEqual(lru_cache.size(), lru_cache.constraint)
        for i in 0,:
            self.assertTrue(i not in live_objects)
class MosaicPainter(Painter):

    __painter_name__ = 'mosaic'

    _logger = _module_logger.getChild('MosaicPainter')

    ##############################################

    def __init__(self, painter_manager, cached_pyramid, z_value=0, status=True, name=None):

        super(MosaicPainter, self).__init__(painter_manager, z_value, status, name)
        
        self._cached_pyramid = cached_pyramid # Fixme: mosaic / pyramid ?
        self._texture_cache = LruCache(constraint=1024**2) # Fixme
        
        self._viewport_area = self._glwidget.glortho2d.viewport_area
        self._shader_program = self._glwidget.shader_manager.texture_shader_program
        
        self._tile_list = []
        self._textures = []
        self._texture_dict = {}
        
        application = QtWidgets.QApplication.instance()
        self._loop = asyncio.get_event_loop()
        # self._loop = QEventLoop(application)
        # asyncio.set_event_loop(self._loop)

        # self._loop.close()

    ##############################################

    @property
    def texture_cache(self):

        return self._texture_cache

    ##############################################

    def reset(self):

        self._texture_cache.reset()

    ##############################################

    def recycle(self):

        # self._logger.debug('Recycle Mosaic Cache')
        # self._mosaic_cache.recycle()

        # self._logger.debug('Recycle OpenGL Cache')
        line = '-'*50 + '\n'
        text = """
Texture Cache: recycle
  before
"""
        text += str(self._texture_cache)
        self._texture_cache.recycle()
        text += '\n  after\n' + str(self._texture_cache) + '\n' + line
        self._logger.debug(text)

    ##############################################

    # def zoom_layer_changed(self, zoom_layer):
    #
    #     pass

    ##############################################

    def update(self):

        level = self._glwidget._zoom_manager.level # Fixme
        texture_cache = self._texture_cache
        cached_pyramid = self._cached_pyramid
        
        self._logger.debug('Update Mosaic Painter @{}'.format(level))
        
        # always compute tile list
        old_tile_list = self._tile_list
        pyramid_level = self._cached_pyramid._pyramid[level]
        # Fixme: return rotated area
        # compute intersection
        mosaic_interval = pyramid_level.projection_interval_to_mosaic(self._viewport_area.area)
        self._tile_list = list(mosaic_interval.iter())
        self._logger.debug('Viewport\n' + str(self._tile_list))
        (tiles_to_release,
         tiles_to_keep,
         tiles_to_acquire) = split_list(old_tile_list, self._tile_list)
        
        # Reset
        self._textures = []
        print(self._texture_dict)
        for tile_index in tiles_to_keep:
            row, column = tile_index
            key = Tile.tile_key(0, level, row, column)
            self._textures.append(self._texture_dict[key])
        self._glwidget.update()
        
        # Get new tiles
        if tiles_to_acquire:
            tasks = [asyncio.async(cached_pyramid.acquire(level, row, column))
                     for row, column in tiles_to_acquire]
            # for task in tasks:
            #     task.add_done_callback(self._task_callback)
            self._logger.debug('Run loop')
            #!# with self._loop:
            self._loop.run_until_complete(asyncio.wait(tasks))
            self._logger.debug('loop done')
            for task in tasks:
                self._task_callback(task)
interval = Interval2D((x, x + 500), (y, y + 500))
mosaic_interval = geoportail_pyramid[level].projection_interval_to_mosaic(interval)
print(mosaic_interval)
# for row, column in mosaic_interval.iter():
#     print(row, column)

loop = asyncio.get_event_loop()

tile = loop.run_until_complete(geoportail_wtms.download_ortho_photo(level, row, column))
# tile.to_pil_image().save(tile.filename(with_layer=True, with_level=True))

geoportail_map_provider = GeoPortailMapProvider(geoportail_wtms)
tasks = [asyncio.async(geoportail_map_provider.get_tile(level, row, column + i)) for i in range(3)]
loop.run_until_complete(asyncio.wait(tasks))

lru_cache = LruCache(constraint=1024**3)

def done_callback(future):
    print('done', future.result())

cached_pyramid = CachedPyramid(geoportail_map_provider, lru_cache)
tasks = [asyncio.async(cached_pyramid.acquire(level, row, column + i)) for i in (0, 1, 0)]
for task in tasks:
    task.add_done_callback(done_callback)
loop.run_until_complete(asyncio.wait(tasks))
cached_pyramid.release(level, row, column)
lru_cache.recycle()

# tiles = cached_pyramid.acquire_interval(level, mosaic_interval)

loop.close()
    def test_history(self):

        print('\nTest History Mode')

        live_objects.clear()

        lru_cache = LruCache(constraint=5)

        for i in range(5):
            lru_cache.add(Obj(i))
        self.assertEqual(len(lru_cache), 5)
        print(lru_cache)

        obj = lru_cache.acquire(6)
        self.assertIsNone(obj)

        obj1 = lru_cache.acquire(1)
        print(lru_cache)
        self.assertEqual(obj1.key(), 1)
        self.assertEqual(lru_cache._younger._obj, obj1)
        self.assertEqual(lru_cache._younger._reference_counter, 1)

        obj3 = lru_cache.acquire(3)
        print(lru_cache)
        self.assertEqual(obj3.key(), 3)
        self.assertEqual(lru_cache._younger._obj, obj3)
        self.assertEqual(lru_cache._younger._reference_counter, 1)

        cache_element = lru_cache._cache_dict[1]
        obj11 = lru_cache.acquire(1)
        print(lru_cache)
        self.assertEqual(cache_element._reference_counter, 2)
        lru_cache.release(1)
        del obj11
        print(lru_cache)
        self.assertEqual(cache_element._reference_counter, 1)
        del cache_element

        for i in range(5, 10):
            lru_cache.add(Obj(i))
        print(lru_cache)
        self.assertEqual(len(lru_cache), 10)

        objs = {}
        for i in 9, 8, 7, 6:
            objs[i] = lru_cache.acquire(i)
        print(lru_cache)

        lru_cache.recycle()
        print(lru_cache)
        self.assertEqual(len(lru_cache), 6)
        for i in 0, 2, 4, 5:
            self.assertTrue(i not in live_objects)

        for i in 6, 7:
            lru_cache.release(i)
            del objs[i]
        print(lru_cache)
        lru_cache.recycle()
        print(lru_cache)
        self.assertEqual(len(lru_cache), 5)
        for i in 7,:
            self.assertTrue(i not in live_objects)

        print("Cleanup")
        print(objs)
        del objs
        del obj1
        del obj3
        lru_cache.reset()
        print(lru_cache)
        self.assertEqual(len(live_objects), 0)