#!/usr/bin/env python
# -*- coding: UTF-8 -*-

# Copyright 2006 (C) Peter Gill - GetPrograms

# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

# All code except Popen and related functions are covered by the above GPL license
# Popen and its two related functions, send_all and recv_some, are taken from
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554 cookbook recipe
# and they are covered by the python PSF license which can be found at:
# http://www.python.org/download/releases/2.5/license/

import urllib
import zipfile
import bz2
import tarfile
import re
import os
import shutil
import string
import subprocess
import errno
import time
import sys
import pygtk
pygtk.require('2.0')
import gtk
from devede_other import *

if subprocess.mswindows:
	from win32file import ReadFile, WriteFile
	from win32pipe import PeekNamedPipe
	import msvcrt

class Popen(subprocess.Popen):
	def recv(self, maxsize=None):
		return self._recv('stdout', maxsize)

	def recv_err(self, maxsize=None):
		return self._recv('stderr', maxsize)

	def send_recv(self, input='', maxsize=None):
		return self.send(input), self.recv(maxsize), self.recv_err(maxsize)

	def get_conn_maxsize(self, which, maxsize):
		if maxsize is None:
			maxsize = 1024
		elif maxsize < 1:
			maxsize = 1
		return getattr(self, which), maxsize

	def _close(self, which):
		getattr(self, which).close()
		setattr(self, which, None)

	if subprocess.mswindows:
		def send(self, input):
			if not self.stdin:
				return None

			try:
				x = msvcrt.get_osfhandle(self.stdin.fileno())
				(errCode, written) = WriteFile(x, input)
			except ValueError:
				return self._close('stdin')
			except (subprocess.pywintypes.error, Exception), why:
				if why[0] in (109, errno.ESHUTDOWN):
					return self._close('stdin')
				raise

			return written

		def _recv(self, which, maxsize):
			conn, maxsize = self.get_conn_maxsize(which, maxsize)
			if conn is None:
				return None

			try:
				x = msvcrt.get_osfhandle(conn.fileno())
				(read, nAvail, nMessage) = PeekNamedPipe(x, 0)
				if maxsize < nAvail:
					nAvail = maxsize
				if nAvail > 0:
					(errCode, read) = ReadFile(x, nAvail, None)
			except ValueError:
				return self._close(which)
			except (subprocess.pywintypes.error, Exception), why:
				if why[0] in (109, errno.ESHUTDOWN):
					return self._close(which)
				raise

			if self.universal_newlines:
				read = self._translate_newlines(read)
			return read


