import threading
import time

import numpy as np

import pygame as pg
from moviepy.decorators import convert_masks_to_RGB, requires_duration
from moviepy.tools import cvsecs

pg.init()
pg.display.set_caption('MoviePy')


def imdisplay(imarray, screen=None):
    """Splashes the given image array on the given pygame screen """
    a = pg.surfarray.make_surface(imarray.swapaxes(0, 1))
    if screen is None:
        screen = pg.display.set_mode(imarray.shape[:2][::-1])
    screen.blit(a, (0, 0))
    pg.display.flip()


@convert_masks_to_RGB
def show(clip, t=0, with_mask=True, interactive=False):
    """
    Splashes the frame of clip corresponding to time ``t``.
    
    Parameters
    ------------
    
    t
      Time in seconds of the frame to display.
    
    with_mask
      ``False`` if the clip has a mask but you want to see the clip
      without the mask.
    
    """

    if isinstance(t, tuple):
        t = cvsecs(*t)

    if with_mask and (clip.mask is not None):
        import moviepy.video.compositing.CompositeVideoClip as cvc
        clip = cvc.CompositeVideoClip([clip.set_position((0, 0))])
    img = clip.get_frame(t)
    imdisplay(img)

    if interactive:
        result = []
        while True:
            for event in pg.event.get():
                if event.type == pg.KEYDOWN:
                    if event.key == pg.K_ESCAPE:
                        print("Keyboard interrupt")
                        return result
                elif event.type == pg.MOUSEBUTTONDOWN:
                    x, y = pg.mouse.get_pos()
                    rgb = img[y, x]
                    result.append({'position': (x, y), 'color': rgb})
                    print("position, color : ", "%s, %s" %
                          (str((x, y)), str(rgb)))
            time.sleep(.03)


@requires_duration
@convert_masks_to_RGB
def preview(clip, fps=15, audio=True, audio_fps=22050, audio_buffersize=3000,
            audio_nbytes=2, fullscreen=False):
    """ 
    Displays the clip in a window, at the given frames per second
    (of movie) rate. It will avoid that the clip be played faster
    than normal, but it cannot avoid the clip to be played slower
    than normal if the computations are complex. In this case, try
    reducing the ``fps``.
    
    Parameters
    ------------
    
    fps
      Number of frames per seconds in the displayed video.
        
    audio
      ``True`` (default) if you want the clip's audio be played during
      the preview.
        
    audio_fps
      The frames per second to use when generating the audio sound.
      
    fullscreen
      ``True`` if you want the preview to be displayed fullscreen.
      
    """
    if fullscreen:
        flags = pg.FULLSCREEN
    else:
        flags = 0
    
    # compute and splash the first image
    screen = pg.display.set_mode(clip.size, flags)
    
    audio = audio and (clip.audio is not None)
    
    if audio:
        # the sound will be played in parrallel. We are not
        # parralellizing it on different CPUs because it seems that
        # pygame and openCV already use several cpus it seems.
        
        # two synchro-flags to tell whether audio and video are ready
        videoFlag = threading.Event()
        audioFlag = threading.Event()
        # launch the thread
        audiothread = threading.Thread(target=clip.audio.preview,
                                       args=(audio_fps,
                                             audio_buffersize,
                                             audio_nbytes,
                                             audioFlag, videoFlag))
        audiothread.start()
    
    img = clip.get_frame(0)
    imdisplay(img, screen)
    if audio:  # synchronize with audio
        videoFlag.set()  # say to the audio: video is ready
        audioFlag.wait()  # wait for the audio to be ready
    
    result = []
    
    t0 = time.time()
    for t in np.arange(1.0 / fps, clip.duration-.001, 1.0 / fps):
        
        img = clip.get_frame(t)
        
        for event in pg.event.get():
            if event.type == pg.QUIT or \
                    (event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE):
                if audio:
                    videoFlag.clear()
                print("Interrupt")
                return result
                    
            elif event.type == pg.MOUSEBUTTONDOWN:
                x, y = pg.mouse.get_pos()
                rgb = img[y, x]
                result.append({'time': t, 'position': (x, y),
                               'color': rgb})
                print("time, position, color : ", "%.03f, %s, %s" %
                      (t, str((x, y)), str(rgb)))
                    
        t1 = time.time()
        time.sleep(max(0, t - (t1-t0)))
        imdisplay(img, screen)
