#!/usr/bin/env python

# -*- coding: utf8 -*- 

#***********************************************************************
# pysycache : a program for learn to use the mouse
# Copyright (C) 2005-2007 Vincent DEROO (vincent.pysycache@free.fr) 
# 
# 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. : 
# 51 Franklin Street, Fifth Floor, Boston, MA02110-1301, USA
#***********************************************************************



#*******************************************************************************
# Importation des modules
#*******************************************************************************
import sys
import getopt, string
import random
import time

import random, os
import pygame
from pygame.locals import *
import datas
from pysyclasses import *
import const


PIECEPOSED = 1
PIECENOTPOSED = 0

NODRAG = 0
DRAGSTARTED = 1

PIECELOIN = 20
PIECEPRES = 21





#*******************************************************************************
#                                     Classe                                   #
#*******************************************************************************


class MovedPiece(pygame.sprite.Sprite):
	"""This class is for the pieces during the drag and drop """
	def __init__(self, filename, mouseleft, mousetop, targetleft, targettop, id):
		pygame.sprite.Sprite.__init__(self) 				#call Sprite intializer
		dirname = os.path.join("", filename, "1")
		self.image, self.rect = datas.Load_image(dirname, filename)
		(self.width, self.height) = self.image.get_size()
		self.rect.left = mouseleft - int(self.width / 2)
		self.rect.top = mousetop - int(self.height / 2)
		self.targetleft = targetleft
		self.targettop = targettop
		self.id = id
		self.left = self.rect.left 
		self.top = self.rect.top
		screen = pygame.display.get_surface()  
		screen.blit(self.image, (self.left, self.top))

	def move(self, mouseleft, mousetop, background, ecart):
		#deplacement de l'element
		#on va effacer le dessous
		screen = pygame.display.get_surface()  
		tr2 = pygame.Rect([self.left, self.top, self.width, self.height])
		screen.blit(background, (self.left, self.top), tr2)

		self.rect.left = mouseleft - int(self.width / 2)
		self.rect.top = mousetop - int(self.height / 2)

		ok = 0
		if const.GModeJeu == const.MODEFANTOM :
			if const.GIdPieceToDrop == self.id:
				ok = 1
		else:
			ok = 1

		if ok == 1:
			#on doit verifier la proximite
			if ( self.rect.left + ecart > self.targetleft) & ( self.rect.top + ecart > self.targettop) & (self.rect.left + self.width - ecart < self.targetleft + self.width ) & ( self.rect.top + self.height - ecart < self.targettop + self.height) :
				#on est proche de la cible... on met la souris en rose que si on 
				#etait loin avant
				if const.GTypeSouris == PIECELOIN :
					for o in const.GLstSouris.sprites():
						o.changepicture('souris-puzzlepink.png')
					const.GTypeSouris = PIECEPRES
			else:
				#on est loin de la cible... si avant on etait pres... on passe
				#la souris en normal
				if const.GTypeSouris == PIECEPRES :
					const.GTypeSouris = PIECELOIN
					for o in const.GLstSouris.sprites():
						o.changepicture('souris-puzzle.png')

		self.left = self.rect.left 
		self.top = self.rect.top


class Piece:
	"""A piece of the jigsaw """
	targetleft = 0		#position sur le modele
	targettop = 0
	boxleft = 0			#position dans la boite
	boxtop = 0
	boxlargeur = 0
	boxhauteur = 0
	filename = ''
	backgrd = ''		#image de fond pour le mode fantome
	id = 0
	visible = PIECENOTPOSED		#0 : la piece n'a pas ete posee
								#1 :          a ete posee


