# -*- coding: utf-8 -*-
"""
Curseurs winwii

$Id$
$URL$
"""

import pygame
import os
from threading import Thread
import time
from minwii.eventutils import EventHandlerMixin, event_handler
from itertools import cycle

class WarpingCursor(pygame.sprite.DirtySprite, EventHandlerMixin):
    '''
    The class for animating the warping cursor
    '''

    @staticmethod
    def _get_theme_images(name) :
        basePath = os.path.abspath(__file__).split(os.path.sep)[:-1]
        basePath.extend(['data', 'cursor'])
        basePath.append(name)
        basePath = os.path.sep.join(basePath)
        images = [f for f in os.listdir(basePath) if os.path.splitext(f)[1] == '.png']
        return basePath, images

    
    def __init__(self, theme='black-perforated', duration=100, blinkMode=True):
        pygame.sprite.DirtySprite.__init__(self)
        imagesPath, images = WarpingCursor._get_theme_images(theme)
        flashImage = images.pop(images.index('flash.png'))
        flashImagePath = os.path.sep.join([imagesPath, flashImage]) 
        self.flashImage = pygame.image.load(flashImagePath).convert_alpha()
        images.sort(lambda a, b : cmp(*[int(os.path.splitext(f)[0]) for f in [a, b]]))
        
        self.images = []
        for img in images :
            imagePath = os.path.sep.join([imagesPath, img])
            img = pygame.image.load(imagePath).convert_alpha()
            self.images.append(img)
        
        # assumes that all images have same dimensions
        self.width = self.images[0].get_width()
        self.height = self.images[0].get_height()
        self.duration = duration
        
        self.image = self.images[0]
        self.pressed = False
        # workarround cursor alignement problem
        pygame.event.set_blocked(pygame.MOUSEMOTION)
        pygame.mouse.set_pos(pygame.mouse.get_pos())
        pygame.event.set_allowed(pygame.MOUSEMOTION)
        # ---
        x, y = pygame.mouse.get_pos()
        left = x - self.width / 2
        top = y - self.height / 2
        self.rect = pygame.Rect((left, top), (self.width, self.height))
        
        self.blinkMode = blinkMode
        self._startBlink()
    
    def __del__(self) :
        if hasattr(self, 'timer') :
            try : self.timer.stop()
            except : pass
    
    def _startBlink(self) :
        if self.blinkMode :
            self._blinking = True
            self.iterator = self.iterImages()
            self.timer = ForeverTimer(self.duration, self.loadNext)
            self.timer.start()
    
    def _stopBlink(self) :
        if self.blinkMode :
            self.timer.stop()
            
    def iterImages(self) :
        for img in cycle(self.images) :
            yield img
    
    def loadNext(self) :
        if self._blinking :
            self.dirty = 1
            self.image = self.iterator.next()
    
    @event_handler(pygame.MOUSEBUTTONDOWN)
    def flashOn(self, event) :
        self.dirty = 1
        self._blinking = False
        self.image = self.flashImage
        self.pressed = True

    @event_handler(pygame.MOUSEBUTTONUP)
    def flashOff(self, event) :
        self.dirty = 1
        if self.blinkMode :
            self._blinking = True
        else :
            self.image = self.images[0]
        self.pressed = False
    
    @event_handler(pygame.MOUSEMOTION)
    def move(self, event) :
        self.dirty = 1
        x, y = pygame.mouse.get_pos()
        rel = (x - self.rect.centerx, y - self.rect.centery)
        self.rect.move_ip(rel)
    
    def setPosition(self, pos) :
        self.dirty = 1
        x, y = pos
        rx, ry = self.rect.centerx, self.rect.centery
        self.rect.move_ip(x-rx, y-ry)


class ForeverTimer(Thread) :
    def __init__(self, duration, func, *args, **kw) :
        Thread.__init__(self)
        self.duration = duration / 1000.
        self.func = func
        self.args = args
        self.kw = kw
        self.running = True

    def run(self) :
        while self.running :
            self.func(*self.args, **self.kw)
            time.sleep(self.duration)
    
    def stop(self) :
        self.running = False
