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

# Copyright (c) 2007 Stas Zykiewicz <stas.zytkiewicz@gmail.com>
#
#           letters.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.


RCFILE = 0
DEBUG = 1
import os,sys,random,operator,fnmatch,gettext,locale,glob
import pygame
from pygame.constants import *
from CPConstants import DATADIR,HOMEDIR

from utils import load_image,load_sound,font2surf,MyError,ProgressBar,ScaleImages
try:
    import pyassetml,pyassetmlSDL
except (ImportError,MyError),info:
    print >> sys.stderr,info,"\nThis version of childsplay depends on pyassetml(SDL)"
    text = "Module letters fails to import pyassetml(SDL)"
    raise MyError,text

class Img:
    pass
class Snd:
    pass

def my_font2surf(word,size,cpg,fcol=None,ttf=None,sizel=None):
    """ This is just a wrapper for the original font2surf function.
    It's used to prevent reversing of the characters when running in a
    RTL environment like Hebrew or Arabic.
    Letters.py uses only English in those environments because of unresolved
    input issues. Contact me at stas.zytkiewicz@gmail.com if you want info about this."""
    #print self.cpg.language
    if cpg.language == 'he':
        if not fcol:
            fcol = (0,0,0)
        try:
            font = pygame.font.Font(ttf,size)
        except Exception,info:
            print >> sys.stderr,info,'\nUsing standard pygame font'
            font = pygame.font.Font(None,size)
        if sizel:
            sizelist = font.size(word)
        else:
            sizelist = map(font.size,word)
        surf = font.render(word, 1, fcol)
        return surf,sizelist
    else:
        return font2surf(word,size,fcol,ttf,sizel)

class Arrow:
    def __init__(self,start,end):
        self.image = Img.arrow
        self.rect = self.image.get_rect()
        self.move = 6
        self.zone = pygame.Rect(start + (self.rect[3],) + (end,))
        self.rect.move_ip(start)
                
    def update(self):
        self.rect = self.rect.move(0,self.move)
        if not self.zone.contains(self.rect):
            self.move = -self.move
    def erase(self):
        self.rect = Img.screen.blit(Img.backgr,self.rect,self.rect)
        
