'''
Created on 23 juil. 2009

@author: Samuel Benveniste
'''
from math import floor, ceil
import pygame
import sys
import colorsys
import constants
from gradients import gradients
from logging.PickleableEvent import PickleableEvent
from songs.Song import Song
from songs.musicxmltosong import Part


class SongPlayingScreen:
    '''
    The screen on which the game is played
    
        wiimotes: 
                The wiimotes used in this session
        window:
            The main display window
        screen:
            The main display surface
        clock:
            The clock used to animate the screen
        savedScreen:
            The background that is painted every time
        playerScreen:
            The buffer for painting everything before bliting
        width:
            The width of the window in pixels
        height:
            The height of the window in pixels
        extendScale :
            True if the scale is G to C instead of C to C
        cascade:
            True if crossing from note to note with a button pressed triggers a new note
        scaleSize:
            The size of the scale used
        cursorPositions:
            The positions of the cursors on the screen, in pixels
    '''
    
    
    
    def __init__(self, instrumentChoice, pguconf):# song, cascade=False, extendedScale=False, easyMode = False, alwaysDown = False, eventLog = None, replay = None, defaultInstrumentChannel = 16, defaultNote = 60):
        '''
        Constructor
        '''
        song = pguconf.song
        cascade = pguconf.cascade
        extendedScale = song.requiresExtendedScale
        easyMode = pguconf.easyMode
        alwaysDown = pguconf.alwaysDown
        eventLog = instrumentChoice.eventLog
        replay = instrumentChoice.replay
        defaultInstrumentChannel = 16
        defaultNote = 60

        if isinstance(song, Song) :
            self.songDurations = []
            self.totalDuration = None
            self.clicks = [0]
            self.clicksIn = [0]
            self.clicksPerMinute = [0]
            self.clicksInPerMinute = [0]
            self.meanTimeBetweenNotes = []
            self.firstClick = None
            self.firstClickIn = None
            
            self.blinkLength = 200
            self.minimalVelocity = 90
            self.shortScaleSize = 8
            self.longScaleSize = 11
            if not extendedScale:
                self.offset = self.longScaleSize - self.shortScaleSize
            else:
                self.offset = 0
            self.borderSize = 5
            self.highlightedNote = 0
            self.highlightedNoteNumber = 0
            self.syllabus = None
            self.savedHighlightedNote = 0
            self.alwaysDown = alwaysDown
            self.nextLevel = None
            
            self.wiimotes = instrumentChoice.wiimotes
            self.activeWiimotes = instrumentChoice.activeWiimotes
            self.window = instrumentChoice.window
            self.screen = instrumentChoice.screen
            self.blitOrigin = instrumentChoice.blitOrigin
            self.clock = instrumentChoice.clock
            self.width = instrumentChoice.width
            self.height = instrumentChoice.height
            self.cursorPositions = instrumentChoice.cursorPositions
            self.savedScreen = instrumentChoice.savedScreen
            self.playerScreen = instrumentChoice.playerScreen
            self.extendedScale = extendedScale
            self.cascade = cascade
            self.joys = instrumentChoice.joys
            self.portOffset = instrumentChoice.portOffset
            if eventLog == None :
                self.eventLog = instrumentChoice.eventLog
            else :
                self.eventLog = eventLog
            self.cursorPositions = instrumentChoice.cursorPositions
            self.song = song
            self.songIterator = self.song.getSongIterator()
            self.midiNoteNumbers = self.song.scale
            if replay == None :
                self.replay = instrumentChoice.replay
            else :
                self.replay = replay
            self.quarterNoteLength = song.quarterNoteLength
            self.cascadeLockLengthMultiplier = 1
            self.nextCascadeLockLengthMultiplier = 1
            self.cascadeLockLength = self.quarterNoteLength * self.cascadeLockLengthMultiplier
            
            self.defaultInstrumentChannel = defaultInstrumentChannel
            self.defaultNote = defaultNote
            
            self.done = False
            self.backToInstrumentChoice = False
            self.easyMode = easyMode
            
            #Initializes the highlightedNote and highlightedNoteNumber etc...
            self.moveToNextNote()
            self.cascadeLockLengthMultiplier = self.nextCascadeLockLengthMultiplier
            
            self.blinkOn = False
            self.savedBlinkOn = False
            ##Will prevent the song to move on if two consecutive notes are identical and the buttons have not been released in between the two
            ##i.e. it guarantees that there will be an attack between two identical consecutive notes
            self.highlightIsFree = True
            
            self.noteRects = []
            self.boundingRect = None
            self.notes = []
            
            self.buttonDown = []
            self.velocityLock = []
            
            self._blinkOffset = 0
            self._cascadeLockTimer = 0
            self.cascadeIsFree = True
            
            self.font = pygame.font.Font(None,80)
            self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.midiNoteNumbers]
            
            self.drawBackground()
            self.initializeWiimotes()
            
            self.songStartTime = self.eventLog.getCurrentTime()
            
            #The main loop
            while not self.done :
                
                #Clear the cursors from the screen
                if self.hasChanged():
                    self.drawBackground()
                self.playerScreen.blit(self.savedScreen, (0, 0))
                
                # Limit frame speed to 50 FPS
                #
                timePassed = self.clock.tick(10000)
                
                self._blinkOffset += timePassed
                if (self.buttonDown or self.alwaysDown) and not self.cascadeIsFree :
                    self._cascadeLockTimer += timePassed
                    if self._cascadeLockTimer > self.cascadeLockLengthMultiplier*self.quarterNoteLength :
                        self.cascadeIsFree = True
                        self.cascadeLockLengthMultiplier = self.nextCascadeLockLengthMultiplier
                
                
                if self._blinkOffset > self.blinkLength:
                    self._blinkOffset -= self.blinkLength
                    self.blinkOn = not self.blinkOn
                    
                if self.replay:
                    self.eventLog.update(timePassed)
                    pickledEventsToPost = self.eventLog.getPickledEvents() 
                    for pickledEvent in pickledEventsToPost:
                        pygame.event.post(pickledEvent.event)
                
                events = pygame.event.get()
                
                if not self.replay:
                    pickledEvents = [PickleableEvent(event.type,event.dict) for event in events]
                    if pickledEvents != [] :
                        self.eventLog.appendEventGroup(pickledEvents)
                
                for event in events:
                    self.input(event)
                                
                for i in range(len(self.wiimotes)):
                    if self.activeWiimotes[i]:
                        self.wiimotes[i].cursor.update(timePassed, self.cursorPositions[i])
                        if self.buttonDown[i] or self.alwaysDown:
                            self.wiimotes[i].cursor.flash()
                        self.wiimotes[i].cursor.blit(self.playerScreen)
                
                self.screen.blit(self.playerScreen, (0,0))
                
                pygame.display.flip()
            
            for i in range(len(self.wiimotes)):
                if self.activeWiimotes[i]:
                    self.wiimotes[i].stopNoteByNoteNumber(self.midiNoteNumbers[self.notes[i]])
            if self.replay :        
                self.totalDuration = self.eventLog.getCurrentTime()
        
        elif isinstance(song, Part) :
            self.songDurations = []
            self.totalDuration = None
            self.clicks = [0]
            self.clicksIn = [0]
            self.clicksPerMinute = [0]
            self.clicksInPerMinute = [0]
            self.meanTimeBetweenNotes = []
            self.firstClick = None
            self.firstClickIn = None
            
            self.blinkLength = 200
            self.minimalVelocity = 90
            self.shortScaleSize = 8
            self.longScaleSize = 11
            if not extendedScale:
                self.offset = self.longScaleSize - self.shortScaleSize
            else:
                self.offset = 0
            self.borderSize = 5
            self.highlightedNote = 0
            self.highlightedNoteNumber = 0
            self.syllabus = None
            self.savedHighlightedNote = 0
            self.alwaysDown = alwaysDown
            self.nextLevel = None
            
            self.wiimotes = instrumentChoice.wiimotes
            self.activeWiimotes = instrumentChoice.activeWiimotes
            self.window = instrumentChoice.window
            self.screen = instrumentChoice.screen
            self.blitOrigin = instrumentChoice.blitOrigin
            self.clock = instrumentChoice.clock
            self.width = instrumentChoice.width
            self.height = instrumentChoice.height
            self.cursorPositions = instrumentChoice.cursorPositions
            self.savedScreen = instrumentChoice.savedScreen
            self.playerScreen = instrumentChoice.playerScreen
            self.extendedScale = extendedScale
            self.cascade = cascade
            self.joys = instrumentChoice.joys
            self.portOffset = instrumentChoice.portOffset
            if eventLog == None :
                self.eventLog = instrumentChoice.eventLog
            else :
                self.eventLog = eventLog
            self.cursorPositions = instrumentChoice.cursorPositions
            self.song = song
            self.songIterator = self.song.iterNotes()
            self.midiNoteNumbers = self.song.scale
            if replay == None :
                self.replay = instrumentChoice.replay
            else :
                self.replay = replay
            self.quarterNoteLength = song.quarterNoteLength
            self.cascadeLockLengthMultiplier = 1
            self.nextCascadeLockLengthMultiplier = 1
            self.cascadeLockLength = self.quarterNoteLength * self.cascadeLockLengthMultiplier
            
            self.defaultInstrumentChannel = defaultInstrumentChannel
            self.defaultNote = defaultNote
            
            self.done = False
            self.backToInstrumentChoice = False
            self.easyMode = easyMode
            
            #Initializes the highlightedNote and highlightedNoteNumber etc...
            self.moveToNextNote()
            self.cascadeLockLengthMultiplier = self.nextCascadeLockLengthMultiplier
            
            self.blinkOn = False
            self.savedBlinkOn = False
            ##Will prevent the song to move on if two consecutive notes are identical and the buttons have not been released in between the two
            ##i.e. it guarantees that there will be an attack between two identical consecutive notes
            self.highlightIsFree = True
            
            self.noteRects = []
            self.boundingRect = None
            self.notes = []
            
            self.buttonDown = []
            self.velocityLock = []
            
            self._blinkOffset = 0
            self._cascadeLockTimer = 0
            self.cascadeIsFree = True
            
            self.font = pygame.font.Font(None,80)
            self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.midiNoteNumbers]
            
            self.drawBackground()
            self.initializeWiimotes()
            
            self.songStartTime = self.eventLog.getCurrentTime()
            
            #The main loop
            while not self.done :
                
                #Clear the cursors from the screen
                if self.hasChanged():
                    self.drawBackground()
                self.playerScreen.blit(self.savedScreen, (0, 0))
                
                # Limit frame speed to 50 FPS
                #
                timePassed = self.clock.tick(10000)
                
                self._blinkOffset += timePassed
                if (self.buttonDown or self.alwaysDown) and not self.cascadeIsFree :
                    self._cascadeLockTimer += timePassed
                    if self._cascadeLockTimer > self.cascadeLockLengthMultiplier*self.quarterNoteLength :
                        self.cascadeIsFree = True
                        self.cascadeLockLengthMultiplier = self.nextCascadeLockLengthMultiplier
                
                
                if self._blinkOffset > self.blinkLength:
                    self._blinkOffset -= self.blinkLength
                    self.blinkOn = not self.blinkOn
                    
                if self.replay:
                    self.eventLog.update(timePassed)
                    pickledEventsToPost = self.eventLog.getPickledEvents() 
                    for pickledEvent in pickledEventsToPost:
                        pygame.event.post(pickledEvent.event)
                
                events = pygame.event.get()
                
                if not self.replay:
                    pickledEvents = [PickleableEvent(event.type,event.dict) for event in events]
                    if pickledEvents != [] :
                        self.eventLog.appendEventGroup(pickledEvents)
                
                for event in events:
                    self.input(event)
                                
                for i in range(len(self.wiimotes)):
                    if self.activeWiimotes[i]:
                        self.wiimotes[i].cursor.update(timePassed, self.cursorPositions[i])
                        if self.buttonDown[i] or self.alwaysDown:
                            self.wiimotes[i].cursor.flash()
                        self.wiimotes[i].cursor.blit(self.playerScreen)
                
                self.screen.blit(self.playerScreen, (0,0))
                
                pygame.display.flip()
            
            for i in range(len(self.wiimotes)):
                if self.activeWiimotes[i]:
                    self.wiimotes[i].stopNoteByNoteNumber(self.midiNoteNumbers[self.notes[i]])
            if self.replay :        
                self.totalDuration = self.eventLog.getCurrentTime()
        
    def drawBackground(self):
        self.savedScreen.fill((255,255,255))
        
        if self.extendedScale :
            self.scaleSize = self.longScaleSize
        else:
            self.scaleSize = self.shortScaleSize
        
        self.noteRects = [pygame.Rect(i * self.width / self.scaleSize+self.blitOrigin[0], self.blitOrigin[1], self.width / self.scaleSize + 1, self.height+1) for i in range(self.scaleSize)]
        #inflate last noteRect to cover the far right pixels
        self.noteRects[-1].width = self.noteRects[-1].width + 1
        
        self.noteRects[self.highlightedNote-self.offset].inflate_ip(self.noteRects[self.highlightedNote-self.offset].width*2,0)
        
        #create bounding rect
        self.boundingRect = self.noteRects[0].unionall(self.noteRects)
        
        self.renderedNoteNames = [self.font.render(constants.noteNumberToName(note),False,(0,0,0)) for note in self.midiNoteNumbers]
        
        #fill the rectangles with a color gradient
        #We start with blue
        startingHue = 0.66666666666666663
        
        for rectNumber in range(self.scaleSize):
            colorRatio = float(rectNumber) / (self.scaleSize - 1)
            #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up
            hue = startingHue * (1 - colorRatio)
            if rectNumber + self.offset != self.highlightedNote:
                #The color of the bottom of the rectangle in hls coordinates
                bottomColorHls = (hue, 0.1, 1)
                #The color of the top of the rectangle in hls coordinates
                topColorHls = (hue, 0.1, 1)
            
                #convert to rgb ranging from 0 to 255
                bottomColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*bottomColorHls)]
                topColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*topColorHls)]
                #add transparency
                bottomColorRgb.append(255)
                topColorRgb.append(255)
                #convert to tuple
                bottomColorRgb = tuple(bottomColorRgb)
                topColorRgb = tuple(topColorRgb)            
                
                self.savedScreen.blit(gradients.vertical(self.noteRects[rectNumber].size, topColorRgb, bottomColorRgb), self.noteRects[rectNumber])
                
                noteNameBlitPoint = (self.noteRects[rectNumber].left+(self.noteRects[rectNumber].width-self.renderedNoteNames[rectNumber+self.offset].get_width())/2,
                                 self.noteRects[rectNumber].bottom-self.renderedNoteNames[rectNumber+self.offset].get_height())
                
                self.savedScreen.blit(self.renderedNoteNames[rectNumber+self.offset], noteNameBlitPoint)
                
                pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), self.noteRects[rectNumber], 2)
        
        colorRatio = float(self.highlightedNote-self.offset) / (self.scaleSize - 1)
        #hue will go from 0.6666... (blue) to 0 (red) as colorRation goes up
        hue = startingHue * (1 - colorRatio)
        #The color of the bottom of the rectangle in hls coordinates
        bottomColorHls = (hue, 0.6, 1)
        #The color of the top of the rectangle in hls coordinates
        topColorHls = (hue, 0.9, 1)
        
        #convert to rgb ranging from 0 to 255
        bottomColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*bottomColorHls)]
        topColorRgb = [floor(255 * i) for i in colorsys.hls_to_rgb(*topColorHls)]
        #add transparency
        bottomColorRgb.append(255)
        topColorRgb.append(255)
        #convert to tuple
        bottomColorRgb = tuple(bottomColorRgb)
        topColorRgb = tuple(topColorRgb)            
        
        self.savedScreen.blit(gradients.vertical(self.noteRects[self.highlightedNote-self.offset].size, topColorRgb, bottomColorRgb), self.noteRects[self.highlightedNote-self.offset])
        
        noteNameBlitPoint = (self.noteRects[self.highlightedNote-self.offset].left+(self.noteRects[self.highlightedNote-self.offset].width-self.renderedNoteNames[self.highlightedNote].get_width())/2,
                         self.noteRects[self.highlightedNote-self.offset].bottom-self.renderedNoteNames[self.highlightedNote].get_height())
        
        self.savedScreen.blit(self.renderedNoteNames[self.highlightedNote], noteNameBlitPoint)
        
        if self.syllabus :
            renderedSyllabus = self.font.render(self.syllabus,False,(0,0,0))
        
            syllabusBlitPoint = (self.noteRects[self.highlightedNote-self.offset].left+(self.noteRects[self.highlightedNote-self.offset].width-renderedSyllabus.get_width())/2,
                             self.noteRects[self.highlightedNote-self.offset].centery-renderedSyllabus.get_height()/2)
            
            self.savedScreen.blit(renderedSyllabus, syllabusBlitPoint)
        
        pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 255), self.noteRects[self.highlightedNote-self.offset], 2)    
            
        if self.song != None and self.blinkOn:
            borderSize = self.borderSize
            pygame.draw.rect(self.savedScreen, pygame.Color(0, 0, 0, 0), self.noteRects[self.highlightedNote-self.offset].inflate(borderSize/2,borderSize/2), borderSize)
        
    def initializeWiimotes(self):
        for loop in self.wiimotes:
            if loop.port == None :
                loop.port = pygame.midi.Output(loop.portNumber)
            self.notes.append(0)
            self.buttonDown.append(False)
            self.velocityLock.append(False)
    
    def updateCursorPositionFromJoy(self, joyEvent):
        joyName = pygame.joystick.Joystick(joyEvent.joy).get_name()
        correctedJoyId = constants.joyNames.index(joyName)
        if correctedJoyId < len(self.cursorPositions):
            if joyEvent.axis == 0 :
                self.cursorPositions[correctedJoyId] = (int((joyEvent.value + 1) / 2 * self.screen.get_width()), self.cursorPositions[correctedJoyId][1])
            if joyEvent.axis == 1 :
                self.cursorPositions[correctedJoyId] = (self.cursorPositions[correctedJoyId][0], int((joyEvent.value + 1) / 2 * self.screen.get_height()))
    
    def heightToVelocity(self, pos, controllerNumber):
        if self.song != None:
            if self.boundingRect.collidepoint(pos) and (self.highlightedNote == self.notes[controllerNumber] or self.velocityLock[controllerNumber]):
                velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity)
            else :
                if self.easyMode:
                    velocity = None
                else:
                    velocity = 60
        else:
            if self.boundingRect.collidepoint(pos):
                velocity = int(floor((1 - (float(pos[1])-self.blitOrigin[1]) / self.height) * (127-self.minimalVelocity))+self.minimalVelocity)
            else :
                velocity = self.minimalVelocity
        return(velocity)
    
    def widthToNote(self, pos):
        nn = 0
        try :
            if self.noteRects[self.highlightedNote-self.offset].collidepoint(pos) :
                return self.highlightedNote
            else :
                while self.noteRects[nn].collidepoint(pos) == False:
                    nn = nn + 1
                return(nn + self.offset)
        except(IndexError):
            return(None)
    
    def logClick(self):
        self.clicks[-1] += 1
        if self.firstClick == None :
            self.firstClick = self.eventLog.getCurrentTime()
        minute = int(floor((self.eventLog.getCurrentTime()-self.songStartTime)/60000))
        if minute > len(self.clicksPerMinute)-1:
            self.clicksPerMinute.append(0)
        self.clicksPerMinute[-1] += 1
    
    def logClickIn(self):
        self.clicksIn[-1] += 1
        if self.clicksIn[-1] > len(self.song.notes)-1 :
            self.clicksIn.append(0)
            self.clicks.append(0)
            self.songDurations.append(self.eventLog.getCurrentTime())
        if self.firstClickIn == None :
            self.firstClickIn = self.eventLog.getCurrentTime()
        minute = int(floor((self.eventLog.getCurrentTime()-self.songStartTime)/60000))
        if minute > len(self.clicksInPerMinute)-1:
            self.clicksInPerMinute.append(0)
        self.clicksInPerMinute[-1]+=1
    
    def input(self, event): 
        
        if event.type == pygame.QUIT:
            for loop in self.wiimotes:
                del loop.port
            pygame.midi.quit()
            sys.exit(0) 
        
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q:
                self.nextLevel = None
                self.done = True
                
            if event.key == pygame.K_i:
                self.backToInstrumentChoice = True
                self.done = True
                
            if event.key == pygame.K_w:
                self.nextLevel = 0
                self.done = True
                
            if event.key == pygame.K_e:
                self.nextLevel = 1
                self.done = True
                
            if event.key == pygame.K_r:
                self.nextLevel = 2
                self.done = True
                
            if event.key == pygame.K_t:
                self.nextLevel = 3
                self.done = True 
        
        if event.type == pygame.JOYAXISMOTION:
            
            joyName = pygame.joystick.Joystick(event.joy).get_name()
            correctedJoyId = constants.joyNames.index(joyName)
            if self.activeWiimotes[correctedJoyId]:
                self.updateCursorPositionFromJoy(event)
                wiimote = self.wiimotes[correctedJoyId]
                pos = self.cursorPositions[correctedJoyId]
    
                if (self.buttonDown[correctedJoyId] or self.alwaysDown):
                    if self.notes[correctedJoyId] != None:
                        velocity = self.heightToVelocity(pos, correctedJoyId)
                        if velocity != None :
                            CCHexCode = wiimote.getCCHexCode()
                            wiimote.port.write_short(CCHexCode, 07, velocity)
                    if self.cascade and self.cascadeIsFree :
                        n = self.widthToNote(pos)
                        if self.highlightedNote == n:
                            wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]])
                            self.notes[correctedJoyId] = n
                            velocity = self.heightToVelocity(pos, correctedJoyId)
                            self.velocityLock[correctedJoyId] = True
                            wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity)
                            self.moveToNextNote()
                            self._cascadeLockTimer = 0
                            self.cascadeIsFree = False
        
        if event.type == pygame.JOYBUTTONDOWN :
            
            joyName = pygame.joystick.Joystick(event.joy).get_name()
            correctedJoyId = constants.joyNames.index(joyName)
            if self.activeWiimotes[correctedJoyId]:
                wiimote = self.wiimotes[correctedJoyId]
                pos = self.cursorPositions[correctedJoyId]
                self.wiimotes[correctedJoyId].cursor.flash()
                if self.replay:
                    self.logClick()
                    
                if not (self.buttonDown[correctedJoyId] or self.alwaysDown):
                    n = self.widthToNote(pos)
                    if self.highlightedNote == n:
                        self._cascadeLockTimer = 0
                        self.cascadeIsFree = False
                        if self.easyMode:
                            wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]])
                        self.notes[correctedJoyId] = n
                        velocity = self.heightToVelocity(pos, correctedJoyId)
                        self.velocityLock[correctedJoyId] = True
                        wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity)
                        if self.replay :
                            self.logClickIn()
                        self.moveToNextNote()
                    else :
                        if not self.easyMode :
                            self._cascadeLockTimer = 0
                            self.cascadeIsFree = False
                            self.notes[correctedJoyId] = n
                            velocity = self.heightToVelocity(pos, correctedJoyId)                    
                            if velocity != None and self.notes[correctedJoyId] != None :
                                wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity)                                      
                    self.buttonDown[correctedJoyId] = True
            
        if event.type == pygame.JOYBUTTONUP:
            joyName = pygame.joystick.Joystick(event.joy).get_name()
            correctedJoyId = constants.joyNames.index(joyName)
            if self.activeWiimotes[correctedJoyId]:
                self.buttonDown[correctedJoyId] = False
                wiimote = self.wiimotes[correctedJoyId]
                if not self.easyMode:
                    wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]])
                self.velocityLock[correctedJoyId] = False
            
        if event.type == pygame.MOUSEMOTION:
            
            self.updateCursorPositionFromMouse(event)
            
            correctedJoyId = 0
            while not self.activeWiimotes[correctedJoyId] :
                correctedJoyId += 1
            wiimote = self.wiimotes[correctedJoyId]
            pos = self.cursorPositions[correctedJoyId]

            if (self.buttonDown[correctedJoyId] or self.alwaysDown):
                self.wiimotes[correctedJoyId].cursor.flash()
                if self.notes[correctedJoyId] != None:
                    velocity = self.heightToVelocity(pos, correctedJoyId)
                    if velocity != None :
                        CCHexCode = wiimote.getCCHexCode()
                        wiimote.port.write_short(CCHexCode, 07, velocity)
                if self.cascade and self.cascadeIsFree :
                    n = self.widthToNote(pos)
                    if self.highlightedNote == n:
                        wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]])
                        self.notes[correctedJoyId] = n
                        velocity = self.heightToVelocity(pos, correctedJoyId)
                        self.velocityLock[correctedJoyId] = True
                        wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity)
                        self.moveToNextNote()
                        self._cascadeLockTimer = 0
                        self.cascadeIsFree = False             
        
        if event.type == pygame.MOUSEBUTTONDOWN:
            
            if event.button == 1:
                correctedJoyId = 0
                while not self.activeWiimotes[correctedJoyId] :
                    correctedJoyId += 1
                wiimote = self.wiimotes[correctedJoyId]
                pos = self.cursorPositions[correctedJoyId]
                self.wiimotes[correctedJoyId].cursor.flash()
                if self.replay:
                    self.logClick()
                    
                if not (self.buttonDown[correctedJoyId] or self.alwaysDown):
                    n = self.widthToNote(pos)
                    if self.highlightedNote == n:
                        self._cascadeLockTimer = 0
                        self.cascadeIsFree = False
                        if self.easyMode:
                            wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]])
                        self.notes[correctedJoyId] = n
                        velocity = self.heightToVelocity(pos, correctedJoyId)
                        self.velocityLock[correctedJoyId] = True
                        wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity)
                        if self.replay :
                            self.logClickIn()
                        self.moveToNextNote()
                    else :
                        if not self.easyMode :
                            self._cascadeLockTimer = 0
                            self.cascadeIsFree = False
                            self.notes[correctedJoyId] = n
                            velocity = self.heightToVelocity(pos, correctedJoyId)                    
                            if velocity != None and self.notes[correctedJoyId] != None :
                                wiimote.playNoteByNoteNumber(self.midiNoteNumbers[self.notes[correctedJoyId]],velocity)                                      
                    self.buttonDown[correctedJoyId] = True                    
            
            if event.button == 2:
                
                self.done = True
        
        if event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1 :
                correctedJoyId = 0
                while not self.activeWiimotes[correctedJoyId] :
                    correctedJoyId += 1
                wiimote = self.wiimotes[correctedJoyId]
                self.buttonDown[correctedJoyId] = False
                if not self.easyMode:
                    if self.notes[correctedJoyId] != None :
                        wiimote.stopNoteByNoteNumber(self.savedMidiNoteNumbers[self.notes[correctedJoyId]])
                self.velocityLock[correctedJoyId] = False
        
    def hasChanged(self):
        changed = False
        if self.song != None:
            if self.blinkOn != self.savedBlinkOn or self.highlightedNote != self.savedHighlightedNote:
                self.savedBlinkOn = self.blinkOn
                self.savedHighlightedNote = self.highlightedNote
                changed = True
        return(changed)
    
    def updateCursorPositionFromMouse(self, mouseEvent):
        correctedJoyId = 0
        while not self.activeWiimotes[correctedJoyId] :
            correctedJoyId += 1
        self.cursorPositions[correctedJoyId] = mouseEvent.pos
        
    def moveToNextNote(self):
        self.savedMidiNoteNumbers = self.midiNoteNumbers[:]
        note, lyricIndex = self.songIterator.next()
        self.highlightedNote = note.column
        self.highlightedNoteNumber = note.midi
        self.syllabus = note.lyrics[lyricIndex].syllabus('iso-8859-1')
        self.nextCascadeLockLengthMultiplier = note.duration
        self.midiNoteNumbers[self.highlightedNote] = self.highlightedNoteNumber
        
        #self.highlightedNote, self.highlightedNoteNumber, self.syllabus, self.nextCascadeLockLengthMultiplier = self.songIterator.next()
        #self.midiNoteNumbers[self.highlightedNote] = self.highlightedNoteNumber
