"""
Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio

GNU Radio Companion 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 2
of the License, or (at your option) any later version.

GNU Radio Companion 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
"""

from Element import Element
import Utils
import Colors
from .. base import odict
from Constants import BORDER_PROXIMITY_SENSITIVITY
from Constants import \
	BLOCK_LABEL_PADDING, \
	PORT_SEPARATION, LABEL_SEPARATION, \
	PORT_BORDER_SEPARATION, POSSIBLE_ROTATIONS
import pygtk
pygtk.require('2.0')
import gtk

BLOCK_MARKUP_TMPL="""\
#set $foreground = $block.is_valid() and 'black' or 'red'
<span foreground="$foreground" font_desc="Sans 8"><b>$encode($block.get_name())</b></span>"""

class Block(Element):
	"""The graphical signal block."""

	def __init__(self, *args, **kwargs):
		"""
		Block contructor.
		Add graphics related params to the block.
		"""
		#add the position param
		self._params['_coordinate'] = self.get_parent().get_parent().Param(
			self,
			odict({
				'name': 'GUI Coordinate',
				'key': '_coordinate',
				'type': 'raw',
				'value': '(0, 0)',
				'hide': 'all',
			})
		)
		self._params['_rotation'] = self.get_parent().get_parent().Param(
			self,
			odict({
				'name': 'GUI Rotation',
				'key': '_rotation',
				'type': 'raw',
				'value': '0',
				'hide': 'all',
			})
		)
		Element.__init__(self)

	def get_coordinate(self):
		"""
		Get the coordinate from the position param.
		@return the coordinate tuple (x, y) or (0, 0) if failure
		"""
		try: #should evaluate to tuple
			coor = eval(self.get_param('_coordinate').get_value())
			x, y = map(int, coor)
			fgW,fgH = self.get_parent().get_size()
			if x <= 0:
				x = 0
			elif x >= fgW - BORDER_PROXIMITY_SENSITIVITY:
				x = fgW - BORDER_PROXIMITY_SENSITIVITY
			if y <= 0:
				y = 0
			elif y >= fgH - BORDER_PROXIMITY_SENSITIVITY:
				y = fgH - BORDER_PROXIMITY_SENSITIVITY
			return (x, y)
		except:
			self.set_coordinate((0, 0))
			return (0, 0)

	def set_coordinate(self, coor):
		"""
		Set the coordinate into the position param.
		@param coor the coordinate tuple (x, y)
		"""
		self.get_param('_coordinate').set_value(str(coor))

	def get_rotation(self):
		"""
		Get the rotation from the position param.
		@return the rotation in degrees or 0 if failure
		"""
		try: #should evaluate to dict
			rotation = eval(self.get_param('_rotation').get_value())
			return int(rotation)
		except:
			self.set_rotation(POSSIBLE_ROTATIONS[0])
			return POSSIBLE_ROTATIONS[0]

	def set_rotation(self, rot):
		"""
		Set the rotation into the position param.
		@param rot the rotation in degrees
		"""
		self.get_param('_rotation').set_value(str(rot))

	def update(self):
		"""Update the block, parameters, and ports when a change occurs."""
		self._bg_color = self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR
		self.clear()
		self._create_labels()
		self.W = self.label_width + 2*BLOCK_LABEL_PADDING
		self.H = max(*(
			[self.label_height+2*BLOCK_LABEL_PADDING] + [2*PORT_BORDER_SEPARATION + \
			sum([port.H + PORT_SEPARATION for port in ports]) - PORT_SEPARATION
			for ports in (self.get_sources(), self.get_sinks())]
		))
		if self.is_horizontal(): self.add_area((0, 0), (self.W, self.H))
		elif self.is_vertical(): self.add_area((0, 0), (self.H, self.W))
		map(lambda p: p.update(), self.get_ports())

	def _create_labels(self):
		"""Create the labels for the signal block."""
		layouts = list()
		#create the main layout
		layout = gtk.DrawingArea().create_pango_layout('')
		layouts.append(layout)
		layout.set_markup(Utils.parse_template(BLOCK_MARKUP_TMPL, block=self))
		self.label_width, self.label_height = layout.get_pixel_size()
		#display the params
		for param in filter(lambda p: p.get_hide() not in ('all', 'part'), self.get_params()):
			layout = param.get_layout()
			layouts.append(layout)
			w,h = layout.get_pixel_size()
			self.label_width = max(w, self.label_width)
			self.label_height = self.label_height + h + LABEL_SEPARATION
		width = self.label_width
		height = self.label_height
		#setup the pixmap
		pixmap = self.get_parent().new_pixmap(width, height)
		gc = pixmap.new_gc()
		gc.set_foreground(self._bg_color)
		pixmap.draw_rectangle(gc, True, 0, 0, width, height)
		#draw the layouts
		h_off = 0
		for i,layout in enumerate(layouts):
			w,h = layout.get_pixel_size()
			if i == 0: w_off = (width-w)/2
			else: w_off = 0
			pixmap.draw_layout(gc, w_off, h_off, layout)
			h_off = h + h_off + LABEL_SEPARATION
		#create vertical and horizontal images
		self.horizontal_label = image = pixmap.get_image(0, 0, width, height)
		if self.is_vertical():
			self.vertical_label = vimage = gtk.gdk.Image(gtk.gdk.IMAGE_NORMAL, pixmap.get_visual(), height, width)
			for i in range(width):
				for j in range(height): vimage.put_pixel(j, width-i-1, image.get_pixel(i, j))
		map(lambda p: p._create_labels(), self.get_ports())

	def draw(self, gc, window):
		"""
		Draw the signal block with label and inputs/outputs.
		@param gc the graphics context
		@param window the gtk window to draw on
		"""
		x, y = self.get_coordinate()
		#draw main block
		Element.draw(
			self, gc, window, bg_color=self._bg_color,
			border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or Colors.BORDER_COLOR,
		)
		#draw label image
		if self.is_horizontal():
			window.draw_image(gc, self.horizontal_label, 0, 0, x+BLOCK_LABEL_PADDING, y+(self.H-self.label_height)/2, -1, -1)
		elif self.is_vertical():
			window.draw_image(gc, self.vertical_label, 0, 0, x+(self.H-self.label_height)/2, y+BLOCK_LABEL_PADDING, -1, -1)
		#draw ports
		for port in self.get_ports(): port.draw(gc, window)

	def what_is_selected(self, coor, coor_m=None):
		"""
		Get the element that is selected.
		@param coor the (x,y) tuple
		@param coor_m the (x_m, y_m) tuple
		@return this block, a port, or None
		"""
		for port in self.get_ports():
			port_selected = port.what_is_selected(coor, coor_m)
			if port_selected: return port_selected
		return Element.what_is_selected(self, coor, coor_m)
