#-*- 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 *
from pygame.locals import *
import pygame
import os
from libopensesame.exceptions import osexception
from libopensesame import debug, misc
from openexp.backend import configurable
from openexp._canvas import canvas
from openexp._coordinates.legacy import legacy as legacy_coordinates

class legacy(canvas.canvas, legacy_coordinates):

	"""
	desc:
		This is a canvas backend built on top of PyGame.
		For function specifications and docstrings, see
		`openexp._canvas.canvas`.
	"""

	# The settings variable is used by the GUI to provide a list of back-end
	# settings
	settings = {
		u"pygame_hwsurface" : {
			u"name" : u"Hardware surface",
			u"description" : u"Create a hardware surface",
			u"default" : u"yes"
			},
		u"pygame_doublebuf" : {
			u"name" : u"Double buffering",
			u"description" : u"Use double buffering",
			u"default" : u"yes"
			},
		u"pygame_window_frame" : {
			u"name" : u"Draw window frame",
			u"description" : u"Draw a frame in window mode",
			u"default" : u"yes",
			},
		u"pygame_window_pos" : {
			u"name" : u"Window position",
			u"description" : u"Window position in window mode (format: 'x,y' or 'auto')",
			u"default" : u"auto",
			}
		}

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

		canvas.canvas.__init__(self, experiment, auto_prepare=auto_prepare,
			**style_args)
		legacy_coordinates.__init__(self)
		self.antialias = True
		self.surface = self.experiment.surface.copy()
		self.clear()

	def set_config(self, **cfg):

		canvas.canvas.set_config(self, **cfg)
		for key, val in cfg.items():
			if u'font_' in key:
				self._font = None
		if self._font is None:
			# First see if the font refers to a file in the resources/ filepool
			try:
				font_path = self.experiment.resource(
					u'%s.ttf' % self.font_family)
				self._font = pygame.font.Font(font_path, self.font_size)
			# If not, try to match a system font
			except:
				self._font = pygame.font.SysFont(self.font_family,
					self.font_size)
			self._font.set_bold(self.font_bold)
			self._font.set_italic(self.font_italic)
			self._font.set_underline(self.font_underline)

	def copy(self, canvas):

		self.surface = canvas.surface.copy()
		self.set_config(**canvas.get_config())

	def show(self):

		self.experiment.surface.blit(self.surface, (0, 0))
		self.experiment.last_shown_canvas = self.surface
		pygame.display.flip()
		return pygame.time.get_ticks()

	@configurable
	def clear(self, color=None):

		if color is not None:
			if u'color' in cfg:
				warnings.warn(u'color is a deprecated style argument for '
					'canvas.clear(). Use background_color instead.',
					DeprecationWarning)
			self.background_color = color
		self.surface.fill(self.background_color.backend_color)

	@configurable
	def line(self, sx, sy, ex, ey):

		sx, sy = self.to_xy(sx, sy)
		ex, ey = self.to_xy(ex, ey)
		pygame.draw.line(self.surface, self.color.backend_color, (sx, sy),
			(ex, ey), self.penwidth)

	@configurable
	def rect(self, x, y, w, h):

		x, y = self.to_xy(x, y)
		if self.fill:
			pygame.draw.rect(self.surface, self.color.backend_color,
				(x, y, w, h), 0)
		else:
			pygame.draw.rect(self.surface, self.color.backend_color,
				(x, y, w, h), self.penwidth)

	@configurable
	def ellipse(self, x, y, w, h):

		x = int(x)
		y = int(y)
		w = int(w)
		h = int(h)
		x, y = self.to_xy(x, y)
		if self.fill:
			pygame.draw.ellipse(self.surface, self.color.backend_color,
				(x, y, w, h), 0)
		else:
			# Because the default way of drawing thick lines gives ugly results
			# for ellipses, we draw thick ellipses manually, by drawing an
			# ellipse with the background color inside of it
			i = self.penwidth / 2
			j = self.penwidth - i
			pygame.draw.ellipse(self.surface, self.color.backend_color,
				(x-i, y-i, w+2*i, h+2*i), 0)
			pygame.draw.ellipse(self.surface,
				self.background_color.backend_color, (x+j, y+j, w-2*j, h-2*j),
				0)

	@configurable
	def polygon(self, vertices):

		vertices = [self.to_xy(x, y) for x, y in vertices]
		if self.fill:
			penwidth = 0
		else:
			penwidth = self.penwidth
		pygame.draw.polygon(self.surface, self.color.backend_color, vertices,
			penwidth)

	def _text(self, text, x, y):

		surface = self._font.render(text, self.antialias,
			self.color.backend_color)
		x, y = self.to_xy(x, y)
		self.surface.blit(surface, (x, y))

	def _text_size(self, text):

		return self._font.size(text)

	def image(self, fname, center=True, x=None, y=None, scale=None):

		_fname = safe_str(fname, enc=misc.filesystem_encoding())
		if not os.path.isfile(_fname):
			raise osexception(u'"%s" does not exist' % fname)
		try:
			surface = pygame.image.load(_fname)
		except pygame.error:
			raise osexception(
				u"'%s' is not a supported image format" % fname)
		if scale is not None:
			try:
				surface = pygame.transform.smoothscale(surface,
					(int(surface.get_width()*scale),
					int(surface.get_height()*scale)))
			except:
				debug.msg(u"smooth scaling failed for '%s'" % fname,
					reason=u"warning")
				surface = pygame.transform.scale(surface,
					(int(surface.get_width()*scale),
					int(surface.get_height()*scale)))
		size = surface.get_size()
		x, y = self.to_xy(x, y)
		if center:
			x -= size[0] / 2
			y -= size[1] / 2
		self.surface.blit(surface, (x, y))

	def gabor(self, x, y, orient, freq, env=u"gaussian", size=96, stdev=12,
		phase=0, col1=u"white", col2=u"black", bgmode=u"avg"):

		surface = canvas._gabor(orient, freq, env, size, stdev, phase, col1,
			col2, bgmode)
		x, y = self.to_xy(x, y)
		self.surface.blit(surface, (x - 0.5 * size, y - 0.5 * size))

	def noise_patch(self, x, y, env=u"gaussian", size=96, stdev=12,
		col1=u"white", col2=u"black", bgmode=u"avg"):

		surface = canvas._noise_patch(env, size, stdev, col1, col2, bgmode)
		x, y = self.to_xy(x, y)
		self.surface.blit(surface, (x - 0.5 * size, y - 0.5 * size))

	@staticmethod
	def init_display(experiment):

		# Intialize PyGame
		pygame.init()

		# Set the window icon
		surf = pygame.Surface( (32, 32) )
		surf.fill( (255, 255, 255) )
		pygame.draw.circle(surf, (0, 0, 255), (16, 16), 10, 4)
		pygame.display.set_icon(surf)

		# Determine the video mode
		mode = 0
		if experiment.var.get(u"pygame_hwsurface", u"yes",
			[u"yes", u"no"]) == u"yes":
			mode = mode | pygame.HWSURFACE
			print(
				u"openexp._canvas.legacy.init_display(): enabling hardware surface")
		else:
			print(
				u"openexp._canvas.legacy.init_display(): not enabling hardware surface")

		if experiment.var.get(u"pygame_doublebuf", u"yes",
			[u"yes", u"no"]) == u"yes":
			mode = mode | pygame.DOUBLEBUF
			print(
				u"openexp._canvas.legacy.init_display(): enabling double buffering")
		else:
			print(
				u"openexp._canvas.legacy.init_display(): not enabling double buffering")

		if pygame.display.mode_ok(experiment.resolution(), mode):
			print(u"openexp._canvas.legacy.init_display(): video mode ok")
		else:
			print(
				u"openexp._canvas.legacy.init_display(): warning: video mode not ok")

		if experiment.var.fullscreen == u'yes':
			mode = mode | pygame.FULLSCREEN

		if experiment.var.get(u'pygame_window_frame', u'yes', [u'yes', u'no']) \
			== u'no':
			mode = mode | pygame.NOFRAME

		if experiment.var.get(u'pygame_window_pos', u'auto') != u'auto':
			os.environ[u'SDL_VIDEO_WINDOW_POS'] = experiment.var.get(
				u'pygame_window_pos')

		# Create the window and the surface
		experiment.window = pygame.display.set_mode(experiment.resolution(), mode)
		pygame.display.set_caption(u'OpenSesame (legacy backend)')
		pygame.mouse.set_visible(False)
		experiment.surface = pygame.display.get_surface()

		# Create a font, falling back to the default font
		try:
			experiment.font = pygame.font.Font(experiment.resource(
				u"%s.ttf" % experiment.var.font_family), experiment.var.font_size)
		except:
			debug.msg(u"'%s.ttf' not found, falling back to default font" \
				% experiment.var.font_family)
			experiment.font = pygame.font.Font(None, experiment.var.font_size)

	@staticmethod
	def close_display(experiment):

		pygame.display.quit()
