
import Tkinter, os, sys, statvfs, tkMessageBox, pymp3cut

from mpcardmanconf import *


def ascSize(numBytes):
	if numBytes<1000:
		return "%d"%numBytes
	elif numBytes<1e6:
		return "%3.2fk"%(numBytes/1024.)
	else:
		return "%3.2fM"%(numBytes/1024./1024.)


class DirBrowser(Tkinter.Frame):

	def __init__(self, parent, dir, sizeChangedCallback):
		Tkinter.Frame.__init__(self, parent)
		self.directory = dir
		self.sizeChangedCallback = sizeChangedCallback
		self._buildScroller()
		self.selection = ()
		self._poll()

	
	def _readDir(self):
		predir = os.listdir(self.directory)
		predir.sort()
		self.dirEntries = [(a[0], a[1], os.path.getsize(a[1])) for a in
			[(a,os.path.join(self.directory, a)) for a in predir]
			if os.path.isfile(a[1]) and not os.path.islink(a[1])]
	

	def updateFilelist(self):
		self._readDir()
		self.scrollist.delete(0, Tkinter.END)
		for a in self.dirEntries:
			self.scrollist.insert(Tkinter.END, "%s (%s)"%(a[0],ascSize(a[2])))


	def _buildScroller(self):
		scrollbar = Tkinter.Scrollbar(self, orient=Tkinter.VERTICAL)
		self.scrollist = Tkinter.Listbox(self, width=80, height=30,
			selectmode=Tkinter.MULTIPLE, yscrollcommand=scrollbar.set,
			exportselection=0, font=("Helvetica",12))
		self.scrollist.bind('<Button-4>', lambda a, self=self: 
			self.scrollist.yview("scroll", -2, "units"))
		self.scrollist.bind('<Button-5>', lambda a, self=self: 
			self.scrollist.yview("scroll", 2, "units"))
		scrollbar.config(command=self.scrollist.yview)
		scrollbar.pack(side=Tkinter.RIGHT,fill=Tkinter.Y)
		self.scrollist.pack(side=Tkinter.LEFT,fill=Tkinter.BOTH,expand=1)
		self.updateFilelist()


	def _poll(self):
		newSel = self.scrollist.curselection()
		if newSel!=self.selection:
			self.selection = newSel
			self.sizeChangedCallback(self.computeSize())
		self.after(100, self._poll)
	

	def computeSize(self):
		selSize = 0
		for a in self.selection:
			selSize += self.dirEntries[int(a)][2]
		return selSize

	
	def getFileList(self):
		return [self.dirEntries[int(a)][1] for a in self.selection]
	

	def _clearSelection(self):
		self.scrollist.select_clear(0, Tkinter.END)
	

