# 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

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


from Sketch 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

    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):
        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)
