# -*- coding: utf-8 -*-
"""
Écran de sélection de l'instrument

$Id$
$URL$
"""
import os.path
import pygame
from minwii.eventutils import event_handler, EventDispatcher, EventHandlerMixin
from minwii.config import FRAMERATE
from minwii.config import  INSTRUMENTS
from minwii.globals import BACKGROUND_LAYER
from minwii.globals import FOREGROUND_LAYER
from minwii.globals import CURSOR_LAYER
from minwii.globals import hls_to_rgba_8bits
from cursors import WarpingCursor


class InstrumentSelector(pygame.sprite.LayeredDirty, EventHandlerMixin) :
    
    rows = 3
    cols = 3
    instruments = INSTRUMENTS

    def __init__(self) :
        super(InstrumentSelector, self).__init__()
        #self._initRects()
        self._initTiles()
        self._initCursor()
        self._inflatedTile = None
        self.selectedInstrument = None
    
    def _initTiles(self) :
        screen = pygame.display.get_surface()
        tileWidth = int(round(float(screen.get_width()) / self.cols))
        tileHeight = int(round(float(screen.get_height()) / self.rows))

        self.tiles = []
        instrus = list(self.instruments[:])
        for y in range(self.cols) :
            for x in range(self.rows) :
                upperLeftCorner = (x * tileWidth, y * tileHeight)
                rect = pygame.Rect(upperLeftCorner, (tileWidth, tileHeight))
                # !!! s'il y avait plus de 3x3 tuiles !!!, il faudrait alors
                # changer le tuple (x,y) qui concerne le point d'application de l'homotétie.
                # Cf. InstrumentTile.inflate
                tile = InstrumentTile(instrus.pop(0), self, rect, (x,y))
                self.add(tile, layer=BACKGROUND_LAYER)
                self.tiles.append(tile)
    
    def _initCursor(self) :
        self.cursor = WarpingCursor(blinkMode=True)
        self.add(self.cursor, layer=CURSOR_LAYER)


    def run(self):
        self._running = True
        clock = pygame.time.Clock()
        pygame.display.flip()
        pygame.mouse.set_visible(False)
        while self._running :
            try :
                EventDispatcher.dispatchEvents()
                dirty = self.draw(pygame.display.get_surface())
                pygame.display.update(dirty)
                clock.tick(FRAMERATE)
            except KeyboardInterrupt :
                self.stop()
                raise
    
    def stop(self) :
        self._running = False
        pygame.mouse.set_visible(True)
        self.cursor._stopBlink()

    @event_handler(pygame.KEYDOWN)       
    def handleKeyDown(self, event) :
        if event.key in (pygame.K_q, pygame.K_ESCAPE) or \
            event.unicode == u'q' :
            self.stop()

    @event_handler(pygame.MOUSEMOTION)
    def onMouseMove(self, event) :
        for tile in reversed(self.sprites()[:-1]) :
            if tile.rect.collidepoint(*event.pos) :
                self.raiseTileOver(tile)
                break
    
    def raiseTileOver(self, tile) :
        if not tile.inflated :
            self.change_layer(tile, FOREGROUND_LAYER)
            tile.inflate(tile.coords)
            
            if self._inflatedTile :
                self._inflatedTile.deflate()
                self.change_layer(self._inflatedTile, BACKGROUND_LAYER)
            
            self._inflatedTile = tile
        
    @event_handler(pygame.MOUSEBUTTONDOWN)
    def selectInstrument(self, event) :
        for tile in reversed(self.sprites()[:-1]) :
            if tile.rect.collidepoint(*event.pos) :
                self.selectedInstrument = tile.instrumentDescription
                self.stop()
                break



class InstrumentTile(pygame.sprite.DirtySprite) :
    
    @staticmethod
    def _get_instrument_image(name) :
        imagePath = os.path.abspath(__file__).split(os.path.sep)[:-1]
        imagePath.extend(['data', 'instruments'])
        name, ext = os.path.splitext(name)
        imagePath.append('%s%s' % (name, ext or '.jpg'))
        return os.path.sep.join(imagePath)
    
    BORDER = 10
    INFLATE_ZOOM = 0.4

    def __init__(self, instrumentDescription, group, rect, coords) :
        pygame.sprite.DirtySprite.__init__(self, group)
        self.inflated = False
        self.instrumentDescription = instrumentDescription
        self.rect = rect
        self._baseRect = rect.copy()
        self.coords = coords
        imagePath = InstrumentTile._get_instrument_image(instrumentDescription['name'])
        self._img = pygame.image.load(imagePath)
        self.update()
    

    def update(self) :
        innerWidth, innerHeight = [l-self.BORDER*2 for l in self.rect.size]
        innerSize = innerWidth, innerHeight
        
        border = pygame.Surface(self.rect.size)
        border.fill((0xdd,0xdd,0xdd,255))
        
        bg = pygame.Surface(innerSize)
        bg.fill((255,255,255,255))
        bgRect = pygame.Rect((self.BORDER, self.BORDER), innerSize)

        img = self._img
        iWidth, iHeight = img.get_size()
        imgRatio = float(iWidth) / iHeight
        
        # adapts dimensions
        iw = innerWidth
        ih = int(round(innerWidth  / imgRatio))

        if ih > innerHeight:
            ih = innerHeight
            iw = int(round(innerHeight * imgRatio))
        
        imgPosition = ((innerWidth - iw) / 2, (innerHeight - ih) / 2)
        imgRect = pygame.Rect(imgPosition, (iw, ih))
        img = pygame.transform.smoothscale(img, (iw, ih))
        
        bg.blit(img, imgRect)
        border.blit(bg, bgRect)
        self.image = border
    

    def inflate(self, refPoint) :
        self.inflated = True
        keep = {}
        for name in REF_POINTS[refPoint] :
            keep[name] = getattr(self.rect, name)
        
        self.rect.inflate_ip(*[l*self.INFLATE_ZOOM for l in self.rect.size])
        
        for k, v in keep.items() :
            setattr(self.rect, k, v)
        
        self.update()
        self.dirty = 1
    

    def deflate(self) :
        self.inflated = False
        self.rect = self._baseRect.copy()
        self.update()
        self.dirty = 1
            


REF_POINTS = {
    (0, 0) : ['top', 'left'],
    (1, 0) : ['top'],
    (2, 0) : ['top', 'right'],

    (0, 1) : ['left'],
    (1, 1) : [],
    (2, 1) : ['right'],

    (0, 2) : ['bottom', 'left'],
    (1, 2) : ['bottom'],
    (2, 2) : ['bottom', 'right']
} 