# -*- coding:utf-8 -*-

"""
This file is part of OpenSesame.

OpenSesame is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

OpenSesame is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with OpenSesame.  If not, see <http://www.gnu.org/licenses/>.
"""
from libopensesame.py3compat import *
import pygame
from collections import OrderedDict
from openexp._canvas.canvas import Canvas
from openexp.backend import configurable
from expyriment import io, control, stimuli
from libopensesame.oslogging import oslogger
from openexp._coordinates.xpyriment import Xpyriment as XpyrimentCoordinates


class Xpyriment(Canvas, XpyrimentCoordinates):

    r"""This is a canvas backend built on top of Expyriment. For function
    specifications and docstrings, see `openexp._canvas.canvas`.
    """
    settings = {
        u"expyriment_opengl": {
            u"name": u"Use OpenGL",
            u"description": u"Use OpenGL mode for better temporal precision",
            u"default": u"yes"
        }
    }

    def __init__(self, experiment, auto_prepare=True, **style_args):

        Canvas.__init__(self, experiment, auto_prepare=auto_prepare,
                        **style_args)
        XpyrimentCoordinates.__init__(self)
        self.clear()

    @configurable
    def clear(self):

        self._elements = OrderedDict()
        self._set_background()

    def set_config(self, **cfg):

        Canvas.set_config(self, **cfg)
        if u'background_color' in cfg:
            self._set_background()

    def show(self):

        # First create a flat list of all elements, including elements that are
        # part of a group. Then we show them, clearing the display on the first,
        # and updating the display on the last.
        t0 = self.experiment.clock.time()
        elements = [e for g in self._elements.values() if g.visible for e in g]
        self._background.present(clear=True, update=not elements)
        while elements:
            e = elements.pop(0)
            e.show(clear=False, update=not elements)
        t1 = self.experiment.clock.time()
        if t1 - t0 > self.MAX_SHOW_DT:
            oslogger.warning('Canvas.show() took {0} ms'.format(t1 - t0))
        return t1

    def _set_background(self):

        self._background = stimuli.BlankScreen(
            colour=self.background_color.backend_color
        )
        self._background.preload()

    @staticmethod
    def init_display(experiment):

        # Configure Expyriment
        io.defaults.mouse_track_button_events = False
        control.defaults.initialize_delay = 0
        control.defaults.event_logging = 0
        control.defaults.window_mode = experiment.var.fullscreen != u'yes'
        control.defaults.fast_quit = True
        control.defaults.window_size = experiment.resolution()
        control.defaults.auto_create_subject_id = True
        control.defaults.open_gl = experiment.var.get(u'expyriment_opengl',
                                                      xpyriment.settings[u'expyriment_opengl'][u'default']) == u'yes'
        control.defaults.audiosystem_sample_rate = experiment.var.sound_freq
        control.defaults.audiosystem_bit_depth = \
            experiment.var.sound_sample_size
        control.defaults.audiosystem_channels = experiment.var.sound_channels
        control.defaults.audiosystem_buffer_size = \
            experiment.var.sound_buf_size
        control.defaults.audiosystem_autostart = False
        # Initialize. If Expyriment jumps into interactive mode, it reads from
        # the stdin, and crashes. Thus we explicitly disable the interactive-
        # mode detection. The is_interactive_mode() function is located
        # differently in different versions of expyriment, and hence we monkey
        # patch it twice.
        control._experiment_control.misc.is_interactive_mode = \
            control._experiment_control.is_interactive_mode = \
            lambda: False
        exp = control.initialize()
        experiment.window = exp.screen._surface
        experiment.expyriment = exp
        # TODO: In order to set the window title and to allow mouse responses we
        # need to bypass expyriment for now
        pygame.display.set_caption(u'OpenSesame (Expyriment backend)')
        pygame.event.set_allowed(pygame.MOUSEBUTTONDOWN)
        pygame.event.set_allowed(pygame.MOUSEBUTTONUP)

    @staticmethod
    def close_display(experiment):

        control.end()


# Non PEP-8 alias for backwards compatibility
xpyriment = Xpyriment
