#! /usr/bin/python
#
#
#	This file is part of DvdRip Queue
#	
#	DvdRip Queue 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 3 of the License, or
#	(at your option) any later version.
#	
#	DvdRip Queue 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 DvdRip Queue.  If not, see <http://www.gnu.org/licenses/>.
#	

import sys, os, webbrowser
from shutil import move
from glob import glob

from dvdripQueue.guiFunctions import changeStockButtonText
from dvdripQueue.dvdrip_lib import getPref
from dvdripQueue.doEncode import doEncode
from dvdripQueue.prefsWindow import prefsWindow

try:
	import pygtk
except:
	pass
try:
	import gtk, gobject
	import gtk.glade
except:
	print "unable to find gtk. Exiting..."
	sys.exit(1)

# Allows us to keep the GUI responsive while dvdrip is encoding (a long
# process, which, without threading, would cause the app to hang
gtk.gdk.threads_init()

# Our main application...
class DvdRipQueue:
	"""
	Main application
	"""
	def __init__(self):
		
		# Set Glade File
		self.gladefile = "/usr/share/dvdrip-queue/dvdrip-queue.glade"
		self.wTree = gtk.glade.XML(self.gladefile) 
 
 		# Get the Main window and connect the "destroy" event
 		self.window = self.wTree.get_widget("main")
		
		dic = { "on_menuItemQuit" : gtk.main_quit,
				"on_mainWindowDestroy" : gtk.main_quit,
				"on_addProject_clicked" : self.addProject,
				"on_infoButton_clicked" : self.showInfoWindow,
				"on_configButton_clicked" : self.configureSelectedProject,
				"on_deleteSelectedButton_clicked" : self.deleteSelectedProject,
				"deleteAllButton_clicked" : self.deleteAllProjects,
				"on_prefs_activate" : self.showPreferences,
				"on_aboutDvdRipQueue_activate" : self.aboutDvdRipQueue,
				"on_startEncodingButton_clicked" : self.startEncoding,
				"on_versionError_response" : self.onVersionErrorButtonClick,
				"on_aboutDvdRipQueue_activate" : self.aboutDvdRipQueue,
				"on_submitBugs_activate" : self.submitBugs,
				"on_projectList_row_activated" : self.projectRowDoubleClick
				}
		
		self.wTree.signal_autoconnect(dic)
		
		self.wTree.get_widget("main").show()
		
		# Change necessary object attributes
		addProjectButton = self.wTree.get_widget("addProjectButton")
		startEncodingButton = self.wTree.get_widget("startEncodingButton")
		infoButton = self.wTree.get_widget("infoButton")

		addProjectButton = changeStockButtonText(addProjectButton, "Add to Queue", "gtk-add")
		startEncodingButton = changeStockButtonText(startEncodingButton, "Start Encoding", "gtk-yes")
		infoButton = changeStockButtonText(infoButton, "", "gtk-info")
		
		# A variable to keep track of how many items in each treeview
		self.lViewItersCount = 0
		self.rViewItersCount = 0
		
		# A variable to toggle between currently encoding or not
		self.nowEncoding = False
		#self.cancelEncode = False
		
		# Declare some other widgets for later use
		self.addProjectButton = self.wTree.get_widget("addProjectButton")
		self.configButton = self.wTree.get_widget("configButton")
		self.deleteSelectedButton = self.wTree.get_widget("deleteSelectedButton")
		self.deleteAllButton = self.wTree.get_widget("deleteAllButton")
		self.infoButton = self.wTree.get_widget("infoButton")
		self.startEncodingButton = self.wTree.get_widget("startEncodingButton")
		self.progressBar = self.wTree.get_widget("progressBar")
		
		# Set up the TreeView widgets and load the rip files into them
		self.setupTreeViews()
		
		print("loading *.rip files... "),
		self.loadRipFiles()
		print("done")
		
		# Select the top item of each treeview
		self.selectTopItem(self.lView)
		
	def projectRowDoubleClick(self, widget, path, view_column):
		self.addProject(widget)
		
	def on_aboutDialog_response(self, widget, foobar):
		"""
		Hide/destroy the about Dialog
		"""
		self.aboutDialog.hide()
		self.aboutDialog.destroy()
		
	def aboutDvdRipQueue(self, widget):
		"""
		Refreshes self.wTree via gtk.glade.XML(gladeFile) and shows the about dialog
		"""
		
		# Refreshes wTree because if you can call this dialog, close 
		#it (destroy it) and then try to open it again you get an error
		# like, Nonetype has no attribute 'show()'
		aboutwTree = gtk.glade.XML("/usr/share/dvdrip-queue/dvdrip-queue-about.glade")
		
		# Get the about dialog window from the widget tree and display it
		self.aboutDialog = aboutwTree.get_widget("aboutDialog")
		self.aboutDialog.show()
		
		aboutDic = {"on_aboutDialog_response" : self.on_aboutDialog_response }
		aboutwTree.signal_autoconnect(aboutDic)
		
	def submitBugs(self, widget):
		webbrowser.open("http://sourceforge.net/tracker/?func=add&group_id=231138")
		
	def selectTopItem(self, TreeView):
		"""
		Selects the top item of a TreeView
		"""
		TreeView.get_selection().select_path(0)
		
	def startEncoding(self, widget):
		if self.nowEncoding == False:
			self.encodeBegin(widget)
			
		elif self.nowEncoding == True:
			self.encodeCancel(widget)
		
	def encodeBegin(self, widget):
		self.nowEncoding = True
		
		self.addProjectButton.set_sensitive(False)
		self.configButton.set_sensitive(False)
		self.deleteSelectedButton.set_sensitive(False)
		self.deleteAllButton.set_sensitive(False)
		self.lView.set_sensitive(False)
		self.rView.set_sensitive(False)

		widget = changeStockButtonText(widget, "Cancel", "gtk-cancel")
		
		iterList = []
		iterList.append(self.queueList.get_iter_root())
		
		while self.queueList.iter_next(iterList[-1]) != None:
			tmpIter = self.queueList.iter_next(iterList[-1])
			iterList.append(tmpIter)
			
		ripFilesToQueue = []
		for iter in iterList:
			ripFileName = self.queueList.get_value(iter, 1)
			ripFilesToQueue.append(ripFileName)
		
		ripQueue = []
		for file in ripFilesToQueue:
			self.ripExitOnFinish(file)
			commands = self.makeDvdRipCommand(file, self.getRippedTitles(file))
			ripQueue = ripQueue + commands
		
		
		self.encoder = doEncode(ripQueue, app)
		self.encoder.start()		

	def onVersionErrorButtonClick(self, widget, Null):
		gtk.main_quit()
		sys.exit(1)
		
	def makeDvdRipCommand(self, ripFile, titles):
		datadirectory = getPref("datadirectory")
		ripFilePath = datadirectory + "/" + ripFile
		commands= []
		
		for title in titles:
			commands.append(["dvdrip -f transcode -t " + str(title) + " " + ripFilePath, ripFile, title])
		
		return commands
		
	def encodeCancel(self, widget):
		self.nowEncoding = False
		self.encoder.cancel()
		
		self.addProjectButton.set_sensitive(True)
 		self.configButton.set_sensitive(True)
		self.deleteSelectedButton.set_sensitive(True)
		self.deleteAllButton.set_sensitive(True)
 		self.lView.set_sensitive(True)
 		self.rView.set_sensitive(True)
 		
 		widget = changeStockButtonText(widget, "Start Encoding", "gtk-yes")
		
	def addProject(self, widget):
		"""
		Adds the selected projects in the projectList widget (left
		TreeView) to the queueList widget (right TreeView)
		"""
		
		# make a list to store the iters
		self.selectedIters = []
				
		# Get selection from projectList
		self.lView.get_selection().selected_foreach(self.forEachSelected)
		
		# Cycles through all the selected items and adds them to the
		# queueList ListStore (the TreeView widget on the right)
		for s in self.selectedIters:
			selectedValue = self.projectList.get_value(s, 0)
			
			# get the chapters ripped in current project filename
			chapters = self.getRippedTitles(selectedValue)
			
			# Add the selection to queueList
			tmpIter = self.queueList.append([len(chapters), selectedValue])
			
			# Add 1 to our running count of Iters
			self.rViewItersCount = self.rViewItersCount + 1
		
			# Remove the item from projectList
			self.projectList.remove(s)
		
		# If the selection contains something (isn't empty) enable the
		# Buttons (make them 'sensitive' to input/clicks)
		if self.selectedIters != []:
			self.setButtonsToSensitive(True)
		
		# Select the top item of both Treeview widgets	
		self.selectTopItem(self.rView)
		self.selectTopItem(self.lView)
		
	def getRippedTitles(self, filename):
		datadirectory = getPref("datadirectory")
		
		# A List to hold the chapters ripped
		titlesRipped = []
		
		# A List to hold the last 4 lines
		oldLines = [""] * 4
		
		# The following text is only added to a *.rip file if the title
		# was copied (ripped) to the hard drive
		tofind = "'actual_chapter' =>"
		
		for line in open(datadirectory + "/" + filename, "r").readlines():
			# if the identifier is found...
			
			if (line.find(tofind) != -1):
				# ...then look through the last 4 lines for the one 
				# with the title number.
				for oldline in oldLines:
					if (oldline.find("' => bless( ") != -1):
						# When you find it get the title number...
						
				
						# Strip the whitespace
						oldline = oldline.strip()
						
						# A Variable to save the title number in
						titleNumber = ""
						
						# if the first character is a ' then start reading
						if (oldline[0] == "'"):
							for char in oldline[1:]:

								# If it's not a ' add it to titleNumber
								if (char != "'"):
									titleNumber = titleNumber + char
								# If it IS a ' we're done
								elif (char == "'"):
									break
						
						# Convert titleNumber from a string to an
						# integer and add it to our list of titles
						titlesRipped.append(int(titleNumber))
						
			# delete the oldest line in the list (the one at the beginning)
			oldLines.pop(0)
			
			# Add this line to the end of the list
			oldLines.append(line)
		
		# Return the list of titles ripped in this project	
		return titlesRipped
			
				
		
	def setButtonsToSensitive(self, buttonsAreSensitive):
		"""
		If input is 'True' set all following buttons to be sensitive
		to input/clicking.
		
		If input is 'False' disable them (make then non-sensitive)
		"""
		
		#self.configButton.set_sensitive(buttonsAreSensitive)
		self.deleteSelectedButton.set_sensitive(buttonsAreSensitive)
		self.deleteAllButton.set_sensitive(buttonsAreSensitive)
		#self.infoButton.set_sensitive(buttonsAreSensitive)
		self.startEncodingButton.set_sensitive(buttonsAreSensitive)
			
	def forEachSelected(self, model, path, iter):
		"""
		For use with gtk.TreeView.get_selection().selected_foreach()
		
		Adds the iter (gtk.TreeIter) of each selected item to a 
		list, self.selectedIters
		"""
		self.selectedIters.append(iter)
			
	def showInfoWindow(self, widget):
 		# comment
		print("X")
		
	def configureSelectedProject(self, widget):
 		# comment
		print("X")
		
	def deleteSelectedProject(self, widget):
		"""
		Deletes the Selected Project from queueList (right TreeView)
		"""
 		Null, tmpIter = self.rView.get_selection().get_selected()
 		
 		if (tmpIter != None):
 			# Get the *.rip Filename and add it back to the projectList
 			tmpName = self.queueList.get_value(tmpIter, 1)
 			self.projectList.append([tmpName])
 			self.queueList.remove(tmpIter)
 			self.rViewItersCount = self.rViewItersCount - 1
 			self.selectTopItem(self.rView)
 		
 		if (self.rViewItersCount == 0):
 			self.setButtonsToSensitive(False)
		
	def deleteAllProjects(self, widget):
		"""
		Deletes all the projects from queueList (rightTreeView)		
		"""
 		self.queueList.clear()
 		self.setButtonsToSensitive(False)
		self.rViewItersCount = 0
		self.loadRipFiles()
		self.selectTopItem(self.lView)
		
	def showPreferences(self, widget):
		self.prefsWindow = prefsWindow(app)
		
 		
 	def loadRipFiles(self):
 		"""
 		Loads all the *.rip files found in the specified data directory 
 		into projectList (Left Treeview widget)
 		"""
		datadirectory = getPref("datadirectory")

		# create an list of the *.rip files in the data directory
		ripFiles = glob(datadirectory + "/*.rip")
		
		self.projectList.clear()
		self.queueList.clear()
		
		for i in range(len(ripFiles)):
			filename = ripFiles[i-1].replace(datadirectory+"/","")
			
			# Removes the .rip
			#buffer = buffer[:buffer.rindex('.rip')]
			
			self.projectList.append([filename])
			
	
	def setupTreeViews(self):
		############## Part 1 - Left Listview #########################
		
		# Make a liststore with one column for string data - left TreeView
		self.projectList = gtk.ListStore(str)
		
		# Get the TreeView widget
		self.lView = self.wTree.get_widget('projectList')
		
		# Link the projectList widget to our liststore object		
		self.lView.set_model(self.projectList)
		lColumns = []
		
		# Add a column to end of array named "*.rip Files", rendered as TEXT, 
		# getting it's 'text' attribute from column 0
		lColumns.append(gtk.TreeViewColumn("*.rip Files", gtk.CellRendererText(), text=0))
		#columns.append(gtk.TreeViewColumn("Oops", gtk.CellRendererProgress(), value=1))
		
		
		
		# Autosize the columns and add them to the treelist
		for c in lColumns:
			c.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
			self.lView.append_column(c)
		
		# Make Treeview searchable
		self.lView.set_search_column(0)
			
		# Allow sorting of the first column
		lColumns[0].set_sort_column_id(0)
		
		self.projectList.set_sort_column_id(0, gtk.SORT_ASCENDING)
		
		
					
		self.lView.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
			
	
		############## Part 2 - Right Listview ########################
		
		# Make a liststore with 2 columns for string data (*.rip file, 
		# and number of titles to encode) - Right TreeView
		self.queueList = gtk.ListStore(str, str)
		
		# Get the TreeView widget
		self.rView = self.wTree.get_widget('queueList')
		
		# Link the queueList widget to our liststore object		
		self.rView.set_model(self.queueList)
		rColumns = []
		
		# Add 2 columns to end of array
		rColumns.append(gtk.TreeViewColumn("Titles", gtk.CellRendererText(), text=0))
		rColumns.append(gtk.TreeViewColumn("*.rip Files", gtk.CellRendererText(), text=1))
		
		# Autosize the filename column, and set the '# of titles' column
		# to a fixed width. Then add them to the treelist
		
		for c in rColumns:
			c.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
			self.rView.append_column(c)
		
		rColumns[0].set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
		rColumns[0].set_fixed_width(40)
		
		self.rView.set_reorderable(True)
		
		
	def ripExitOnFinish(self, ripProjectFilename):
		# get the current location of the datadirectory
		datadirectory = getPref("datadirectory")
		
		# Make a tempFile to hold the file's contents
		tmp = open(datadirectory + "/.dvdrip-queue_tmp", "w")
		tmp.write("")
		tmp.close()
		tmp = open(datadirectory + "/.dvdrip-queue_tmp", "a")
		
		exitFound=0
		
		# Open the rip file (text file)
		for line in open(datadirectory + "/" + ripProjectFilename, "r").readlines():
			if (line.find("'tc_exit_afterwards' => 1,") != -1):
				exitFound=5
			if ((line.find("'tc_fast_resize' =>") != -1) and (exitFound < 0)):
				tmp.write("        'tc_exit_afterwards' => 1,\n")
			tmp.write(line)
			exitFound=exitFound -1
		
		#replace old *.rip file with new file that exits on finish
		move(datadirectory + "/.dvdrip-queue_tmp", datadirectory + "/" + ripProjectFilename)

if __name__ == "__main__":
	app = DvdRipQueue()
	gtk.main()
