#!/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

import os

from winswitch.globals import WIN32, OSX
from winswitch.util.paths import WM_ICONS, DEFAULT_ICONS, WINSWITCH_SHARE_DIR, APP_DIR, SHARE_DIR, PREFIX_SEARCH_ORDER, ICON_DIR
from winswitch.util.icon_util import load_pixmap_file, MAX_ICON_SIZE
from winswitch.util.common import is_valid_dir
from winswitch.util.simple_logger import Logger

logger=Logger("icon_cache", log_colour=Logger.GREEN)


pixmaps_dirs = []
if WIN32:
	share_icons = os.path.join(APP_DIR, "share", "icons")
	pixmaps_dirs.append(share_icons)
else:
	if OSX:
		""" We bundle the default GTK icons on OSX """
		share_icons = os.path.join(SHARE_DIR, "icons")
		pixmaps_dirs.append(share_icons)
	# WM_ICONS: we bundle a bunch of icons for WindowManagers that may be missing from a standard install
	wm_icons_dir = os.path.join(WINSWITCH_SHARE_DIR, WM_ICONS)
	# default icons: mostly used for macosx
	default_icons_dir = os.path.join(WINSWITCH_SHARE_DIR, DEFAULT_ICONS)
	# We recurse down these paths, but we still want to include sub-directories in the list
	# to make sure they get loaded up first (and take precedence over the icons found later)
	PATHS = ["share/pixmaps",
			"share/icons/hicolor/48x48/apps",
			"share/icons/oxygen/48x48/apps",
			"share/icons/oxygen/48x48/categories",
			"share/icons",
			"include/X11/pixmaps/",
			wm_icons_dir,
			default_icons_dir]
	#Start with our own icons
	pixmaps_dirs.append(ICON_DIR)
	for prefix in PREFIX_SEARCH_ORDER:
		for p in PATHS:
			full_path = os.path.join(prefix, p)
			try:
				if is_valid_dir(full_path):
					pixmaps_dirs.append(full_path)
			except:
				logger.serror("error testing %s" % full_path)

	pixmaps_dirs.append(wm_icons_dir)
	logger.sdebug("pixmaps_dir=%s" % str(pixmaps_dirs))




pixmap_cache = None
def populate_pixmap_lookup():
	global pixmap_cache
	global pixmaps_dirs
	if pixmap_cache is not None:
		return pixmap_cache
	pixmap_cache = {}
	stats = {}
	logger.slog("this may take a few seconds..")
	for pixmaps_dir in pixmaps_dirs:
		if is_valid_dir(pixmaps_dir):
			count = populate_pixmap_lookup_from_dir(pixmap_cache, pixmaps_dir)
			stats[pixmaps_dir] = count
	logger.slog("pixmap cache size=%d, stats=%s" % (len(pixmap_cache), stats))
	return pixmap_cache

def remove_pixmap(pixmap):
	if pixmap in pixmap_cache:
		del pixmap_cache[pixmap]


def populate_pixmap_lookup_from_dir(pixmaps, pixmaps_dir):
	count = 0
	for root, dirs, files in os.walk(pixmaps_dir):
		#dont recurse into "cursors" dir:
		if "cursors" in dirs:
			#remove it from walk:
			dirs.remove("cursors")
		for fname in files:
			lname = fname.lower()
			if lname.endswith(".icon") or lname in pixmaps:
				continue
			filepath = os.path.join(root, fname)
			pos = lname.rfind(".")
			if pos>0:
				noext = lname[:pos]
				pixmaps[noext] = filepath
			else:
				pixmaps[lname] = filepath
			count += 1
	return count




def guess_icon_from_name(name, __debug=False, allow_substring_match=False, size_limit=MAX_ICON_SIZE):
	_debug = __debug		#or name.find("edit")>=0
	if _debug:
		logger.sdebug(None, name, __debug, allow_substring_match)
	if not name:
		return	None
	cooked = name.lower()
	short = None
	if cooked.find(" ")>0:
		short = cooked[:cooked.find(" ")]
	for s in [" ", ".png", ".jpg", ".jpeg", ".gif", ".xpm", ".ppm"]:
		cooked = cooked.replace(s, "")
	if len(cooked)==0 or cooked=="None":
		return	None
	if cooked.endswith("winswitch/mime_open"):
		logger.sdebug("will need to load real icon once the real command has been set", name, __debug, allow_substring_match)
		return	None
	pixmap_cache = populate_pixmap_lookup()
	if cooked.startswith("/"):		#is a path
		pos = cooked.rfind("/")
		if pos>0:
			cooked = name[pos+1:]
		pos = cooked.rfind(" ")
		if pos>0:
			cooked = cooked[:pos]
	if _debug:
		logger.sdebug("looking for '%s'" % cooked, name)
	path = pixmap_cache.get(cooked)
	if path:
		data = load_pixmap_file(path, size_limit)
		if _debug:
			logger.sdebug("direct match (%s)=%s" % (cooked, data is not None), name, __debug, allow_substring_match)
		if data:
			return	data
	if _debug:
		logger.sdebug("short='%s'" % short, name)
	candidates = []
	for pixmap,path in pixmap_cache.items():
		if pixmap.startswith(cooked) or (short and pixmap.startswith(short)):
			data = load_pixmap_file(path, size_limit)
			if data:
				return data
		elif allow_substring_match:
			if pixmap.find(cooked)>=0 or (short and pixmap.find(short)>=0):
				candidates.append(path)

	for path in candidates:
		data = load_pixmap_file(path, size_limit)
		if _debug:
			logger.sdebug("data(%s)=%s" % (path, data is not None), name, __debug, allow_substring_match)
		if data:
			return	data
	if _debug:
		logger.sdebug("not found!", name, __debug, allow_substring_match)
	return	None




def main():
	import time
	logger.slog()
	logger.slog("icon_dir=%s" % ICON_DIR)
	logger.slog("pixmaps_dirs=%s" % pixmaps_dirs)
	logger.slog("loading pixmap cache... (this may take a while)")
	start = time.time()
	populate_pixmap_lookup()
	end = time.time()
	logger.slog("len(pixmap_cache)=%d" % len(pixmap_cache))
	delta = int((end-start)*10)/10.0
	logger.slog("took %s seconds" % delta)


if __name__ == "__main__":
	main()
