# Sketch - A Python-based interactive drawing program
# Copyright (C) 1997, 1998, 1999, 2000 by Bernhard Herzog
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

#
# Handle external data
#
#
# This module defines two classes to represent external graphics like
# bitmapped images or encapsulated PostScript files.


from app import Rect, Trafo, IdentityMatrix, NullUndo, SKCache

from base import GraphicsObject, RectangularObject
from properties import EmptyProperties


instance_cache = SKCache()

class ExternalData:

	# default instance variables
	stored_in_cache = 0
	filename = ''

	def __init__(self, filename='', do_cache=1):
		if filename and do_cache:
			self.stored_in_cache = 1
			instance_cache[filename] = self
		if filename:
			self.filename = filename

	def __del__(self):
		if self.stored_in_cache and instance_cache.has_key(self.filename):
			del instance_cache[self.filename]

	def Filename(self):
		return self.filename


	# to be supplied by derived classes
	#
	#    Size() return the size as a tuple (width, height)


def get_cached(filename):
	if instance_cache.has_key(filename):
		return instance_cache[filename]
	return None


class ExternalGraphics(RectangularObject, GraphicsObject):

	has_edit_mode = 0
	# by default this has no properties:
	has_fill = has_line = has_font = 0
	cache_cdata = None
	cache_gray_cdata = None

	data = None

	def __init__(self, data=None, trafo=None, duplicate=None):
		RectangularObject.__init__(self, trafo, duplicate=duplicate)
		GraphicsObject.__init__(self, duplicate=duplicate)
		if duplicate is not None:
			data = duplicate.data
		self.data = data

	def Data(self):
		return self.data

	def SetData(self, data):
		self.cache_cdata = None
		self.cache_gray_cdata = None
		undo = self.SetData, self.data
		self.data = data
		# XXX issue_changed() here ?
		return undo

	def Hit(self, p, rect, device, clip=0):
		width, height = self.data.Size()
		return device.ParallelogramHit(p, self.trafo, width, height, 1,
										ignore_outline_mode=clip)

	def SetLowerLeftCorner(self, corner):
		# Used by the place mode in SketchCanvas. Currently no undo
		# needed since this is called *before* self is a part of a
		# document.
		self.trafo = apply(Trafo, self.trafo.coeff()[:4] + tuple(corner))
		self.del_lazy_attrs()

	def RemoveTransformation(self):
		if self.trafo.matrix() != IdentityMatrix:
			center = self.coord_rect.center()
			width, height = self.data.Size()
			trafo = Trafo(1, 0, 0, 1,
							center.x - width / 2, center.y - height / 2)
			return self.set_transformation(trafo)
		return NullUndo

	def update_rects(self):
		width, height = self.data.Size()
		rect = self.trafo(Rect(0, 0, width, height))
		self.coord_rect = rect
		self.bounding_rect = rect.grown(2)

	def Info(self):
		# Should be overwritten by derived classes
		return 'ExternalGraphics'

	def SetProperties(self, **kw):
		return NullUndo

	def AddStyle(self, style):
		return NullUndo

	def Properties(self):
		return EmptyProperties

	def GetSnapPoints(self):
		width, height = self.data.Size()
		corners = ((0, 0), (width, 0), (width, height), (0, height))
		return map(self.trafo, corners)

	def Snap(self, p):
		width, height = self.data.Size()
		try:
			x, y = self.trafo.inverse()(p)
			if 0 <= x <= width:
				if 0 <= y <= height:
					x = round(x / width) * width
					y = round(y / height) * height
				else:
					y = min(max(y, 0), height)
			else:
				x = min(max(x, 0), width)
				if 0 > y or y > height:
					y = min(max(y, 0), height)

			p2 = self.trafo(x, y)
			return (abs(p - p2), p2)
		except SingularMatrix:
			return (1e200, p)