#*******************************************************************************
#
#*******************************************************************************
class ApplicationPuzzle(ApplicationPysy):
	def __init__(self):
		ApplicationPysy.__init__(self)
		
		self.ImgBackground = ""
		self.ImgModele = ""
		self.EcartPiece = 40			#ecart pour le placement des pieces
		self.GIdxPremPieceCoffre = 0	#indice de la premiere piece visible du coffre
		self.PieceMoved = pygame.sprite.RenderClear()

	def InitializeApp(self, DirThemes, ActName):
		ApplicationPysy.InitializeApp(self, DirThemes, ActName)

		self.BackgroundBox, rectmp = datas.Load_image("images", 'fond-' + self.ActivityName + '.png')
		if const.GWithSound == 1:
			if const.GSoundError == 0:
				self.Channel0 = pygame.mixer.Channel(0)
				music = os.path.join(const.GRepPysycache, 'sounds', 'slide.wav').encode(const.GConsoleLocale)
				self.Sound0 = pygame.mixer.Sound(music)
		self.PuzzleWidth = 0
		self.PuzzleHeight = 0
		self.WaitForClick = True


	#***************************************************************************
	# Retour 0 : on a pas gagne
	#        1 : on a gagne  
	#***************************************************************************
	def OnAGagne(self, gagne):
		if (const.GNbPieces == 0):
			gagne = 1
		else:
			gagne = 0
		return gagne


	#***************************************************************************
	#
	#***************************************************************************
	def DoPlayerGagne(self):
		screen = pygame.display.get_surface()
		Imggagne, rectgagne = datas.Load_image("", self.ImgBackground, None, True)
		self.Background.blit(Imggagne, (0 + const.MARGELEFT + 27, 0 + const.MARGETOP))
		screen.blit(Imggagne, (0 + const.MARGELEFT + 27, 0 + const.MARGETOP))
		pygame.display.update()
		pygame.time.wait(2000)


	#***************************************************************************
	#
	#***************************************************************************
	def GetPieceToDrop(self):
		if const.GModeJeu == const.MODEFANTOM :
			#on va designer la piece a installer
			if const.GNbPieces > 0:
				x = random.randint(0, const.GNbPieces - 1)
				cpt = 0
				for pzl in const.GTabPuzzles:
					if pzl.visible == PIECEPOSED:
						#piece deja posee
						pass
					else:
						if cpt == x:
							#c'est cette piece qu'il faut poser
							screen = pygame.display.get_surface()  
							ImgATrouv, recttmp = datas.Load_image("", pzl.backgrd , None, True)
							w, h = ImgATrouv.get_size()
							w2 = int(w * self.PuzzleWidth / 640)
							h2 = int(h * self.PuzzleHeight / 480)
							ImgATrouv = pygame.transform.scale(ImgATrouv, (w2, h2) )
							self.Background.blit(ImgATrouv, (pzl.targetleft, pzl.targettop))
							const.GIdPieceToDrop = pzl.id
							break
						cpt += 1
		else:
			const.GIdPieceToDrop = 999


	#***************************************************************************
	#
	#***************************************************************************
	def InitActivity(self, WithHasard):
		ApplicationPysy.InitActivity(self, WithHasard)

		const.StateOfDrag = NODRAG
		const.GTypeSouris = PIECELOIN
		const.GIdxMovedPiece = 0	

		self.ImgFond, background_rect = datas.Load_image("", self.ImgModele, None, True)

		screen = pygame.display.get_surface()  

		#on copie ce cache sur l'image de fond
		screen = pygame.display.get_surface()
		self.Background.blit(self.ImgFond, (0 + const.MARGELEFT + 27, 0 + const.MARGETOP))

		self.GetPieceToDrop()

		#afficher les pieces du puzzle dans le coffre
		self.GIdxPremPieceCoffre = 0
		self.ShowPiecesOfPuzzle()


	#***************************************************************************
	#
	#***************************************************************************
	def MotionAfterMouse(self, event0, event1, str):
		ApplicationPysy.MotionAfterMouse(self, event0, event1, str)

		if (str[0] == 0) & (str[1] == 0) & (str[2] == 0):
			#on bouge sans avoir enfonce de bouton...
			#l'etat de la souris est a 0 0 0

			if (const.GStateOfDrag == DRAGSTARTED) :
				#... mais on est en statut drag 'n drop ...
				#ce n'est pas normal
				screen = pygame.display.get_surface()  
				screen.blit(self.Background, (0, 0))
				const.GStateOfDrag = NODRAG
				for o in const.GLstSouris.sprites():
					o.changepicture('souris-puzzle.png')		#la souris n'est rose qu'en mode drag

		if (const.GStateOfDrag == DRAGSTARTED) :
			#on deplace la piece en meme temps que la souris
			for pce in self.PieceMoved.sprites() :
				pce.move(event0, event1, self.Background, self.EcartPiece)

			screen = pygame.display.get_surface()  
			self.PieceMoved.draw(screen)


	#***************************************************************************
	#
	#***************************************************************************
	def DoOnMouseDown(self, event0, event1, str):
		ApplicationPysy.DoOnMouseDown(self, event0, event1, str)

		#recherche si n'est pas un des deux boutons avant/apres
		if ( event0 + const.DEMISOURIS >= 0 ) & ( event0 + const.DEMISOURIS <= 64) & ( event1 + const.DEMISOURIS >= 487 ) & ( event1 + const.DEMISOURIS <= 551 ) :
			#pieces avant
			self.GIdxPremPieceCoffre = self.GIdxPremPieceCoffre - 1
			if self.GIdxPremPieceCoffre < 0:
				self.GIdxPremPieceCoffre = 0
			self.ShowPiecesOfPuzzle()
			#et recopier la derniere piece (car chevauchement)
			self.ShowBtnMenus()
		if ( event0 + const.DEMISOURIS >= 648 ) & ( event0 + const.DEMISOURIS <= 712) & ( event1 + const.DEMISOURIS >= 487 ) & ( event1 + const.DEMISOURIS <= 551 ) :
			#pieces apres
			self.GIdxPremPieceCoffre += 1
			if self.GIdxPremPieceCoffre > len( const.GTabPuzzles) - 1:
				self.GIdxPremPieceCoffre = len( const.GTabPuzzles) -1
			self.ShowPiecesOfPuzzle()
			#et recopier la derniere piece (car chevauchement)
			self.ShowBtnMenus()

		i = 0
		screen = pygame.display.get_surface()

		#----------------- recherche si est une piece a deplacer ------------
		#on ne fait pas deplacer si en dehors de la zone 
		if const.GChrono == 1:
			y = int(60 - float(pygame.time.get_ticks() - const.GTpsDebut)/1000)

			if y == 5:
				imgchrono, rectchrono = datas.Load_image("images", "chrono4.png")
				self.Background.blit(imgchrono, (736, 10))
				screen.blit(imgchrono, (736, 10))
			elif y == 15:
				imgchrono, rectchrono = datas.Load_image("images", "chrono3.png")
				self.Background.blit(imgchrono, (736, 10))
				screen.blit(imgchrono, (736, 10))
			elif y == 30:
				imgchrono, rectchrono = datas.Load_image("images", "chrono2.png")
				self.Background.blit(imgchrono, (736, 10))
				screen.blit(imgchrono, (736, 10))
			elif y >= 58:
				imgchrono, rectchrono = datas.Load_image("images", "chrono1.png")
				self.Background.blit(imgchrono, (736, 10))
				screen.blit(imgchrono, (736, 10))

		for obj in const.GTabPuzzles:
			if ( event0 + const.DEMISOURIS >= obj.boxleft ) & ( event0 + const.DEMISOURIS <= obj.boxleft + obj.boxlargeur ) & ( event1 + const.DEMISOURIS >= obj.boxtop  ) & ( event1 + const.DEMISOURIS <= obj.boxtop + obj.boxhauteur ) :
				#on va commencer a faire glisser la piece
				const.GStateOfDrag = DRAGSTARTED
				const.GTypeSouris = PIECELOIN 
				#on recupere la piece qu'il faut deplacer
				const.GIdxMovedPiece = obj.id
				self.PieceMoved.empty()
				self.PieceMoved.add(MovedPiece(obj.filename, event0, event1, obj.targetleft, obj.targettop, obj.id))

				self.PieceMoved.draw(screen)
