# -*- coding: utf-8 -*-
#
# Copyright (c) 2006 Miguel Pérez Francisco <mperez@icc.uji.es>
#
#           puzzle.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.

## puzzle.py, an image is splited in rectangular pieces, you have to compose the original image.
## Age 3-5

DEBUG = 0
RCFILE = 0

import os,sys,random,glob
import pygame
from pygame.constants import *
from utils import load_image,load_sound,MyError,import_module,ScaleImages
from CPConstants import HOMEDIR

# TODO: The pieces now are rectangular. Change it to have a more real form

########################################
# Constats definition
########################################

# Position of the splitted image
INIX=20
INIY=20

# Position of the target image
INIXF=450
INIYF=20

# Offset between the position of the mouse and the piece being translated
OFFSETIMGX=30
OFFSETIMGY=30

# Size of the lines between pieces
TAMLINEA=2

#Position of the thumbnail of the image
INIXTH,INIYTH=350,400


class Img:
    pass
class Snd:
    pass

class Pieze(pygame.sprite.Sprite):
    """ A pieze of a puzzle """
    def __init__(self,image):
        pygame.sprite.Sprite.__init__(self) #call Sprite initializer
        self.image = image
        self.rect = image.get_rect()
        
    def update(self):
        "move the image based on the mouse position"
        pos = pygame.mouse.get_pos()
        self.rect.midtop = pos

    def set_position(self,pos):
        self.rect.move_ip(pos)