class GetPrograms:
	"""
	Class to download programs needed for devede to run on windows.
	grep, mplayer, mencoder, ln, vcdimager, dvdauthor, mkisofs.
	grep, dvdauthor, mkisofs, and vcdimager should be provided in the
	windows package.
	"""

	def __init__(self):
		self.dialog = gtk.Dialog(title="Select Programs to Install", parent=None, flags=gtk.DIALOG_MODAL, buttons=None)
		self.progressBar = gtk.ProgressBar()
		self.progressBar.set_orientation(gtk.PROGRESS_LEFT_TO_RIGHT)
		# if key is True, download
		# programs to check for, if not found must be installed
		self.programs={"mplayer":False, "grep":False, "vcdimager":False, "dvdauthor":False, "mkisofs":False, "ln":False}
		# everything that must downloaded and installed
		self.checked={"mplayer":False, "grep":False, "vcdimager":False, "dvdauthor":False, "mkisofs":False, "ln":False,"cygwin":False}


	def startProcessing(self):
		for k,v in self.checked.iteritems():
			if v==True:
				print "downloading: ", k
				self.download(package=k.strip())
				self.unzip(package=k.strip())

	def msgbox(self,msg,title):
		message = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, msg)
		message.set_title(title)
		message.run()
		message.destroy()

	def checkbox_toggled(self,widget, msg=None):
		print "In test func: ", msg
		print "%s was toggled %s" % (msg, ("OFF", "ON")[widget.get_active()])
		if ("OFF", "ON")[widget.get_active()] == "ON":
			self.checked[msg]=True
			self.checked["cygwin"]=True
		else:
			self.checked[msg]=False
		return

	def makeButtonBox(self,name=None, label=None):
		p1 = gtk.HBox(True, 1)
		button=gtk.CheckButton(label=name)
		button.connect("toggled", self.checkbox_toggled, name.lower())
		p1.pack_start(button,True,True,1)
		button.show()
		lblOutput=gtk.Label(label)
		p1.pack_start(lblOutput,True,True,1)
		p1.show()
		lblOutput.show()
		return p1

	def displayCheckmarkGui(self):
		self.dialog.add_button(gtk.STOCK_QUIT,gtk.RESPONSE_CLOSE)
		self.dialog.add_button(gtk.STOCK_OK,gtk.RESPONSE_OK)

		if self.checkProgram("vcdimager") == False:
			self.programs["vcdimager"]=True
		if self.checkProgram("dvdauthor") == False:
			self.programs["dvdauthor"]=True
		if self.checkProgram("mkisofs") == False:
			self.programs["mkisofs"]=True
		if self.checkProgram("ln") == False:
			self.programs["ln"]=True

		lblMessage=gtk.Label("Programs that need to be downloaded for\n devede to work.")
		lblMessage.set_justify(gtk.JUSTIFY_CENTER)
		lblMessage.show()
		self.dialog.vbox.pack_start(lblMessage,True,True,10)

		if self.checkProgram("mplayer") == False:
			p1=self.makeButtonBox("Mplayer","Check to Install")
			self.dialog.vbox.pack_start(p1,True,True,1)

		if self.checkProgram("vcdimager") == False:
			p2=self.makeButtonBox("Vcdimager","Check to Install")
			self.dialog.vbox.pack_start(p2,True,True,1)

		if self.checkProgram("mkisofs") == False:
			p3=self.makeButtonBox("Mkisofs","Check to Install")
			self.dialog.vbox.pack_start(p3,True,True,1)

		if self.checkProgram("dvdauthor") == False or self.checkProgram("spumux")==False:
			p4=self.makeButtonBox("Dvdauthor","Check to Install")
			self.dialog.vbox.pack_start(p4,True,True,1)

		if self.checkProgram("grep") == False:
			p5=self.makeButtonBox("Grep","Check to Install")
			self.dialog.vbox.pack_start(p5,True,True,1)

		if self.checkProgram("ln") == False:
			p6=self.makeButtonBox("Ln","Check to Install")
			self.dialog.vbox.pack_start(p6,True,True,1)

		self.progressBar.show()
		self.dialog.vbox.pack_start(self.progressBar,True,True,1)


		resp=self.dialog.run()
		
		if resp == gtk.RESPONSE_CLOSE:
			print "Response Close"
		elif resp == gtk.RESPONSE_OK:
			print "Response OK"
			self.startProcessing()
		
		self.msgbox(msg="Please restart DeVeDe", title="WinDeVeDe Installer")


	def download(self, location=None,package=None):
		reg=re.compile("Content-Length:.*")
		reg2=re.compile("[0-9]*[0-9]")

		if package == "mplayer":
			location="http://www2.mplayerhq.hu/MPlayer/releases/win32/MPlayer-mingw32-1.0rc1.zip"
		elif package == "grep":
			location="http://peter.m.gill.googlepages.com/grep.zip"
		elif package == "ln":
			location="http://peter.m.gill.googlepages.com/ln.zip"
		elif package == "vcdimager":
			location="http://peter.m.gill.googlepages.com/vcdimager.zip"
		elif package == "dvdauthor":
			location="http://peter.m.gill.googlepages.com/dvdauthor.zip"
		elif package == "mkisofs":
			location="http://peter.m.gill.googlepages.com/mkisofs.zip"
		elif package == "cygwin":
			location="http://peter.m.gill.googlepages.com/cygwin1.zip"
		else:
			print "Unknown package"
			return
		
		print location
		
		url=urllib.urlopen(location)
		n=0
		temp=reg.search(str(url.info()))
		temp=temp.group()
		size=reg2.search(temp)
		size=size.group()
		
		print url.info()
		print "Size of file: ", int(size)/1000 , " kilobytes"
		output=open(package+".zip","wb")
		while True:
			s=url.read(8192)
			if not s:
				break
			output.write(s)
			n=n+len(s)
			downloaded=int(n)/1000
			size2=int(size)/1000
			print "Downloaded ", int(n)/1000 , " kilobytes of ", int(size)/1000, "."
			
			self.progressBar.set_fraction(float(downloaded)/float(size2))
			self.progressBar.set_text("Downloading "+ package + ". "+ str(int((downloaded/float(size2))*100)) + "% complete.")
			while gtk.events_pending():
				gtk.main_iteration()
			
		url.close()
		output.close()

		return

	def unzip(self,package):
		basedir=os.getcwd()
		bindir=os.path.join(basedir,"bin")
		tempdir=os.path.join(basedir,"temp")
		
		if not os.path.isdir(tempdir):
			os.mkdir(tempdir)

		shutil.move(package+".zip",tempdir)
		os.chdir(tempdir)
		
		file=zipfile.ZipFile(package+".zip")
		for name in file.namelist():
			data = file.read(name)
			try:
				output=open(name,"wb")
				output.write(data)
				output.close()
			except IOError:
				print "IOError" 
				if not os.path.isdir(name) and len(data)==0:
					os.mkdir(name)
			print name #, len(data), repr(data[:10])
		file.close()

		if not os.path.isdir(bindir):
			os.mkdir(bindir)

		if package=="mplayer":
			os.chdir("mplayer")
			for x in os.listdir(os.getcwd()):
				print "moving: ", x
				if os.path.isdir(x):
					if os.path.isdir(os.path.join(bindir,x)):
						shutil.rmtree(os.path.join(bindir,x))
					shutil.move(x,os.path.join(bindir+os.sep+x))
				else:
					shutil.move(x,bindir)
			os.chdir("../")
			os.rmdir(package)
		elif package=="grep":
			shutil.move("grep.exe",bindir)
			shutil.move("cygpcre-0.dll",bindir)
		elif package=="ln":
			shutil.move("ln.exe",bindir)
		elif package=="vcdimager":
			shutil.move("vcdimager.exe",bindir)
			shutil.move("cygpopt-0.dll",bindir)
		elif package=="mkisofs":
			shutil.move("mkisofs.exe",bindir)
		elif package=="dvdauthor":
			shutil.move("dvdauthor.exe",bindir)
			shutil.move("spumux.exe",bindir)
			shutil.move("dvdunauthor.exe",bindir)
			shutil.move("mpeg2desc.exe",bindir)
			shutil.move("spuunmux.exe",bindir)
			shutil.move("cyglcms-1.dll",bindir)
			shutil.move("cygMagick-10.dll",bindir)
			shutil.move("cygtiff-5.dll",bindir)
		elif package=="cygwin":
			shutil.move("cygwin1.dll",bindir)
		
		os.chdir(basedir)
		return

	def untar(self):
		pass

	def checkProgram(self,name=None):
		pathlist=[os.path.join(os.getcwd(),"bin"), r'C:\WINDOWS', r'C:\WINDOWS\system32', r'C:\WINNT']
		found=False
		if name=="mplayer":
			name+=".exe -v"
		elif name=="mencoder":
			name+=".exe -msglevel help"
		elif name=="dvdauthor":
			name+=".exe --help"
		elif name=="vcdimager":
			name+=".exe --help"
		elif name=="mkisofs":
			name+=".exe -help"
		elif name=="grep":
			name+=".exe --v"
		elif name=="ln":
			name+=".exe --help"
		elif name=="spumux":
			name+=".exe --help"
		print name
		for x in pathlist:
			print "x: ", x
			y=os.path.join(x,name)
			print "y: ", y
			try:
				#z = check_program(y)
				z=subprocess.Popen(y)
				print "z: ", z
				z.wait()
				if z.returncode == 127:
					continue
				else:
					found=True
					break
			except OSError:
				print "Error Checking Program Exist"
		return found

	def testFunc(self):
		print "In test func"
		return


message = "Other end disconnected!"

def recv_some(p, t=.1, e=1, tr=5, stderr=0):
	print "recv_some"
	if tr < 1:
		tr = 1
		print "tr: ", tr
	x = time.time()+t
	y = []
	r = ''
	pr = p.recv
	#print "pr: ", pr
	if stderr:
		pr = p.recv_err
		print "pr_err: ", pr
	while time.time() < x or r:
		r = pr()
		#print "r: ", r
		if r is None:
			if e:
				print message
				raise Exception(message)
			else:
				break
		elif r:
				y.append(r)
		else:
			delay=(x-time.time())/5
			if delay>0:
				time.sleep(delay)
			else:
				time.sleep(max((x-time.time())/tr, 0))
	return ''.join(y)

def send_all(p, data):
	while len(data):
		sent = p.send(data)
		if sent is None:
			raise Exception(message)
		data = buffer(data, sent)

if __name__ == "__main__":
	
	s = GetPrograms()
	s.displayCheckmarkGui()
	