#				pygame.display.update()

				break
			i += 1

		const.GLstSouris.draw(screen)
		pygame.display.update()


	#***************************************************************************
	#
	#***************************************************************************
	def DoOnMouseUpAfterButtons(self, event0, event1):
		ApplicationPysy.DoOnMouseUpAfterButtons(self, event0, event1)

		ok = 0
		if (const.GStateOfDrag == DRAGSTARTED) :
			#on est a la fin du deplacement
			screen = pygame.display.get_surface()  

			if (const.GTypeSouris == PIECEPRES) :
				cpt = 0
				for pzl in const.GTabPuzzles:
					if (pzl.id == const.GIdxMovedPiece) :
						#on recherche la piece concernee
						if const.GModeJeu == const.MODEFANTOM :
							if const.GIdPieceToDrop == pzl.id:
								ok = 1
						else:
							ok = 1

						if ok == 1:
							#on informe que la piece est posee
							pzl.visible = PIECEPOSED

							self.PieceMoved.empty()
							datas.DebugMessage( "I put the piece id " + str(pzl.id) + " with the visibility " + str(pzl.visible))

							#on colle la piece a sa position 
							filename = os.path.join(self.LstThemesOfActivity[const.GIdxThemes], "1", pzl.filename)
							imgtmp, background_rect = datas.Load_image("", pzl.filename, None, True)
							self.Background.blit(imgtmp, (pzl.targetleft, pzl.targettop))
							ok = 1

							#on joue la musique
							if const.GWithSound == 1:
								if const.GSoundError == 0:
									self.Channel0.play(self.Sound0)

							#on diminue le nombre de pieces restants
							const.GNbPieces = const.GNbPieces - 1
							datas.DebugMessage("")
							datas.DebugMessage("Number of leaving pieces " + str(const.GNbPieces))
							del const.GTabPuzzles[cpt]

						#On redessine la souris en blanc
						for o in const.GLstSouris.sprites():
							o.changepicture('souris-puzzle.png')

						#on recharge les pieces du puzzle
						self.GetPieceToDrop()
						if const.GModeJeu == const.MODEFANTOM :
							#effacer la zone de l'ecran concernant la boite a piece
							screen = pygame.display.get_surface()  
							self.Background.blit(self.BackgroundBox, (67, 487), (67, 487, 640, 110))

						self.ShowPiecesOfPuzzle()
						screen.blit(self.Background, (0, 0))
						#et recopier la derniere piece (car chevauchement)
						self.ShowBtnMenus()

						break
					cpt += 1
			else:
				datas.DebugMessage("trop loin")
				for o in const.GLstSouris.sprites():
					o.changepicture('souris-puzzle.png')
				screen.blit(self.Background, (0, 0))

			#redessin de la souris a sa position 
			const.GLstSouris.draw(screen)
			pygame.display.update()
		const.GStateOfDrag = NODRAG


	#***************************************************************************
	#
	#***************************************************************************
	def DoInitLevel(self):
		""" """
		ApplicationPysy.DoInitLevel(self)

		self.EcartPiece = 60
		if const.GLevel == 0:
			self.EcartPiece = 60
		elif const.GLevel == 1 :
			self.EcartPiece = 40
		else:
			self.EcartPiece = 20


	#***************************************************************************
	#    
	#***************************************************************************
	def GetLevelForDfgFile(self, levelname):
		return str(const.GLevel)


	#***************************************************************************
	#    
	#***************************************************************************
	def ReadDfgFile(self):
		""" Charge le fond a partir d'un fichier de configuration contenus dans le repertoire"""
		ApplicationPysy.ReadDfgFile(self)

		#effacer l'existant
		const.GTabPuzzles[:] = []

		#------------------ on va lire le fichier de configuration -----------------
		configname = self.LstFicConfig[self.IdxFileDfg]

		datas.DebugMessage("")
		datas.DebugMessage("dfg file (number : " + str(self.IdxFileDfg) + ") named " + configname)

		(dirpath, dirname) = os.path.split(configname)

		cpt = 0
		i = 0
		nb1 = 0
		f = open(configname,'rb') 
		lignes = f.readlines()
		for lig in lignes:
			lig = lig.strip()
			if len(lig) == 0:
				continue

			if cpt == 0:
				#fond de l'image
				#chargement du dessin servant de fond
				(f1, f2) = os.path.split(dirpath)
				
				lig = lig.split('|')
				if len(lig) == 3:
					self.PuzzleWidth = int(lig[1])
					self.PuzzleHeight = int(lig[2])
					self.ImgBackground = os.path.join(f1, lig[0])
				else:
					self.PuzzleWidth = 640
					self.PuzzleHeight = 480
					self.ImgBackground = os.path.join(f1, lig[0])

			if cpt == 1:
				#le modele du puzzle
				self.ImgModele  = os.path.join(dirpath, lig)

			if cpt >= 2:
				#les morceaux du puzzle
				pce = Piece()

				lig = lig.split('|')

				pce.targetleft = int(lig[1]) + const.MARGELEFT + 27
				pce.targettop = int(lig[2]) + const.MARGETOP
				pce.filename = os.path.join(dirpath, lig[0])
				pce.backgrd =  os.path.join(dirpath, lig[3])
				pce.id = i

				const.GTabPuzzles.append(pce)

				i += 1

			cpt += 1
		f.close()

		#MAJ du nombre de piece a voir
		const.GNbPieces = i


	#***************************************************************************
	# Affiche les pieces du puzzle dans le coffre
	#***************************************************************************
	def ShowPiecesOfPuzzle(self):
		NbPieceCoffre = 5

		#effacer la zone de l'ecran concernant la boite a piece
		screen = pygame.display.get_surface()  
		self.Background.blit(self.BackgroundBox, (67, 487), (67, 487, 640, 110))
		screen.blit(self.BackgroundBox, (67, 487), (67, 487, 640, 110))

		#afficher les pieces
		i = 0
		cptvisible = 0
		for pzl in const.GTabPuzzles:
			datas.DebugMessage ("i=" + str(i) + " visible = " + str(pzl.visible))
			if cptvisible >= NbPieceCoffre :
				pzl.boxleft = -1
				pzl.boxtop = -1
			else:
				if i >= self.GIdxPremPieceCoffre:
					if pzl.visible == PIECENOTPOSED :
						#la piece n'est pas posee : on peut donc l'afficher
						imgtmp, self.rect = datas.Load_image("", pzl.filename, None, True)

						width = 0
						height = 0
						(pzl.largeur, pzl.hauteur) = imgtmp.get_size()
						coefwidth = float(pzl.largeur) / 116			#largeur admissible pour les pieces posees
						coefheight = float(pzl.hauteur) / 107			#hauteur admissible pour les pieces posees
						if coefwidth > coefheight :
							coefimg = coefwidth
						else :
							coefimg = coefheight
						pzl.coef = coefimg

						pzl.boxlargeur = int(pzl.largeur / coefimg)
						pzl.boxhauteur = int(pzl.hauteur / coefimg)
						imgtmp = pygame.transform.scale(imgtmp, (pzl.boxlargeur, pzl.boxhauteur ))
						pzl.boxleft = 69 + 116 * cptvisible
						pzl.boxtop = 489
						self.Background.blit(imgtmp, (pzl.boxleft, pzl.boxtop))
						screen.blit(imgtmp, (pzl.boxleft, pzl.boxtop))
						cptvisible += 1
					else:
						pzl.boxleft = -1
						pzl.boxtop = -1
				else:
					pzl.boxleft = -1
					pzl.boxtop = -1
			i += 1

		if cptvisible == 0:
#			i = 0
#			for pzl in const.GTabPuzzles:
#				if i <= self.GIdxPremPieceCoffre :
#					if pzl.visible == PIECENOTPOSED :
#						cptvisible += 1
#				else:
#					break
#					
#				i += 1
			self.GIdxPremPieceCoffre = self.GIdxPremPieceCoffre - 1
			if self.GIdxPremPieceCoffre >= 0:
				self.ShowPiecesOfPuzzle()