class Game:
    """  puzzle.py - part of childsplay.py, a suite of educational games for
  young children.
  """

    def __init__(self,screen,backgr,rc_dic,basepath,libdir,cpg):
        self.screen = screen
        self.backgr = backgr
        self.rc_dic = rc_dic
        self.myimages = []      
        self.basedir  = basepath

        self.pressed = 0
        self.pieceselected = None
        self.bonus = 0
        try:
            import pyassetmlSDL
            #assetmlSDL = import_module(os.path.join(self.basedir,'pyassetmlSDL.py'))
        except (ImportError,MyError),info:
            print >> sys.stderr,info,"\nThis version of childsplay depends on pyassetmlSDL"
            text = "Module memory fails to import pyassetmlSDL"
            raise MyError,text

        # create two assetmlSDL instances one for parsing images and one for sounds
        self.Assets_img = pyassetmlSDL.AssetmlSDL()
        self.Assets_img.set_mldir('childsplay/memory-136x136/memory-136x136.assetml')
        self.Assets_snd = pyassetmlSDL.AssetmlSDL()
        self.Assets_snd.set_mldir('childsplay/childsplay-sounds/childsplay-sounds.assetml')
        
        self.libdir = libdir

        try:
            self.myimages = glob.glob(os.path.join(HOMEDIR,'puzzle','my_images','*'))
        except Exception,info:
            print info
            self.myimages = []
        if DEBUG: print "Contents of my_images", self.myimages
        if len(self.myimages) < 1:
            self.myimages = None
            
        self.score = 0
        # gamelevels (level,(nx,ny,points))
        # level:  a numeric value
        # nx, ny: number of pieces in x and y
        # points: for this level
        
        self.gamelevels = [(0,(2,2,100)),
                           (1,(3,2,100)),
                           (2,(3,3,200)),
                           (3,(4,3,300)),
                           (4,(4,4,500))]
        #self.gamelevels = [(1,(2,2,100)), (1,(2,3,100))]
        self.gameitems = [1,2,3,4]
        
        # Image Size, by now these values has to be "divisibles" by 2,3,4,5,6
        self.xsize = 324
        self.ysize = 324
        # TODO: put the x and y size in funtion of the real x and y size of the image

        self._setup()
    
        
    def _setup(self):
        
        files = ('bummer.wav','wahoo.wav')
        self.Sound = Snd()
        self.Image = Img()
        self.Assets_snd.get_assets(files,self.Sound)

    def load_puzzle(self):
        """  Load an image. to split, it choose one between the images in
        # myimages folder and the childsplay images.
        """

        # Select the image to split, choose one between the images in
        # myimages folder and the childsplay images
        if self.myimages and random.randint(0,1):
            imn=random.randint(0,len(self.myimages)-1)
            self.image=load_image(self.myimages[imn])
        else:
            pzimages = glob.glob(os.path.join(self.libdir,'puzzleData','*.png'))
            imn=random.randint(0,len(pzimages)-1)
            self.image=load_image(pzimages[imn])
        # we don't upscale all images are 324x324
        #self.image=pygame.transform.scale(self.image,(self.xsize,self.ysize))

        self.pieces=[]
        self.posiciones=[] # The position of each pieze

        # Split the surface in pieces
        ix=0
        px=self.incx*ix
        while px<self.xsize:
            iy=0
            py=self.incy*iy
            while py<self.ysize:
                self.posiciones.append((INIX+px,INIY+py))
                pieze=self.image.subsurface(pygame.Rect((px,py),(self.incx,self.incy)))
                pieze=Pieze(pieze)
                self.pieces.append(pieze)
                iy=iy+1
                py=self.incy*iy
            ix=ix+1
            px=self.incx*ix
                
        random.shuffle(self.posiciones)
        self.posicionesoriginales=self.posiciones[:]

        # TODO: Use sprites and groups with the draw method to draw
        # only the moved parts
        # self.allsprites = pygame.sprite.RenderPlain(self.pieces)

        return
    
    def helptitle(self):
        return _("Puzzle")
    
    def __str__(self):
        """Must return the original, not translated, title of this game.
        It's needed by the high score class of childsplay."""        
        return "Puzzle"
    
    def help(self):
        text = [_("The aim of the game:"),
        _("Compose an image: You have to take the pieces from the left image and put them in their right position of the right image."),
        " ",
        _("Difficulty : 3-5 years"),
        " ",
        _("Number of levels : 5")]
        
        return text 
    
    def start(self,level,spam):
        """Puzzle game"""
        self.stop,self.score = 0,0
        self.rows, self.cols ,self.bonus = level[1]
        self.npieces=self.cols*self.rows
        # bonusp is the score for each piece put in its place
        self.bonusp=self.bonus/self.npieces
        # size of a piece
        self.incx=self.xsize/self.cols
        self.incy=self.ysize/self.rows
        #TODO: Control that the previous two divisions are exact
        
        self.create_puzzle()

        #TODO: A button to advance in level. This should affect to the bonus???

    def show_image(self):
        """draw the piezes of the selected image"""
        ix=0
        iy=0
        for pieze in self.pieces:
            self.screen.blit(pieze.image, (INIX+ix*(self.incx),
                                           INIY+iy*(self.incy)),
                             pygame.Rect(0,0,self.incx,self.incy))
            iy+=1
            if iy==self.rows:
                iy=0
                ix+=1


    
    def create_puzzle(self):
        """ Loads an image and split it"""

        self.load_puzzle()

        #self.ball=self.pieces[0].image
        #self.ballrect=self.pieces[0].rect
        #self.ballrect = ball.get_rect()

        self.ok=[0]*len(self.pieces)

        # Create a thumbnail of the image
        # TODO: scale the thumbnail in relation to the image size  
        self.puzzlethumb=pygame.transform.scale(self.image,(75,100))

        self.refresh_screen(100)
        
    def refresh_screen(self,retardo=None):
        """ Draw the all the parts of the game"""

        #TODO: Update only the parts that have been moved, with
        #sprites and groups

        # Draw the background
        self.screen.blit(self.backgr,(0,0))

        # Draw the thumbnail 
        self.screen.blit(self.puzzlethumb,(INIXTH,INIYTH))

        # Draw the contour of the target pieces 
        pygame.draw.rect(self.screen,(0,0,0),pygame.Rect(INIXF,INIYF,self.xsize,self.ysize),TAMLINEA)
        for rows in range(1,self.rows):
            pygame.draw.rect(self.screen,(0,0,0),pygame.Rect(INIXF,INIYF+(self.incy)*rows,self.xsize, TAMLINEA),TAMLINEA)
        for cols in range(1,self.cols):
            pygame.draw.rect(self.screen,(0,0,0),pygame.Rect(INIXF+(self.incx)*cols,INIYF,TAMLINEA,self.ysize),TAMLINEA)

        # Draw the pieces  
        i=0
        ix=0
        iy=0        
        for pieze in self.pieces:
            self.screen.blit(pieze.image, self.posiciones[i])
            iy+=1
            if iy==self.rows:
                iy=0
                ix+=1
            i=i+1
            #TODO: 
            #if retardo is not None:
            #    pygame.time.wait(retardo)
            #    pygame.display.update((self.posiciones[i][0],self.posiciones[i][1],self.incx,self.incy))
                

        # Draw the contour of the source pieces 
        pygame.draw.rect(self.screen,(0,0,0),pygame.Rect(INIX,INIY,self.xsize,self.ysize),TAMLINEA)
        for rows in range(1,self.rows):
            pygame.draw.rect(self.screen,(0,0,0),pygame.Rect(INIX,INIY+(self.incy)*rows,self.xsize, TAMLINEA),TAMLINEA)
        for cols in range(1,self.cols):
            pygame.draw.rect(self.screen,(0,0,0),pygame.Rect(INIX+(self.incx)*cols,INIY,TAMLINEA,self.ysize),TAMLINEA)
            
        # Draw the selected pieze so it appears always on top
        if self.pieceselected is not None:
            self.screen.blit(self.pieces[self.pieceselected].image,
                             self.posiciones[self.pieceselected])
        
        pygame.display.update()

    def put_piece_in_original_place(self,np):
        """ put a piece in its original place """
        self.posiciones[np]=self.posicionesoriginales[np]
        
    def put_piece_in_target_place(self,np):
        """put a piece in its target place """
        ix=np/self.rows
        iy=np%self.rows
        self.posiciones[np]=(INIXF+ix*(self.incx),
                             INIYF+iy*(self.incy))
        
    def is_in_target_place(self,targetpos,np):
        """ return true if the targetpos position is inside the target place."""
        ix=np/self.rows
        iy=np%self.rows

        targetrect=pygame.Rect((INIXF+ix*(self.incx),
                               INIYF+iy*(self.incy)),
                               (self.incx,self.incy))
        self.ok[np]=1
       
        return targetrect.collidepoint((targetpos[0]+self.offsetimgx,targetpos[1]+self.offsetimgy))

    def loop(self,events):
        """ loop of the game """
        self.score = 0

        oka=0
        for event in events:
            if event.type == QUIT:
                break
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                break
            if event.type == MOUSEBUTTONDOWN:

              # if a piece was selected
              if self.pressed:
                self.pressed=0
                targetpos=self.posiciones[self.pieceselected]
                if not(self.is_in_target_place(targetpos,self.pieceselected)):
                    self.Sound.bummer.play()
                    self.bonus=self.bonus-self.bonusp
                    self.put_piece_in_original_place(self.pieceselected)
                else:
                    self.score=self.bonusp
                    self.put_piece_in_target_place(self.pieceselected)
                    self.Sound.wahoo.play()
                    oka=1
                    for i in range(self.npieces):
                        oka=oka*self.ok[i]
                        
              # if a piece was not selected, select it if it is on the
              # source board
              else:
                pos_mouse=pygame.mouse.get_pos() 

                findpiece=0
                acpiece=0
                aux=0
                while (not findpiece and acpiece<len(self.pieces)):
                    if pygame.Rect(self.posiciones[acpiece],
                                   (self.incx,self.incy)).collidepoint(pos_mouse):
                        #mouse position
                        pos_mouse=pygame.mouse.get_pos()
                        self.pieceselected=acpiece

                        self.offsetimgx=pos_mouse[0]-self.posiciones[self.pieceselected][0]
                        self.offsetimgy=pos_mouse[1]-self.posiciones[self.pieceselected][1]

                        mousex=pos_mouse[0]-self.offsetimgx
                        mousey=pos_mouse[1]-self.offsetimgy
                        aux=acpiece
                        findpiece=1
                    else:
                        acpiece=acpiece+1
                        
                # Test if the piece is on the original position
                if findpiece and pygame.Rect((INIX,INIY),(self.xsize,self.ysize)).collidepoint(pos_mouse):
                    self.pressed=1
                    self.posiciones[self.pieceselected]=((mousex,mousey))



        if self.pressed==1:
            pos_mouse=pygame.mouse.get_pos() 
            mousex=pos_mouse[0]-self.offsetimgx
            mousey=pos_mouse[1]-self.offsetimgy
            self.posiciones[self.pieceselected]=((mousex,mousey))
            #print self.posiciones[self.pieceselected]
            #print self.pressed
        

        self.refresh_screen()

        if oka:
            self.score = self.bonus
            #TODO: play a sound
            pygame.time.wait(1500)

        self.stop=-oka

        return self.stop,self.score

