#!/usr/bin/python
# -*- coding: Utf-8 -*-

import os, Image, shutil, glob, string
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from gui_modules_animation.animation_base import Base
from moteur_modules_animation.mencoder import WidgetMEncoder
from moteur_modules_animation.mplayer import Mplayer
from gui_modules_lecture.affichage_image.afficheurImage import VisionneurImagePourEKD


class Animation_ConvertirImgEnAnim(QWidget):
	"""-----------------------------------------
	# Cadre accueillant les widgets de :
	# Animation >> convertir images en animations
	# -----------------------------------------"""
	def __init__(self, parent):
		QWidget.__init__(self)
		
		# -------------------------------
		# Parametres généraux du widget
		# -------------------------------
		self.base = Base(self) # module de animation
		
		# création des répertoires temporaires
		if os.path.isdir('/tmp/ekd/tampon/conv_img_en_video') is False:
        		os.makedirs('/tmp/ekd/tampon/conv_img_en_video')
		
		#=== tout sera mis dans une boîte verticale ===#
		vbox=QVBoxLayout(self)
		
		#=== Variable de configuration ===#
		self.config=parent.config
		
		# Identifiant de la classe
		self.idSection = 'Animation - Convertir des Images en Video'
		self.base.printSection()
		
		self.statusBar = parent.statusBar()
		#self.statusBar = QStatusBar()
		
		# -------------------------------------------------------------------
		# Boîte de groupe : "Fichier vidéo source"
		# -------------------------------------------------------------------
		self.base.widgetSource(vbox, _(u"Fichiers images sources"))
		
		# -------------------------------------------------------------------
		# Boîte de groupe "Réglage de sortie de l'encodage"
		# -------------------------------------------------------------------
		
		#=== Création de la boite de groupe de réglage (contenant la boite self.layoutReglage) ===#
		self.base.widgetReglage(vbox, nomReglage=_(u"Réglages"), boite='grid')
		
		#=== Widget qui seront inclus dans la boite de réglage ===#
		
		#||| titre |||#
		txt = _(u"Nombre d'images/s")
		label = QLabel("<u>%s</u> :" %txt)
		self.layoutReglage.addWidget(label,0,0,1,2,Qt.AlignHCenter)
		txt = _(u"Codecs")
		label = QLabel("<u>%s</u> :" %txt)
		self.layoutReglage.addWidget(label,0,3,Qt.AlignHCenter)
		
		#||| Stacked |||#
		
		# Élement par défaut du stacked
		
		# Le codec mpeg1 prenant un nombe limité de valeurs
		# il n'aura pas droit à son spin mais à une boite de combo
		self.comboMPEG1 = QComboBox()
		listeComboMPEG1 = ['5','10','12','15','24','25','30','50','60']
		for i in listeComboMPEG1:
			self.comboMPEG1.addItem(i)
		self.connect(self.comboMPEG1,SIGNAL("currentIndexChanged(int)"),self.comboMPEG1Change)
		
		self.frameCombo = QFrame()
		boiteFrame = QHBoxLayout()
		boiteFrame.addWidget(self.comboMPEG1)
		self.frameCombo.setLayout(boiteFrame)
		
		# autre élément du stacked
		
		self.spin = QSpinBox()
		self.spin.setRange(1,100) # 25 par défaut
		
		self.curseur = QSlider(Qt.Horizontal)
		self.curseur.setRange(1,100)
		self.curseur.setMaximumSize(175,175)
		
		self.FrameSpinCurseur = QFrame()
		boiteFrame = QHBoxLayout()
		boiteFrame.addWidget(self.spin)
		boiteFrame.addWidget(self.curseur)
		self.FrameSpinCurseur.setLayout(boiteFrame)
		
		# remplissage du stacked
		
		self.stacked = QStackedWidget()
		self.stackedCombo = self.stacked.addWidget(self.frameCombo)
		self.stackedspinCurseur = self.stacked.addWidget(self.FrameSpinCurseur)
		
		self.layoutReglage.addWidget(self.stacked,1,0, Qt.AlignCenter)
		
		#||| boite de combo |||#
		
		self.combo=QComboBox() # le self sert à afficher des informations sur les items à partir de la fonction

		listeCombo=[(_(u'MPEG1 video'),	'mpeg1video'),\
			(_(u'Motion JPEG'),	'mjpeg'),\
			(_(u'H263 Plus'),	'h263p'),\
			(_(u'DivX 4-5'),	'mpeg4'),\
			(_(u'MS-MPEG4v2'),	'msmpeg4v2'),\
			(_(u'Lossless JPEG'),	'ljpeg')]
		
		# Insertion des codecs de compression dans la combo box
		for i in listeCombo:
                	self.combo.addItem(i[0],QVariant(i[1]))
		
		self.layoutReglage.addWidget(self.combo,1,3)
		
		self.connect(self.spin,SIGNAL("valueChanged(int)"), self.spinChange)
		self.connect(self.curseur,SIGNAL("sliderMoved(int)"), self.curseurBouge)
		self.connect(self.combo,SIGNAL("currentIndexChanged(int)"),self.stackedChange)
		
		# [bidouillage] espacement entre les 2 colonnes
		# Rq: spacing espace les cellules en horizontal et en vertical -> pas joli
		self.layoutReglage.addWidget(QLabel("         "),0,2)
		self.layoutReglage.addWidget(QLabel("         "),1,2)
		self.layoutReglage.setAlignment(Qt.AlignHCenter)
		
		# Chargement des paramètres de configuration
		try:
			typ = self.config.get(self.idSection,'codec')
			indice = 0 # indice de la ligne de self.listeCombo correspondant au type d'ordre
			for i in listeCombo:
				if i[1]!=typ:
					indice += 1
				else:
					break
			self.combo.setCurrentIndex(indice)
		except:
			self.combo.setCurrentIndex(0)
		
		try:
			spin = int(self.config.get(self.idSection,'nbr_img_sec'))
			self.spin.setValue(spin)
		except:
			self.spin.setValue(25)
		
		try:
			spin = self.config.get(self.idSection,'nbr_img_sec_mpeg1video')
			indice = 0 # indice de la ligne de self.listeCombo correspondant au type d'ordre
			for i in listeComboMPEG1:
				if i!=spin:
					indice += 1
				else:
					break
			self.comboMPEG1.setCurrentIndex(indice)
		except:
			# Valeur 25 sélectionnée par défaut
			indice = 0 # indice de la ligne de self.listeCombo correspondant à 25
			for i in listeComboMPEG1:
				if i!='25':
					indice += 1
				else:
					break
			self.comboMPEG1.setCurrentIndex(int(indice))
		
		#----------
		# Onglets
		#----------
		self.tab = QTabWidget()
		self.dicoTab = {}
		
		#=== Là où s'afficheront les images ===#
		widget = QWidget()
		vboxMplayer = QVBoxLayout(widget)
		self.afficheurImg=VisionneurImagePourEKD()
		self.curseurImg = QSlider(Qt.Horizontal)
		self.curseurImg.setEnabled(False)
		# Drapeau servant à ne pas afficher 2 fois la même image
		self.verrouillerValueChange = 0
		self.connect(self.curseurImg,SIGNAL("sliderReleased()"), self.curseurImgRelache)
		self.connect(self.curseurImg,SIGNAL("sliderMoved(int)"), self.curseurImgBouge)
		self.connect(self.curseurImg,SIGNAL("sliderPressed()"), self.curseurPresse)
		self.connect(self.curseurImg,SIGNAL("valueChanged(int)"), self.curseurChange)
		
		vboxMplayer.addWidget(self.afficheurImg)
		vboxMplayer.addWidget(self.curseurImg)
		self.dicoTab['images']=self.tab.addTab(widget, _(u'Images sources'))
		
		#=== Widgets mplayer ===#
		widget = QWidget()
		vboxMplayer = QVBoxLayout(widget)
		vboxMplayer.addStretch()
		hbox = QHBoxLayout()
		vboxMplayer.addLayout(hbox)
		hbox.addStretch()
		self.mplayer = Mplayer(taille=(350,252))
		hbox.addWidget(self.mplayer)
		hbox.addStretch()
		vboxMplayer.addStretch()
		chemin = self.ligneEditionSource.text()
		self.mplayer.setEnabled(False)
		self.dicoTab['video']=self.tab.addTab(widget, _(u'Vidéo créée'))
		
		vbox.addWidget(self.tab)
		
		# -------------------------------------------------------------------
		# widgets du bas : ligne + boutons Aide et Appliquer
		# -------------------------------------------------------------------
		self.base.widgetBas(vbox)
		
		# affichage de la boîte principale
		self.setLayout(vbox)
	
	
	def curseurImgRelache(self):
		"""Changement de l'image affichée lors du déplacement du curseur associée"""
		self.verrouillerValueChange = 0
		i = self.curseurImg.value()
		self.afficheurImg.setImage(self.listeChemin[i])
	
	def curseurImgBouge(self, i):
		"""Montre le nom de l'image qui serait affichée si le curseur associée était relâché"""
		self.statusBar.showMessage(self.listeChemin[i])
	
	def curseurPresse(self):
		self.verrouillerValueChange = 1
	
	def curseurChange(self, i):
		"Permet un changement de l'image avec les flèches gauche et droite \
		et avec un simple clic sur une partie du curseur"
		if not self.verrouillerValueChange:
			self.afficheurImg.setImage(self.listeChemin[i])
			self.statusBar.showMessage(self.listeChemin[i])
	
	
	def spinChange(self, i):
		"""modifie le curseur lorsque le curseur bouge"""
		self.curseur.setValue(i)
		self.config.set(self.idSection,'nbr_img_sec',self.spin.value())
	
	
	def curseurBouge(self, i):
		"""Quand on change la position du curseur la valeur du spin est automatiquement modifiée"""
		self.spin.setValue(i)
	
	
	def comboMPEG1Change(self, i):
		idCombo = self.comboMPEG1.currentText()
		self.config.set(self.idSection,'nbr_img_sec_mpeg1video',idCombo)
	
	
	def stackedChange(self,i):
		"""Le widget de sélection de la valeur numérique associée à la boite de combo peut changer suivant le codec"""
		idCombo = str(self.combo.itemData(i).toStringList()[0])
		print "Combo :", idCombo
		if idCombo=='mpeg1video':
			self.stacked.setCurrentIndex(self.stackedCombo)
		else:
			self.stacked.setCurrentIndex(self.stackedspinCurseur)
		if idCombo=='ljpeg':
			self.statusBar.showMessage(_(u"La vidéo résultante ne pourra pas être lue avec tous les logiciels (ex. bon avec mplayer mais pas avec xine)"))
		else:
			self.statusBar.clearMessage()
		self.config.set(self.idSection,'codec', idCombo)
	
	
	def ouvrirSource(self, nomEntree=None):
		""" Récupération du chemin de la vidéo sélectionnée """
		if not nomEntree:
			txt = _(u"Fichiers vidéos")
			listeChemin=QFileDialog.getOpenFileNames(None, _(u"Ouvrir"), os.path.expanduser('~'), ("JPEG (*.jpg *.JPG *.jpeg *.JPEG);;PNG (*.png *.PNG);;GIF (*.gif *.GIF);;BMP (*.bmp *.BMP);;SGI (*.sgi *.SGI);;TIF (*.tif *.TIF);;TARGA (*.tga *.TGA);;PNM (*.pnm *.PNM);;PPM (*.ppm *.PPM);; *"))
			self.listeChemin = [str(listeChemin[i]) for i in range(len(listeChemin))]
		else: # module séquentiel
			self.listeChemin = nomEntree
		
		if self.listeChemin==[]: return
		
		print "Chemins sélectionnés", self.listeChemin
		
		# extension de la 1ère image (avec étoile devant)
		fich, ext=os.path.splitext(self.listeChemin[0])
		self.extAvecEtoile = "*"+ext
		
		# répertoire courant d'entrée
		self.repCourEntree = os.path.dirname(self.listeChemin[0])
		
		# remplissage de la ligne d'édition
		self.ligneEditionSource.setText(self.repCourEntree+"/"+self.extAvecEtoile)
		
		# Affichage du chemin + nom de fichier dans la zone
		# de texte du widget QLineEdit (de l'init) .
		#self.ligneEditionSource.setText(listeChemin)
		
		self.curseurImg.setRange(0,len(self.listeChemin)-1)
		self.curseurImg.setValue(0)
		self.afficheurImg.setImage(self.listeChemin[0])
		self.curseurImg.setEnabled(True)
		self.tab.setCurrentIndex(self.dicoTab['images'])
		
		# Quand un fichier est sélectionné, le bouton "Séparer" devient cliquable
		# et la vidéo peut être lue avec mplayer
		self.boutApp.setEnabled(True)
		
		#self.config.set('Animation Encodage','path',chemin)
	
	
	def afficherAide(self):
		#""" Boîte de dialogue d'aide """
		self.base.afficherAide(_(u"Blablablablablablablablablabla ... blablabla ... blablablabla ... blablabla."))
		'''
		messageAide=QMessageBox(self)
		messageAide.setText(_(u"Blablablabla ... blabla anim_conv_img_en_video."))
		messageAide.setWindowTitle(_(u"Aide"))
		messageAide.setIcon(QMessageBox.Information)
		messageAide.exec_()
		'''
	
	def redimImg(self, imgTaille):
		"""Copie dans /tmp/ekd/tampon/conv_img_en_video et
		# remplissage de la liste temporaire avec les 
		# fichiers chargés par l'utilisateur"""
		
		reply = QMessageBox.warning(self, 'Message',
		_(u"Vos images ne sont pas toutes de la même taille. Ceci dit la vidéo peut quand même être crée avec une taille d'image correspondante à la taille de la 1ère image détectée (par ordre alpha-numérique). Les opérations supplémentaires allongeront le processus de conversion. Voulez-vous quand-même continuer?"), QMessageBox.Yes, QMessageBox.No)
		if reply == QMessageBox.No:
			return
		
		listeTemp=[]
		for parcChemTempo in self.listeChemin:
			cop=shutil.copy("".join(parcChemTempo), '/tmp/ekd/tampon/conv_img_en_video')
			listeTemp.append(os.path.basename(parcChemTempo))
			# Mise en ordre
			listeTemp.sort()
		
		# Redimensionnement des images tampon (si l'utilisateur charge
		# des images avec des tailles complètement différentes
		for tmp in range(len(listeTemp)):
			chemin = '/tmp/ekd/tampon/conv_img_en_video/'+listeTemp[tmp]
			img=Image.open(chemin)
			# si la taille de l'image est identique à la taille de référence
			# alors on se contente de renommer l'image
			if img.size == imgTaille.size:
				os.rename(chemin, '/tmp/ekd/tampon/conv_img_en_video/'+'tmp47jt2t37eey'+string.zfill((tmp+1), 6)+'.jpg')
			# si la taille de l'image est différente de la taille de référence
			# alors on la redimensionne vant de la sauver
			else:
				redim=img.resize(imgTaille.size)
				redim.save('/tmp/ekd/tampon/conv_img_en_video/'+'tmp47jt2t37eey'+string.zfill((tmp+1), 6)+'.jpg', "JPEG", quality=100)
		
		# Elimination des fichiers temporaires qui n'ont pas été 
		# redimensionnés et qui ne servent donc plus à rien
		for elim in glob.glob('/tmp/ekd/tampon/conv_img_en_video/*.*'):
			if os.path.basename(elim)[0:14]!='tmp47jt2t37eey':
				os.remove(elim)
		
		# Redéfinition du chemin d'entrée des fichiers
		self.repCourEntree='/tmp/ekd/tampon/conv_img_en_video'
	
	
	def appliquer(self, nomSortie=None, ouvert=1):
		""" appelle la boite de dialogue de sélection de fichier à sauver et appel de la fonction de séparation audio-vidéo """
		
		# Recup de la taille de la 1ère chargée
		imgTaille=Image.open(self.listeChemin[0])
		
		# Si toutes les images sont de la même taille, alors on applique la procédure normale
		# sinon on passe par la création d'un répertoire tampon et on entre dans la structure
		# conditionnelle « if not taillesImgCorrectes »
		taillesImgCorrectes = 1 # par défaut les images sont considérant comme étant à la bonne taille
		nbrImg = len(self.listeChemin)
		
		for parcChemTempo in self.listeChemin:
			if Image.open(parcChemTempo).size==imgTaille.size:
				pass
			else:
				taillesImgCorrectes = 0
				break
		
		print "taillesImgCorrectes", taillesImgCorrectes
		
		# Si les tailles des images sont différentes
		if not taillesImgCorrectes:
			# création du réperoire tampon
			self.redimImg(imgTaille)
		
		#=== Détermination des chemins d'entrée et sortie ===#
		
		cheminVideoSorti=""
		
		if not nomSortie:
			# récupération du chemin de la vidéo de destination (à l'exception de l'extension)
			cheminVideoSorti=str(QFileDialog.getSaveFileName(None, _(u"Sauver"), os.path.expanduser(self.base.repSortieProv()), _(u"Tous les fichiers *.*")))
		else: # module séquentiel
			cheminVideoSorti=nomSortie
		
		if cheminVideoSorti=="": return
		
		print "Chemin sorti", cheminVideoSorti
		
		imgObj = Image.open(self.listeChemin[0])
		
		#print "Spin :", self.spin.value() , "; Radio_mpeg :", self.radio_mpeg1video.isChecked(), "; Radio_jpeg :", self.radio_motionjpeg.isChecked()
		
		i=self.combo.currentIndex()
		idCombo = str(self.combo.itemData(i).toStringList()[0])
		print "Combo :", idCombo
		
		# On récupère la valeur numérique associée au codec de 2 façon différentes
		if idCombo=='mpeg1video':
			valeurNum = str(self.comboMPEG1.currentText())
		else:
			valeurNum = str(self.spin.value())
		
		# extension du fichier vidéo
		if idCombo == 'mpeg1video':
			ext = '.mpg'
		else:
			ext = '.avi'
		
		cheminVideoSorti = cheminVideoSorti+ext
		
		print "COMMANDE D'ENCODAGE :\n", 'mencoder mf://'+"\""+self.repCourEntree+'/'+self.extAvecEtoile+"\""+' -mf fps='+str(valeurNum)+':w='+str(imgObj.size[0])+':h='+str(imgObj.size[1])+' -ovc lavc -lavcopts vcodec='+idCombo+' -o '+"\""+cheminVideoSorti+"\""
		
		# Passage par le répertoire temporaire car si cela n'est pas fait toutes les images
		# contenues dans le répertoire courant (et non les images sélectionnées par l'utilisateur)
		# sont sélectionnées pour la conversion ... ce qui est bien embêtant !.
		listeTemp=[]
		for parcChemTempo in self.listeChemin:
			cop=shutil.copy("".join(parcChemTempo), '/tmp/ekd/tampon/conv_img_en_video')
			listeTemp.append(os.path.basename(parcChemTempo))
			# Mise en ordre
			listeTemp.sort()
		
		# Redéfinition du chemin d'entrée des fichiers
		self.repCourEntree='/tmp/ekd/tampon/conv_img_en_video'
		
		cheminVideoEntre = self.repCourEntree+'/'+self.extAvecEtoile
		
		tailleIm = [str(imgObj.size[0]), str(imgObj.size[1])]
		
		# Drapeau de bon déroulement des opérations
		drapReussi = 1
		
		try:
			mencoder = WidgetMEncoder(idCombo, cheminVideoEntre, cheminVideoSorti, valeurNum=valeurNum, laisserOuvert=ouvert, tailleIm=tailleIm)
			mencoder.setWindowTitle(_(u"Conversion des images en vidéo"))
			mencoder.exec_()
		except:
			drapReussi = 0
			messageErrAnEnc=QMessageBox(self)
			messageErrAnEnc.setText(_(u"Un problème est survenu lors de l'exécution de \"mencoder mf://...\""))
			messageErrAnEnc.setWindowTitle(_(u"Error"))
			messageErrAnEnc.setIcon(QMessageBox.Warning)
			messageErrAnEnc.exec_()
		
		# Epuration/elimination des fichiers (redimensionnés) tampon
		for toutRepCompo in glob.glob('/tmp/ekd/tampon/conv_img_en_video/*.*'):
			os.remove(toutRepCompo)
		
		# Si tout a bien marché, on active mplayer avec le chemin de sortie de la vidéo
		if drapReussi:
			self.mplayer.listeVideos = [cheminVideoSorti]
			self.mplayer.setEnabled(True)
			self.tab.setCurrentIndex(self.dicoTab['video'])
		
		return cheminVideoSorti
	
	
	def sequentiel(self, entree, sortie, ouvert=0):
		"""Utile dans le module du même nom. Applique les opérations de la classe. Retourne le vrai nom du fichier de sortie"""
		self.ouvrirSource(entree)
		return self.appliquer(sortie, ouvert)
	
	
	def sequentielReglage(self):
		"""Utile dans le module du même nom. Récupère le widget de réglage associé à l'identifiant donné en 1er argument. Retourne l'instance du widget de réglage"""
		self.groupReglage.setTitle(_(u"Réglages: convertir des images en animation"))
		return self.groupReglage