#!/usr/bin/env python

# This file is part of Window-Switch.
# Copyright (c) 2009-2013 Antoine Martin <antoine@nagafix.co.uk>
# Window-Switch is released under the terms of the GNU GPL v3

from winswitch.globals import WIN32, OSX
from winswitch.util.common import is_valid_file
from winswitch.util.simple_logger import Logger
import StringIO
import os


#has_gtk tells us if we can load gtk (on Unix this means we must have a DISPLAY)
try:
	import gtk
	assert gtk
	has_gtk = True
except Exception, e:
	has_gtk = False

try:
	import cairo
	import rsvg
	HAS_CAIRO_RSVG = True
except:
	HAS_CAIRO_RSVG = False

try:
	import PIL.Image
	has_PIL = True
except:
	has_PIL = False

HAS_PIXBUFLOADER = WIN32 or OSX or os.environ.get('DISPLAY', False) not in (False, "")

logger=Logger("icon_util", log_colour=Logger.HIGHLIGHTED_BLUE)

MAX_ICON_SIZE = 48


def resize_pixbuf(pixbuf, size_limit):
	scale_x = 48.0/pixbuf.get_width()
	scale_y = 48.0/pixbuf.get_height()
	scaled = gtk.gdk.Pixbuf(pixbuf.get_colorspace(), pixbuf.get_has_alpha(), pixbuf.get_bits_per_sample(), 48, 48)
	pixbuf.scale(scaled, 0, 0, 48, 48, 0, 0, scale_x, scale_y, gtk.gdk.INTERP_BILINEAR)
	return scaled


def gtk_load_scaled_pixmap(filename, size_limit=MAX_ICON_SIZE):
	pixbuf = gtk.gdk.pixbuf_new_from_file(filename)
	#logger.sdebug("pixbuf=%s" % pixbuf, name, "(...)", size_limit)
	scaled = resize_pixbuf(pixbuf, size_limit);
	#logger.sdebug("scaled=%s" % scaled, name, "(...)", size_limit)
	scaled_data = get_data_from_icon(scaled)
	#if scaled_data:
	#	logger.sdebug("new data size: %s" % len(scaled_data), name, "(...)", size_limit)
	return	scaled_data

def pil_load_scaled_pixmap(filename, size_limit):
	img = PIL.Image.open(filename)
	(w,h) = img.size
	if w>size_limit or h>size_limit:
		img.thumbnail((size_limit,size_limit), PIL.Image.ANTIALIAS)
	assert img
	return	pil_image_to_png_data(img)

def pil_image_to_png_data(img):
	output = StringIO.StringIO()
	img.save(output, 'PNG')
	contents = output.getvalue()
	output.close()
	return	contents


def load_pixmap_file(filename, size_limit=MAX_ICON_SIZE):
	if not is_valid_file(filename):
		logger.sdebug("file does not exist", filename, size_limit)
		return	None
	try:
		if HAS_CAIRO_RSVG and (filename.lower().endswith("svg") or filename.lower().endswith("svgz")):
			data = cairo_load_svg(filename, size_limit)
			if data:
				return	data
		if has_gtk:
			data = gtk_load_scaled_pixmap(filename, size_limit)
			if data:
				return	data
			logger.sdebug("gtk pixmap load failed", filename, size_limit)
		if has_PIL:
			return	pil_load_scaled_pixmap(filename, size_limit)
	except ValueError, e:
		if (filename.lower().endswith("xpm")):
			""" avoid dumping a stacktrace here as this seems to happen quite often.. """
			logger.sdebug("failed to load XPM using PIL: %s" % e, filename, size_limit)
		else:
			logger.serr(None, e, filename, size_limit)
	except Exception, e:
		if filename.endswith(".mng"):
			""" as above: mng files cannot be loaded, just ignore """
			return	None
		logger.serr(None, e, filename, size_limit)
	return	None

# needs gnome-python2-rsvg aka python-rsvg
# This code was found here:
# http://mail.python.org/pipermail/python-list/2009-October/1221329.html
# Some other useful pointers:
# http://stackoverflow.com/questions/3064374/how-to-return-an-image-in-an-http-response-with-cherrypy
# http://www.gossamer-threads.com/lists/python/dev/777356
# http://pygame.org/wiki/CairoPygame
def cairo_load_svg(filename, size_limit):
	buf = StringIO.StringIO()
	svgsurface = cairo.SVGSurface(buf, size_limit, size_limit)
	svgctx = cairo.Context(svgsurface)
	svg = rsvg.Handle(file=filename)			#@UndefinedVariable
	svgwidth = svg.get_property('width')
	svgheight = svg.get_property('height')
	if svgwidth<=0.0 or svgheight<=0.0:
		logger.serror("rsvg reported zero width or height! cannot continue loading this icon.", filename, size_limit)
		return	None
	scale = min(size_limit/float(svgwidth), size_limit/float(svgheight))
	svgctx.scale(scale, scale)
	svg.render_cairo(svgctx)

	tmp = StringIO.StringIO()
	svgsurface.write_to_png(tmp)
	svgsurface.finish()
	tmp.seek(0)
	return pil_load_scaled_pixmap(tmp, size_limit)

def get_data_from_icon(icon):
	if not icon:
		return	None
	#logger.sdebug("type=%s" % type(icon), icon)
	if not HAS_PIXBUFLOADER:
		return	None
	buf = []
	icon.save_to_callback(save_to_memory, "png", {}, buf)
	#logger.sdebug("buf len=%d" % len(buf), icon)
	if len(buf)>0:
		return	"".join(buf)
	return	None

def save_to_memory(buf, save_to):
	save_to.append(buf)

def get_icon_from_data(data):
	if not data or not HAS_PIXBUFLOADER:
		return	None
	sig = "(%s : %s)" % (type(data), len(data))
	try:
		loader = gtk.gdk.PixbufLoader()
		loader.write(data)
		loader.close()
	except Exception, e:
		logger.error(sig+" %s" % e)
		return	None
	pixbuf = loader.get_pixbuf()
	return pixbuf
