'''
Created on 15 juil. 2009

@author: Samuel Benveniste
'''

import pygame
import pygame.midi
import sys
import time
import pickle

from numpy import array
from numpy.linalg import norm

from math import floor

from gui.constants import *
from PlayingScreen import PlayingScreen
from instruments.Instrument import Instrument
from cursor.WarpingCursor import *
from controllers.Wiimote import Wiimote
from logging.EventLog import EventLog
from logging.PickleableEvent import PickleableEvent 

class InstrumentChoice:
    '''
    The screen for choosing instruments
    
        instruments: 
                The available instruments            
        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
        done:
            Goes to True when all instruments have been selected
        cursorPositions:
            The positions of the cursors on the screen, in pixels
        imageRects:
            The rectangles where the images of the instruments are located
        focus:
            The numbers of the instruments currently in focus
    '''
    
    def __init__(self, instruments, wiimotes, window, screen, clock, joys, portOffset, activeWiimotes, eventLog=None, replay = False, logFilePath = None, scaleFactor = 1):
        '''
        Constructor
        
            instruments: 
                The instruments for this session           
            wiimotes: 
                The wiimotes used in this session
        '''
        self.scaleFactor = scaleFactor
        
        self.instruments = instruments
        self.wiimotes = wiimotes
        self.window = window
        self.screen = screen
        self.clock = clock
        self.width = int(floor(screen.get_width()*self.scaleFactor))
        self.height = int(floor(screen.get_height()*self.scaleFactor))
        self.blitOrigin = ((self.screen.get_width()-self.width)/2,(self.screen.get_height()-self.height)/2)        
        self.joys = joys
        self.portOffset = portOffset
        
        self.activeWiimotes = activeWiimotes
        
        self.currentWiimote = 0
        while not self.activeWiimotes[self.currentWiimote] :
            self.currentWiimote += 1
        self.done = False        
        
        self.cursorPositions = []
        self.imageRects = []
        self.savedImageRects = []
        self.focus = []
        self.zoomed = []
        
        if eventLog == None:
            self.eventLog = EventLog()
            self.replay = False
        else:
            self.eventLog = eventLog
            self.replay = replay
            print self.replay
                
        #There are 3 instruments per row, up to 9 instruments
        #Draw their images on the screen
        self.savedScreen = pygame.Surface(self.screen.get_size())
        self.savedScreen.fill((255, 255, 255))
        for i in range(len(self.instruments)) :
            drawPos = array([(self.width / 3) * (i % 3), (self.height / 3) * (i / 3)])
            curImage = pygame.image.load(self.instruments[i].image).convert_alpha()
            scaledImage = pygame.transform.smoothscale(curImage, (self.width / 3, self.height / 3))
            self.imageRects.append(self.savedScreen.blit(scaledImage, drawPos + self.blitOrigin))
            self.savedImageRects = self.imageRects[:]
        #Draw the initial cursor on the buffer
        self.playerScreen = pygame.Surface(self.savedScreen.get_size())
        self.playerScreen.blit(self.savedScreen, (0, 0))
        
        for i in range(len(self.wiimotes)):
            #Create the list of instrument focus (one focus per wiimote)
            self.focus.append(0)
            self.zoomed.append(None)
            #Set the screen for the cursors (it can't be set before)
            self.wiimotes[i].cursor.screen = self.playerScreen
            self.cursorPositions.append(self.wiimotes[i].cursor.centerPosition)
            
        self.wiimotes[self.currentWiimote].cursor.blit(self.playerScreen)
        
        #The main loop
        while self.done == False :
            
            #Clear the cursors from the screen
            self.playerScreen.blit(self.savedScreen, (0, 0))
            
            # Limit frame speed to 50 FPS
            #
            timePassed = self.clock.tick(50)
            
            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 self.eventFilter(event)]
                if pickledEvents != [] :
                    self.eventLog.appendEventGroup(pickledEvents)
            
            for event in events:
                self.input(event)
                            
        
            if self.zoomed[self.currentWiimote] != None :
                self.imageRects = self.savedImageRects[:]
                #inflate the chosen rect
                zoomedRectNumber = self.zoomed[self.currentWiimote]
                newRect = zoomRect(self.imageRects[zoomedRectNumber], 1.3)
                self.imageRects[zoomedRectNumber] = newRect
                curImage = pygame.image.load(self.instruments[zoomedRectNumber].image).convert_alpha()
                self.scaledImage = pygame.transform.smoothscale(curImage, newRect.size)
                self.playerScreen.blit(self.scaledImage, newRect.topleft)
            
            for i in range(len(self.wiimotes)):
                self.wiimotes[i].cursor.update(timePassed, self.cursorPositions[i])
                
            self.wiimotes[self.currentWiimote].cursor.blit(self.playerScreen)                
            
            if self.zoomed[self.currentWiimote] != None and self.imageRects[self.zoomed[self.currentWiimote]].collidepoint(self.cursorPositions[self.currentWiimote]):
                self.focus[self.currentWiimote] = self.zoomed[self.currentWiimote]
                pygame.draw.rect(self.playerScreen, pygame.Color(0, 255, 0, 255), self.imageRects[self.zoomed[self.currentWiimote]], 10)
            else:
                for i in range(len(self.imageRects)) :
                    if self.imageRects[i].collidepoint(self.cursorPositions[self.currentWiimote]):
                        self.focus[self.currentWiimote] = i
                        pygame.draw.rect(self.playerScreen, pygame.Color(0, 255, 0, 255), self.imageRects[i], 10)
                        if self.zoomed[self.currentWiimote] != None:
                            self.playerScreen.blit(self.scaledImage, self.imageRects[self.zoomed[self.currentWiimote]].topleft)
            
            self.screen.blit(self.playerScreen, (0, 0))
            
            pygame.display.flip()
            
    def input(self, event):
        if event.type == pygame.QUIT:
            pygame.midi.quit()
            sys.exit()
        if event.type == pygame.JOYAXISMOTION:
            self.updateCursorPositionFromJoy(event)
        if event.type == pygame.JOYBUTTONDOWN :
            self.assignInstrumentToWiimote(event)
        if event.type == pygame.MOUSEBUTTONDOWN:
            if self.zoomed[self.currentWiimote] == self.focus[self.currentWiimote]:
                self.assignInstrumentToMouse(event)
            else:
                self.zoomed[self.currentWiimote] = self.focus[self.currentWiimote]
        if event.type == pygame.MOUSEMOTION:
            self.updateCursorPositionFromMouse(event)            
                     
    def updateCursorPositionFromJoy(self, joyEvent):
        joyName = pygame.joystick.Joystick(joyEvent.joy).get_name()
        print joyName
        correctedJoyId = joyNames.index(joyName)
        if self.activeWiimotes[correctedJoyId]: 
            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 assignInstrumentToWiimote(self, joyEvent):
        joyName = pygame.joystick.Joystick(joyEvent.joy).get_name()
        correctedJoyId = joyNames.index(joyName)
        if self.activeWiimotes[correctedJoyId]:
            if self.zoomed[correctedJoyId] == self.focus[correctedJoyId]:
                self.wiimotes[correctedJoyId].instrument = self.instruments[self.focus[correctedJoyId]]
                self.zoomed[correctedJoyId] = None
                self.imageRects = self.savedImageRects[:]
                if self.currentWiimote<len(self.wiimotes)-1:
                    self.currentWiimote = self.currentWiimote+1
            else:
                self.zoomed[correctedJoyId] = self.focus[correctedJoyId]
            if self.hasFinished():
                self.done = True
    
    def updateCursorPositionFromMouse(self, mouseEvent):
        correctedJoyId = 0
        while not self.activeWiimotes[correctedJoyId] :
            correctedJoyId += 1
        self.cursorPositions[correctedJoyId] = mouseEvent.pos
    
    def assignInstrumentToMouse(self, mouseEvent):
        correctedJoyId = 0
        while not self.activeWiimotes[correctedJoyId] :
            correctedJoyId += 1
        self.wiimotes[correctedJoyId].instrument = self.instruments[self.focus[correctedJoyId]]
        if self.hasFinished():
            self.done = True
    
    def hasFinished(self):
        finished = True
        for i in range(len(self.wiimotes)):
            if self.wiimotes[i].instrument == None and self.activeWiimotes[i]:
                finished = False
        return(finished)
    
    def eventFilter(self, event):
        c = event.type
        if c == 17:
            return False
        elif c == pygame.MOUSEMOTION or pygame.MOUSEBUTTONDOWN or pygame.MOUSEBUTTONUP or pygame.JOYAXISMOTION or pygame.JOYBUTTONDOWN or pygame.JOYBUTTONUP or pygame.KEYDOWN:
            return True
        else:
            return False