class Game(Img,Snd):    
    """  Letters.py - part of childsplay.py, a suite of educational games for
  young children.
  """

    def __init__(self,screen,backgr,rc_dic,basepath,libdir,cpg):
        Img.screen = screen
        Img.backgr = backgr
        self.gamelevels = range(1,5)
        self.gameitems = range(8)
        self.rc_dic = rc_dic
        self.basedir  = basepath
        self.libdir = libdir
        self.cpg = cpg
        self.stop = 0
        self.score = 0
        if DEBUG: print "self.cpg",dir(self.cpg)       
        # create two assetmlSDL instances one for parsing images and one for sounds
        self.Assets_img = pyassetmlSDL.AssetmlSDL()
        self.Assets_img.set_mldir('childsplay/childsplay-images/childsplay-images.assetml')
        Img.arrow = self.Assets_img.get_assets(('arrow.png',))
        
        loc = self.cpg.language
        if DEBUG: print "letters game, locale set to",loc
        # start a progressbar
        self.pbar = ProgressBar(header=_("Loading images, please wait"),\
                                    step=1,\
                                    ttf=os.path.join(DATADIR,'VeraSeBd.ttf'))
        self.updatebar()
        # Do we have other user provided images?
        try:
            self.myimages = glob.glob(os.path.join(HOMEDIR,'letters','my_images','*'))
        except Exception,info:
            print info
            self.myimages = []
        if DEBUG: print "Contents of my_images", self.myimages
        self.updatebar()
        if loc == 'system': loc = 'en'
        self.trans_descr_pics = {}
        if self.myimages:
            # use the users pics, we assume th name of the pic is the correct description
            # self.trans_descr_pics must become a dict like: {u'FISH':<surface>,u'BEAR':<surface>,....}
            self.trans_descr_pics = {}
            # scale images?
            for path in self.myimages:
                base,file = os.path.split(path)
                name,ext = os.path.splitext(file)
                self.trans_descr_pics[unicode(name).upper()] = load_image(path,alpha=1)
                self.updatebar()
        else:
            assetml_packs = []
            # we will use the standard pics
            def_pack = 'childsplay/memory-136x136/memory-136x136.assetml'
            assetml_packs.append(def_pack)
            # first check if we have the lfc package installed.
            lfc_pack = 'childsplay/objectslib/pics/cards/cards.assetml'
            try:
                self.Assets_img.set_mldir(lfc_pack)
            except SystemExit,info:
                if DEBUG: print info
                pass
            else: # if installed, try to find localized pics
                assetml_packs.append(lfc_pack)
            for pack in assetml_packs:
                self.Assets_img.set_mldir(pack)
                # TODO: for the memory stuff we don't have alpha
                if pack == lfc_pack:
                    self.Assets_img.set_transparent_image(0)
                    self.Assets_img.set_alpha_image(1)
                else:
                    self.Assets_img.set_transparent_image(1)
                    self.Assets_img.set_alpha_image(0)
                descr_pics = self.Assets_img.get_assets(('*.png',),fullname=1)# {foo.png:foo.png object,spam.png:spam.png object}
                parser = pyassetml.AssetmlParser(pack)       
                for k,v in descr_pics.items():
                    try:
                        found = parser.find_names((('file',k),('description',loc)))[0]
                    except TypeError:
                        if DEBUG: print >> sys.stderr,"Error in names searching, assetml","descr_pics",descr_pics,"locale",loc
                        found = None
                    if found:
                        self.trans_descr_pics[found.upper()] = v
                        if DEBUG: print "Found localized words ",found
                    else:
                        self.trans_descr_pics[k.upper()[:-4]] = v
                        if DEBUG: print "Found words",k
                    self.updatebar()
                if pack == lfc_pack:# need to scale to 136x136
                    self.pbar.clearbar(Img.screen,Img.backgr)
                    self.pbar.reset_bar(_("Scale images, please wait"))
                    sc_img = ScaleImages(self.trans_descr_pics,(136,136))
                    self.trans_descr_pics = sc_img.get_images()
                self.pbar.clearbar(Img.screen,Img.backgr)
                self.pbar.reset_bar(_("Loading images, please wait"))
        self.Assets_snd = pyassetmlSDL.AssetmlSDL()
        self.Assets_snd.set_mldir('childsplay/childsplay-sounds/childsplay-sounds.assetml')
        files = ('bummer.wav','wahoo.wav')
        self.Assets_snd.get_assets(files, Snd)
         
        self._setup()   
    
    def updatebar(self):
        progress = self.pbar.update()
        pygame.display.update(self.screen.blit(self.pbar.get_bar(),(200,200)))
    
    def _setup(self):
        self.ttf = os.path.join(DATADIR,'VeraSeBd.ttf')
        self.score = 0
        self.fontsize = 48
        self.fcol = (226,178,31)
                
        wrdlist = self.trans_descr_pics.keys()
        random.shuffle(wrdlist)
        
        self.wordlist = wrdlist[:]
        if DEBUG: print "wordlist",self.wordlist
        self.objs_to_move = []
        
        self.piccoor = (300,40)
    
    def start(self,level,i):
        """  Type the letter under the arrow,or type the whole word""" 
        
        word = self.wordlist[i]
        if DEBUG: print "Choosen word",word
        
        self.word = word # use standard
        self.wordpic = self.trans_descr_pics[self.word]
        try:
            spam,self.sizelist =  my_font2surf(self.word,self.fontsize,\
                                        self.cpg,self.fcol,self.ttf)
        except MyError,info:
            MyError.line = 'method start()'
            MyError.name = __name__
            raise MyError,info
        l = 0
        for item in self.sizelist: # count the letter size
            l = l+item[0]
        if l >= 350:
            self.fontsize = self.fontsize - 10
            l = 350
        self.userword = u""
        self.wordcoor = (400-l-50,340)
        self.usercoor = (self.wordcoor[0]+l+50,340)
        box = pygame.Rect(self.usercoor + (l,item[1]))
        box.inflate_ip(4,4)
        br = pygame.draw.rect(self.screen,(9,244,9),box,2)
        # pythonish case in :)
        apply({"1":self._level_1,
            "2":self._level_2,
            "3":self._level_3,
            "4":self._level_4}[str(level)])
        
        self.pbar.clearbar(Img.screen,Img.backgr)
        r1 = Img.screen.blit(self.wordsurf,self.wordcoor)
        r2 = Img.screen.blit(self.wordpic,self.piccoor)
        pygame.display.update((r1,r2,br))
        
    def _level_1(self):
        self.end = 140
        self.objs_to_move.append((Arrow((self.wordcoor[0],self.wordcoor[1]-132),self.end-20)))
        self.offset = self.wordcoor[0]
        self.wordsurf,sizelist =  my_font2surf(self.word,self.fontsize,self.cpg,\
                                            self.fcol,self.ttf)
        self.arrowdic = {} # used to store the coord. of the letters
        # TODO: the arrow is not above the letters if the words are larger
        # it's probably due to the different fontsize when the words are larger.
        map(operator.setitem,[self.arrowdic]*len(self.sizelist),self.word,sizelist)
        
    def _level_2(self):
        self.piccoor = (300,100)
        pick = random.choice(self.word)
        wrd = self.word.replace(pick,'-',1)
        self.wordsurf,spam =  my_font2surf(wrd,self.fontsize,self.cpg,\
                                            self.fcol,self.ttf)
    
    def _level_3(self):
        dash = '-'*(len(self.word)-2)
        wrd = self.word[0]+dash+self.word[-1]
        self.wordsurf,spam =  my_font2surf(wrd,self.fontsize,self.cpg,\
                                            self.fcol,self.ttf)
        
    def _level_4(self):
        wrd = '-' * len(self.word)
        self.wordsurf,spam =  my_font2surf(wrd,self.fontsize,self.cpg,\
                                        self.fcol,self.ttf)
    
    def loop(self,events):
        self.dirty_rects = []
        self.score = 0
        self.stop = 0
        for event in events:
            # added swedish extended ascii å, ä and ö
            if event.type is KEYDOWN and (96<event.key<123 or 
                                            event.key==59 or
                                            event.key==39 or
                                            event.key==91) :
                userkey = event.unicode
                #print userkey
                self._check_key(userkey[0])# when multiple keyes are pushed, len(userkey) > 1 ???
            # XXX implement shift keys ???
            #elif event.type is KEYDOWN and event.key K_RSHIFT or event.key is K_LSHIFT
        for obj in self.objs_to_move:
            self.dirty_rects.append((Img.screen.blit(Img.backgr,obj.rect,obj.rect)))
            obj.update()
            self.dirty_rects.append((Img.screen.blit(obj.image,obj.rect)))
        pygame.display.update(self.dirty_rects)
        return self.stop,self.score
    
    def __str__(self):
        """Must return the original, not translated, title of this game.
        It's needed by the high score class of childsplay."""        
        return "Letters"
    
    def helptitle(self):
        return _('Letters')
        
    def help(self):
        text = [_("The aim of the game:"),
        _("Learning to type simple words with examples and pictures."),
        " ",
        _("Difficulty : 4-6 years"),
        _("Number of levels : 4"),
        " ",
        _("Try to type the letters and words, there are four levels each one"),
        _("slightly more difficult then the previous one."),
        _("In every level there are one or more letters left out of the word."),
        _("The last level just shows you the picture and dashes."),
        _("If you hit a wrong letter you hear a 'bummer' sound."),
        _("You can try as many times until you hit the right letter (26 times?)."),
        " ",
        _("Translation of the words:"),
        _("If you installed childsplay with the provided 'Makefile',"),
        _("you have had the opportunity to translate the words used by"),
        _("the letters module."),
        _("and type 'letters-trans.py' (without the ' ')."),
        _("If you get a 'bash: letters-trans.py: command not found' error you"),
        _("should look where letters-trans.py is installed and run it from there.")]

        return text
        
    
    def _check_key(self,key):
        key = unicode(key.upper())
        step = len(self.userword)
        #print 'step',step,self.word[step]
        if self.word[step] == key:
            self.userword = "%s%s" % (self.userword,key)
            if self.userword == self.word:
                self._blit_key(self.userword,step)
                self._word_complete() # We don't return
            else:
                self._blit_key(self.userword,step)
                self.score = 1
                if len(self.objs_to_move) > 0: # erase arrow
                    obj = self.objs_to_move.pop()
                    obj.erase()
                    self.dirty_rects.append((obj.rect))
                    # create new arrow
                    x = self.arrowdic[key][0] + self.offset
                    y = self.wordcoor[1]-132
                    self.objs_to_move.append((Arrow((x,y),self.end-20)))
                    self.offset = x
        else:
            self.score = -1
            Snd.bummer.play(1)
        return 0
    
    def _blit_key(self,seq,step):
        seqsurf,spam = my_font2surf(seq,self.fontsize,self.cpg,\
                                    self.fcol,self.ttf)
        rec = seqsurf.get_rect()
        rec.move_ip(self.usercoor)
        old = self.screen.blit(Img.backgr,rec,rec)
        new = self.screen.blit(seqsurf,rec)
        pygame.display.update([old,new])
        
    def _word_complete(self):
        if len(self.objs_to_move) > 0: #erase arrow
            obj = self.objs_to_move.pop()
            obj.erase()
            self.dirty_rects.append((obj.rect))
        #print 'complete word'
        Snd.wahoo.play()
        self.score += 20
        self.stop = -1