class CardMan(Tkinter.Tk):

	def __init__(self, dir):
		Tkinter.Tk.__init__(self)
		self.cardMounted = None
		self.amBusy = None

		self._setupEvents()
		self.title("MP3 Multimedia card manager")

		self._makeButtons()
		self.dirBrowser = DirBrowser(self, dir, self.selSizeChanged)
		self.dirBrowser.pack(side=Tkinter.LEFT, expand=1, fill=Tkinter.BOTH)
	

	def _setupEvents(self):
		self.protocol("WM_DELETE_WINDOW", self.quit())


	def _makeButtons(self):
		buttonFrame = Tkinter.Frame(self)
		quitButton = Tkinter.Button(buttonFrame, text="Quit", command=self.quit)
		quitButton.pack(side=Tkinter.TOP, expand=1, fill=Tkinter.X)
		self.mountButton = Tkinter.Button(buttonFrame, text="Mount", 
			command=self.mountOrUnmount)
		self.mountButton.pack(side=Tkinter.TOP, expand=1, fill=Tkinter.X)
		self.transferButton = Tkinter.Button(buttonFrame, text="Transfer",
			state=Tkinter.DISABLED, command=self.transfer)
		self.transferButton.pack(side=Tkinter.TOP, expand=1, fill=Tkinter.X)
		self.clearButton = Tkinter.Button(buttonFrame, text="Clear Card",
			state=Tkinter.DISABLED, command=self.clearCard)
		self.clearButton.pack(side=Tkinter.TOP, expand=1, fill=Tkinter.X)
		self.freeLabel = Tkinter.Label(buttonFrame, text="       ")
		self.freeLabel.pack(side=Tkinter.TOP, expand=1, fill=Tkinter.X)
		self.selLabel = Tkinter.Label(buttonFrame, text="      0")
		self.selLabel.pack(side=Tkinter.TOP, expand=1, fill=Tkinter.X)
		self.moveTransferredVar = Tkinter.IntVar()
		transButton = Tkinter.Checkbutton(buttonFrame, 
			text="Move Transferred", variable=self.moveTransferredVar)
		transButton.select()
		transButton.pack(side=Tkinter.TOP, expand=1, fill=Tkinter.X)
		self.chunkVar = Tkinter.IntVar()
		chunkButton = Tkinter.Checkbutton(buttonFrame, 
			text="Chunk mp3s", variable=self.chunkVar)
		chunkButton.select()
		chunkButton.pack(side=Tkinter.TOP, expand=1, fill=Tkinter.X)

		buttonFrame.pack(side=Tkinter.LEFT, expand=0)

	def selSizeChanged(self, newSize):
		self.selLabel.config(text="%10s"%ascSize(newSize))

	def freeSpaceOnCard(self, ejected=None):
		v = os.statvfs(cardPath)
		return v[statvfs.F_BAVAIL]*v[statvfs.F_FRSIZE]

	def updateFreeSpaceOnCard(self):
		self.freeLabel.config(text=ascSize(self.freeSpaceOnCard()))

	def getMoveTransferred(self):
		return self.moveTransferredVar.get()

	def getDoChunk(self):
		return self.chunkVar.get()

	def busy(self):
		self.config(cursor="watch")
		self.amBusy = 1
		self.update()

	def unbusy(self):
		self.config(cursor="left_ptr")
		self.amBusy = 0
		self.update()

	def _mountCard(self):
		self.busy()
		self.owd = os.getcwd()
		try:
			os.chdir(cardPath)
		except os.error:
			tkMessageBox.showerror(title="mpcardman", message="Can't chdir to"+
				" %s. Do you have a card inserted?."%cardPath)
			self.unbusy()
			return
		self.cardMounted = 1
		self.clearButton.config(state=Tkinter.NORMAL)
		self.transferButton.config(state=Tkinter.NORMAL)
		self.updateFreeSpaceOnCard()
		self.mountButton.config(text="Unmount")
		self.unbusy()

	def _stillMounted(self):
		mountlines = os.popen("mount", 'r').readlines()
		for a in mountlines:
			if a.find(cardPath)!=-1:
				return 1

	def _unmountCard(self):
		self.busy()
		os.chdir(self.owd)
		os.system("sync; sudo aum; sleep 1")
		if self._stillMounted():
			self.bell()
			tkMessageBox.showerror(title="mpcardman", message="Unmount failed."+
				" Probably somebody else is on %s."%cardPath)
			self.unbusy()
			return
		self.cardMounted = None
		self.freeLabel.config(text="         ")
		self.clearButton.config(state=Tkinter.DISABLED)
		self.transferButton.config(state=Tkinter.DISABLED)
		self.mountButton.config(text="Mount")
		self.unbusy()

	def mountOrUnmount(self):
		if self.cardMounted:
			self._unmountCard()
		else:
			self._mountCard()

	def clearCard(self):
		if self.cardMounted:
			self.busy()
			os.system("rm -f %s"%(os.path.join(cardPath, "*")))
			self.unbusy()
		self.updateFreeSpaceOnCard()

	def _chunk(self, fName, nameTag):
		mpFile = pymp3cut.MP3File(fName)
		runningTime = os.path.getsize(fName)*8/mpFile.bitrate
		numPieces = runningTime/300
		if numPieces==0:
			pieceLength = runningTime
		else:
			pieceLength = runningTime/numPieces
		mpFile.calculate_parts("%s,%d,%d"%(nameTag, pieceLength,
			runningTime))
		return mpFile.cut_parts()

	def transfer(self):
		if not self.cardMounted:
			return
		if self.freeSpaceOnCard()<self.dirBrowser.computeSize():
			print "Not enough free space"
			return
		self.busy()
		try:
			nameTag = 'a'
			for a in self.dirBrowser.getFileList():
				if self.getDoChunk():
#				numPieces = max(2,os.path.getsize(a)/1100000)
#				if os.system("mpgsplit -%d '%s' -b %s"%(numPieces, a, nameTag)):
					if self._chunk(a, nameTag):
						tkMessageBox.showerror(title="mpcardman", message="mpg split"+
						" failed.  Giving up.")
						break
				else:
					os.system("cp '%s' ."%a)
				if self.getMoveTransferred():
					os.system("mv %s %s"%(a, archiveDir))
				nameTag = chr(ord(nameTag)+1)
		finally:
			os.system("sync")
			self.updateFreeSpaceOnCard()
			self.unbusy()
			self.dirBrowser.updateFilelist()
			self.bell()

	def quit(self):
		if self.amBusy:
			return
		if self.cardMounted:
			self._unmountCard()
		Tkinter.Tk.quit(self)


if __name__=="__main__":
	if len(sys.argv)==2:
		m = CardMan(os.path.abspath(sys.argv[1]))
	else:
		m = CardMan(sourcePath)
	m.mainloop()