def zoomRect(rect, ratio):
    zoomedRect = rect.inflate(int(floor((ratio - 1) * rect.width)), int(floor((ratio - 1) * rect.height)))
    return(zoomedRect)        

if __name__ == "__main__":
    pygame.init()
    #pygame.event.set_blocked([pygame.MOUSEBUTTONDOWN,pygame.MOUSEBUTTONUP,pygame.MOUSEMOTION])
    
    pygame.midi.init()
    instruments = [Instrument(majorScale, i + 1, "".join(["../instruments/instrumentImages/", instrumentImagePathList[i], ".jpg"]), octaves[i]) for i in range(9)]
    
    joys = [pygame.joystick.Joystick(id).get_name() for id in range(pygame.joystick.get_count())]
    joyOffset = joys.index(joyNames[0])
    pygame.joystick.Joystick(joyOffset).init()
    print(joyOffset)  
    
    ports = [pygame.midi.get_device_info(id)[1] for id in range(pygame.midi.get_count())]
    portOffset = ports.index(portNames[0])
    print(portOffset)
    
    window = pygame.display.set_mode((1280, 1024),pygame.FULLSCREEN)
    screen = pygame.display.get_surface()
    clock = pygame.time.Clock()        
    cursorImages = createImageListFromPath('../cursor/cursorImages/black', 11)
    durations = [75 for i in range(len(cursorImages))]
    
    extsc = False
    casc = False
    
    jadbt = [3, 4, 5, 3, 4, 4, 5, 6, 6, 5, 3, 3, 4, 5, 3, 4, 4, 5, 6, 7, 3]
    song = None
    
    cursors = [WarpingCursor(None, cursorImages, durations, (300 * i, 300 * i)) for i in range(1)]
    wiimotes = [Wiimote(i, i + portOffset, None, None, cursors[i]) for i in range(1)]
    choice = InstrumentChoice(instruments, wiimotes, window, screen, clock, joyOffset, portOffset)
    play = PlayingScreen(choice, song, casc, extsc)
    for wiimote in wiimotes:
        del wiimote.port            
        
    f = file('temp.pkl', 'w')
    pickler = pickle.Pickler(f)
    pickler.dump(play.eventLog.eventGroups)
    pickler.dump(play.eventLog.times)
    f.close()
    
    f = file('temp.pkl', 'r')
    unpickler = pickle.Unpickler(f)
    eventGroups = unpickler.load()
    times = unpickler.load()
    f.close()
    eventLog = EventLog(eventGroups,times)
    
    cursors = [WarpingCursor(None, cursorImages, durations, (300 * i, 300 * i)) for i in range(1)]
    wiimotes = [Wiimote(i, i + portOffset, None, None, cursors[i]) for i in range(1)]
    choice2 = InstrumentChoice(instruments, wiimotes, window, screen, clock, joyOffset, portOffset, eventLog)
    play = PlayingScreen(choice2, song, casc, extsc)
    
    for wiimote in wiimotes:
        del wiimote.port
    
    pygame.midi.quit()
    sys.exit()
