# -*- coding: utf-8 -*-

# Copyright (c) 2007 Stas Zykiewicz <stas.zytkiewicz@gmail.com>
#
#           pyassetmlSDL.py
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 3 of the GNU General Public License
# as published by the Free Software Foundation.  A copy of this license should
# be included in the file GPL-3.
#
# 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

DEBUG = 0
TRANSPARENT_IMAGE = 1
ALPHA_IMAGE = 0

__version__ = "0.4"

import sys

from CPConstants import ASSETMLROOT

class PyassetmlsdlError(Exception):
    pass
 
try:
    import pyassetml,pygame
    from pygame.constants import RLEACCEL
except ImportError,info:
    print >> sys.stderr, "pyassetmlSDL report a error:\n", info
    raise PyassetmlsdlError

import os

def load_sound(name):
    """Loads a sound -> pygame sound object.
      If no file can be loaded return a dummy class"""
    class NoneSound:
        def play(self,loop=None):
            pass
        def stop(self):
            pass
        def queue(self):
            pass
        
    if not pygame.mixer or not pygame.mixer.get_init():
        print >> sys.stderr, 'Cannot load sound: %s \n%s\n pygame.mixer.error' % (name,pygame.get_error())
        
        print >> sys.stderr, 'Using Nonesound'
        return NoneSound()
    try:
        sound = pygame.mixer.Sound(name)
    except pygame.error, message:
        print >> sys.stderr, 'Cannot load sound: %s \n%s' % (name,pygame.get_error())
        print >> sys.stderr, 'Using Nonesound'
        return NoneSound()
    return sound

def load_music(file):
    """  Set up music object, if the music can't be loaded a bogus object will be returnt.
     Beware that due to SDL limitations you can only have one music source loaded.
     This means that even when you have multiple pygame instances, there can only be one
     music source. This function returns a filename wrapped in a sound like object with
     a play and stop method.
     For multiple sources use the pygame.Sound and wave combination.
     """
    class MusicObject:
        def __init__(self,filename):
            self.s = filename
        def play(self,loop=0):
            pygame.mixer.music.load(self.s)
            pygame.mixer.music.play(loop)
        def stop(self):
            pygame.mixer.music.stop()
        def queue(self):
            pygame.mixer.music.queue(self.s)
    
    class NoneSound:
        def play(self,loop=0):
            pass
        def stop(self):
            pass
        def queue(self):
            pass
    
    if not pygame.mixer or not pygame.mixer.get_init():
        print >> sys.stderr, 'Cannot load sound, pygame.mixer.error', '\nUsing Nonesound'
        return NoneSound()
    try:
       playmusic = MusicObject(file)
    except (pygame.error,IOError),info:
        print >> sys.stderr,info,"\nDisable music"
        playmusic = NoneSound()
    return playmusic

def load_image(file):
    """loads an image and convert it"""
    try:
        surface = pygame.image.load(file)
    except pygame.error,info:
        PyassetmlsdlError.line = 'load_image()'
        print >> sys.stderr, "PyassetmlSDL, could not load",file,info
        raise PyassetmlsdlError, 'Could not load image "%s"\n %s'%(file, pygame.get_error())
    if TRANSPARENT_IMAGE:
        if DEBUG: print "pyassetmlSDL transparent image",file
        surface.set_colorkey(surface.get_at((0, 0)), RLEACCEL)
    if ALPHA_IMAGE:
        if DEBUG: print "pyassetmlSDL alpha image",file
        #if the image loaded has alpha, the overall alpha set here
        #(128) will be overriden. Do it anyway for forcing RLEACCEL
        surface.set_alpha(128, RLEACCEL)
        # if the display is in a lower mode, then surface.convert would
        # convert the surface in an alpha-less surface.
        return surface

    return surface.convert()

## These prefixen are used to determine which pygame function to call
## XXXX Maybe it would be better to get the mimetype from assetml, but pyassetml
## doesn't support it, yet. TODO
music = load_music
sound = load_sound
image = load_image

EXT_switch = {'png':music,'mp3':music,'ogg':music,'wav':sound,'au':sound,\
              'png':image,'jpg':image,'gif':image,'bmp':image}

