# Copyright (C) 2000-2001 The OpenRPG Project
#
#    openrpg-dev@lists.sourceforge.net
#
# This program 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.
#
# This program 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., 675 Mass Ave, Cambridge, MA 02139, USA.
# --
#
# File: mapper/images.py
# Author: OpenRPG
# Maintainer:
# Version:
#   $Id: images.py,v 1.21 2007/12/11 04:07:15 digitalxero Exp $
#
# Description:
#
__version__ = "$Id: images.py,v 1.21 2007/12/11 04:07:15 digitalxero Exp $"

import urllib
import Queue
import thread
from threading import Lock
import time
from orpg.orpg_wx import *
from orpg.orpgCore import *

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance()

class ImageHandlerClass(object):
    __cache = {}
    __fetching = {}
    __queue = Queue.Queue(0)
    __lock = Lock()

    def load(self, path, object_type, image_object):
        #Load an image, with a intermideary fetching image shown while it loads in a background thread
        if self.__cache.has_key(path):
            return wx.ImageFromMime(self.__cache[path][1], self.__cache[path][2])
        if not self.__fetching.has_key(path):  #If We are not fetching this image right now
            self.__fetching[path] = True       #Start Image Loading Thread
            thread.start_new_thread(self.__loadThread, (self, path, object_type, image_object))
        else:
            if self.__fetching[path] is True:
            	thread.start_new_thread(self.__loadCacheThread, (self, path, object_type, image_object))
        return wx.Image(open_rpg.get_component("dir_struct")["icon"] + "fetching.png", wx.BITMAP_TYPE_PNG)

    def directLoad(self, path, object_type, image_object):
        #Directly load an image, no threads
        if self.__cache.has_key(path):
            return wx.ImageFromMime(self.__cache[path][1], self.__cache[path][2])
        uriPath = urllib.unquote(path)
        try:
            d = urllib.urlretrieve(uriPath)
            # We have to make sure that not only did we fetch something, but that it was an image that we got back.
            if d[0] and d[1].getmaintype() == "image":
                self.__cache[path] = (path, d[0], d[1].gettype(), None)
                return wx.ImageFromMime(self.__cache[path][1], self.__cache[path][2])
            else:
                open_rpg.get_component('log').log("Image refused to load or URI did not reference a valid image: " + path, ORPG_GENERAL, True)
                return None
        except IOError:
            open_rpg.get_component('log').log("Unable to resolve/open the specified URI; image was NOT loaded: " + path, ORPG_GENERAL, True)
            return None

    def cleanCache(self):  #Shrinks the Cache down to the proper size
        try:
            cacheSize = int(open_rpg.get_component('settings').get_setting("ImageCacheSize"))
        except:
            #caceSize = 32
            cacheSize = 32 #was cace?
        cache = self.__cache.keys()
        cache.sort()
        for key in cache[cacheSize:]:
            del self.__cache[key]

    def flushCache(self):  #This function will flush all images contained within the image cache.
        self.__lock.acquire()
        try:
            keyList = self.__cache.keys()
            for key in keyList:
                del self.__cache[key]
        finally:
            self.__lock.release()
        urllib.urlcleanup()

    #Image thread. Note 'thread' maybe replaced with 'threading' later because it is higher. 
    def __loadThread(object, self, path, object_type, image_object):
        uriPath = urllib.unquote(path)
        self.__lock.acquire()
        try:
            d = urllib.urlretrieve(uriPath)
            # We have to make sure that not only did we fetch something, but that it was an image that we got back.
            if d[0] and d[1].getmaintype() == "image":
                self.__cache[path] = (path, d[0], d[1].gettype(), image_object)
                self.__queue.put((self.__cache[path], object_type, image_object))
                if self.__fetching.has_key(path):
                    del self.__fetching[path]
            else:
		wx.MessageBox("Image refused to load or URI did not reference a valid image: " + path)
                open_rpg.get_component('log').log("Image refused to load or URI did not reference a valid image: " + path, ORPG_GENERAL, True)
                self.__fetching[path] = False
        except IOError:
            urllib.urlcleanup()
            self.__fetching[path] = False
	    wx.MessageBox("Unable to resolve/open the specified URI; image was NOT loaded: " + path)
            open_rpg.get_component('log').log("Unable to resolve/open the specified URI; image was NOT loaded: " + path, ORPG_GENERAL, True)
        finally:
            self.__lock.release()

    def __loadCacheThread(object, self, path, object_type, image_object):
        try:
            st = time.time()
            while self.__fetching.has_key(path) and self.__fetching[path] is not False:
                time.sleep(0.025)
                if (time.time()-st) > 120:
                    open_rpg.get_component('log').log("Timeout: " + path, ORPG_GENERAL, True)
                    break
        except:
            self.__fetching[path] = False
	    wx.MessageBox("Unable to resolve/open the specified URI; image was NOT loaded: " + path)
            open_rpg.get_component('log').log("Unable to resolve/open the specified URI; image was NOT loaded: " + path, ORPG_GENERAL, True)
            return
        self.__lock.acquire()
        try:
            open_rpg.get_component('log').log("Adding Image to Queue from Cache: " + str(self.__cache[path]), ORPG_DEBUG)
            self.__queue.put((self.__cache[path], object_type, image_object))
        finally:
            self.__lock.release()

#Property Methods
    def _getCache(self):
        return self.__cache

    def _getQueue(self):
        return self.__queue

#Properties
    Cache = property(_getCache)
    Queue = property(_getQueue)

ImageHandler = singleton(ImageHandlerClass)