class AssetmlSDL:
    def __init__(self, assetmlpath=ASSETMLROOT):
        """ class to fetch data from assetml files and provides methods
          to turn these files into sdl objects"""
        self.assetfiles = filter(os.path.isdir,os.listdir(assetmlpath))
        self.assetmlpath = assetmlpath
        
    def set_mldir(self, dirname):
        """ This sets the assetml file path to be used.
        XXX
        if not dirname in self.assetfiles:
            print >> sys.stderr, "pyassetmlSDL report a error:\nCan\'t find", dirname
            raise PyassetmlsdlError
        # XXX maybe we could do a search here, so we can first search the dir we need
        # and then set it to mldir. Better wait until the dataset thing is ready
        """
        self.mldir = os.path.join(self.assetmlpath,dirname)
        #print 'mldir',self.mldir
        self.parser = pyassetml.AssetmlParser(self.mldir)
        
    def set_transparent_image(self, trans=1):
        """ Set image to be transparent or not, 1 or 0.
         This value will be used until it's been reset.
         """
        global TRANSPARENT_IMAGE
        TRANSPARENT_IMAGE = trans
    
    def set_alpha_image(self, alpha=1):
        """ Sets image to use alpha channel or not, 1 or 0
         This value will be used until it's been reset.
         """
        global ALPHA_IMAGE
        ALPHA_IMAGE = alpha


    def get_assets(self, filenames, class_instance=None, fullname=0):
        """ This will return a dictionary with the found files as SDL objects.
         example: {'file1.ext':<pygame.image object>,'file2.ext':<pygame.image object>}
         When a class instance is given the dictionary is mapped onto this class instance.
         Instead of a class instance you can parse any object that has a __dict__ method.
         When filenames is a sequence of one then only the SDL object is returnt.
         A special case is when filenames == ('*.foo',), then all the files whith '.foo'
         in there name are returnt as a dictionary. The '*' in this case doesn't function
         as a traditional wildcard, but to signal that, while it's a sequence of one we don't
         want just one object, but all the matching objects.
         It's a somewhat hackerish solution.
        """
        WILDCARD = 0
        FULLNAME = fullname
        object_dict = {}
        name = ""
        loc = self.parser.get_locale()
        if len(filenames) == 1:
            if filenames[0].find('*') == 0:
                WILDCARD = 1
                filenames = (filenames[0][1:],)
        searchpat = ((u'file', filenames),)
        if DEBUG: print 'searchpat',searchpat
        files = self.parser.find(searchpat)
        if DEBUG: print "result",files
        if not files:
            return None
        for file in files:
            desc = os.path.basename(file)
            name, ext = os.path.splitext(desc)
            if FULLNAME:
                name = desc
            try:
                object_dict[name] = apply(EXT_switch[ext[1:]], (file,))
            except KeyError,info:
                print >> sys.stderr, "No support for",ext[1:],"\n",info
        
        if class_instance:
            try:
                class_instance.__dict__.update(object_dict)                  
            except:
                print >> sys.stderr, "failed to map the dictionary onto the class object"
            return None
        else:
            if len(filenames) == 1 and WILDCARD:
                return object_dict
            elif len(filenames) == 1 and object_dict.has_key(name):
                return object_dict[name]
            else:
                return object_dict
        return None
        
if __name__ == '__main__':
    import pprint
    p = AssetmlSDL('/home/stas/Projects/assetml')
    p.set_mldir('flags/flags.assetml')
    #files = ('am.png','ar.png','nl.png','fr.png','cz.png')
    # This is also possible to find all the png's
    files = ('*.png',) # The * is mandatory 
    pygame.init()
    screen = pygame.display.set_mode((800,600))
    
    assets = p.get_assets(files)
    
    class test:
        pass
    t=test()
    p.get_assets(files,t)# added the objects to the instance
    print "Result of get_assets(files,class object)"
    pprint.pprint(dir(t))
    
    print "Result of get_assets(files)"    
    pprint.pprint(assets)
    rects = []
    x,y = 10,40
    for surf in assets.values():
        rects.append(screen.blit(surf,(x,y)))
        x += surf.get_width()+10
    pygame.display.update(rects)
    pygame.time.wait(4000)
