"""
Python script a module to comunicate with apple events

v 0.1a2
v.0.2 16 april 1998 


"""
import sys
import getaete
import baetools
import baetypes
from Carbon import AE
import AppleEvents
import macfs
from types import *
#from aetypes import InstanceType
from aepack import AEDescType

ordinal = {
'every': 'all ',
'first' : 'firs',
'last' : 'last',
'any' : 'any ',
'middle' : 'midd'}


Error = 'PythonScript.Error'


class PsEvents:
	pass


class PsClasses:

	
	def __getattr__(self, name):
		try:
			return DCItem(name, self)
		except:
			pass
		
	def __repr__(self):
		if self.form != 'prop':
			t = type(self.seld)
			if t == StringType:
				self.form = 'name'
			elif baetypes.IsRange(self.seld):
				self.form = 'rang'
			elif baetypes.IsComparison(self.seld) or baetypes.IsLogical(self.seld):
				self.form = 'test'
			elif t == TupleType:
			# Breakout: specify both form and seld in a tuple
			# (if you want ID or rele or somesuch)
				self.form, self.seld = self.seld
			elif t == IntType:
				self.form = 'indx'
			else:
				pass

		if self.seld in ordinal.keys():
			self.seld = baetypes.Ordinal(ordinal[self.seld])
			self.form = 'indx'

		s = "baetypes.ObjectSpecifier(%s, %s, %s" % (`self.want`, `self.form`, `self.seld`)
		if `self.fr`:
			s = s + ", %s)" % `self.fr`
		else:
			s = s + ")"
		return s
		
	def __str__(self):
		return self.want
		
		
def template(self, seld=None, fr=None):
	self.seld = seld
	self.fr = fr
		
def template1(self, which, fr=None):
	self.want = 'prop'
	self.form = 'prop'
	self.fr = fr
	
class DCItem:
	def __init__(self, comp, fr):
		self.compclass = comp
		self.fr = fr
		
	def __call__(self, which=None):
		if which:
			self.compclass = eval('PsClass.%s' % self.compclass)
		else:
			try:
				self.compclass = eval('PsProperties.%s' % self.compclass)
			except AttributeError:
				self.compclass = eval('PsClass.%s' % self.compclass)
		return self.compclass(which, self.fr)

class PsClass:
	pass

class PsProperties:
	pass				


class PsEnumerations:
	pass

			
def PsScript(sig=None, Timeout=0, Ignoring=0):
	elements = {}
	if sig:
		target, sig = Signature(sig)
		pyscript = getaete.Getaete(sig)
	else:
		target, sig = Signature('Pyth')
		pyscript = getaete.Getaete()
	setattr(PyScript, 'timeout', Timeout)
	setattr(PyScript, 'ignoring', Ignoring)
	setattr(PyScript, 'target', target)
	for key, value in pyscript[0].items():
		setattr(PsEvents, key, value)
	for key, value in pyscript[1].items():
		CreateClass(key, 'PsClasses', value)
		for val in value[2]:
			CreateProperty(val[0], 'PsClasses', `val[1]`)
			
		if value[3]:
			for val in value[3]:
				if val[0] not in elements.keys():
					elements[val[0]] = val[1]
				elif len(val[1]) > len(elements[val[0]]):
					elements[val[0]] = val[1]

	for key, value in pyscript[2].items():
		for val in value:
			setattr(PsEnumerations, val[0], val[1])

def CreateClass(newClassName, superClassName, value):
	parentDict = PsClass.__dict__
	exec "class %s(%s): pass" % (newClassName, superClassName) in \
			globals(), parentDict
	newClassObj = parentDict[newClassName]
	newClassObj.__init__ = template
	exec "setattr(newClassObj, 'want', %s)" % `value[0]`
	if value[2] and value[2][0][0] == 'every':
		exec "setattr(newClassObj, 'plur', 1)"

def CreateProperty(newClassName, superClassName, value):
	parentDict = PsProperties.__dict__
	exec "class %s(%s): pass" % (newClassName, superClassName) in \
			globals(), parentDict
	newClassObj = parentDict[newClassName]
	if newClassName == 'Every':
		value = "baetypes.mkOrdinal('every')"
	newClassObj.__init__ = template1
	exec "setattr(newClassObj, 'seld', %s)" % value

def Signature(signature):
	if type(signature) == AEDescType:
		target = signature
	elif type(signature) == InstanceType and hasattr(signature, '__aepack__'):
		target = signature.__aepack__()
	elif type(signature) == StringType:
		if len(signature) == 4:
			target = AE.AECreateDesc(AppleEvents.typeApplSignature, signature)
			target_signature = signature
		else:
			#This should ready be made persistant, so PythonScript 'remembered' where applications were
			fss, ok = macfs.PromptGetFile('Find the aplication %s' % signature, 'APPL')
			if ok:
				target_signature = fss.GetCreatorType()[0]
				target = AE.AECreateDesc(AppleEvents.typeApplSignature, target_signature)
	else:
		raise TypeError, "signature should be 4-char string or AEDesc"
	return target, target_signature

		

		
class PyScript(PsEvents):
	def __init__(self, name, obj=None,  **args):
		desc, code, subcode, rply, message, keywds = name
#		print 'code', code
#		print 'subcode', subcode
#		print 'rply', rply
#		print 'message', message
#		print 'keywds', keywds
#		print 'name', name
#		print 'obj', obj
#		print 'args', args
		self.code = code
		self.subcode = subcode
		self.attributes ={}
		self.arguments = {}
		if keywds:
			self.arguments = self.keyargs(keywds, args)
		self.arguments['----'] = self.keyfms(message[0], obj)

		##XXXX Eudora needs this XXXX##
		if self.arguments['----'] == None:
			del self.arguments['----']
#		print 'arguments', self.arguments
		if self.ignoring or rply[0] == 'null':
			self.send_flags = AppleEvents.kAENoReply
		else:
			self.send_flags = AppleEvents.kAEWaitReply
		self.send_priority = AppleEvents.kAENormalPriority	
		if self.timeout:
			self.send_timeout = self.timeout
		else:
			self.send_timeout = AppleEvents.kAEDefaultTimeout


	def keyargs(self, ats, args):
#		print 'keyargs', ats, args
		output = {}
		for arg in args.keys():
			for at in ats:
				if at[0] == arg:
					output[at[1]] = self.keyfms(at[2][0], args[arg])
		return output
				
	def keyfms(self, key, value):
#		print 'keyfms', 'key', key, `value`
		if key == 'obj ' or key == 'insl':
			return eval(`value`)
		elif key == 'TEXT':
			return value
		elif key == 'null':
			return 
		elif key == 'bool':
			return baetypes.mkboolean(value)
		elif key == 'type':
			try:
				val = eval('PsClass.%s()' % value)
				return baetypes.mktype(str(val))
			except:
				return baetypes.mktype(value)
		else:
			print "I don't know what to put here -- script.keyargs"
			print key, `value`
			sys.exit[1]
		
	def newevent(self, code, subcode, parameters = {}, attributes = {}):
		"""Create a complete structure for an apple event"""
#		print code, subcode, parameters, attributes
		event = AE.AECreateAppleEvent(code, subcode, self.target,
			  	  AppleEvents.kAutoGenerateReturnID, AppleEvents.kAnyTransactionID)
		baetools.packevent(event, parameters, attributes)
		return event
		
	def sendevent(self, event):
		"""Send a pre-created appleevent, await the reply and unpack it"""
		
		reply = event.AESend(self.send_flags, self.send_priority,
							  self.send_timeout)
		parameters, attributes = baetools.unpackevent(reply)
		return reply, parameters, attributes
		
	def send(self, code, subcode, parameters = {}, attributes = {}):
		"""Send an appleevent given code/subcode/pars/attrs and unpack the reply"""
#		print code, subcode, parameters, attributes
		return self.sendevent(self.newevent(code, subcode, parameters, attributes))
		
	def __str__(self):
		_reply, _arguments, _attributes = self.send(self.code, self.subcode, self.arguments, self.attributes)

		if _arguments.has_key('errn'):
			raise baetools.Error, baetools.decodeerror(_arguments)
		# XXXX Optionally decode result
		if _arguments.has_key('----'):
			return str(_arguments['----'])
		else:
			return 

	
	
def test():
	Simp = 'Hermit:Applications:SimpleText'
	PsScript('MACS', Timeout=60*60*3)
#	PsScript('CSOm', Timeout=60*60*3)
#	PsScript('', Timeout=60*60*3)
#	PyScript('macsoup')
	ev = PsEvents
	ps = PsClass
#	print PsProperties.__dict__
#	y = script(ev.Open, File('Hermit:Desktop Folder:Lincolnshire Imp'), using=Application_file(Simp))
#	print baetypes.NProperty('prop', 'prop', 'pnam',  baetypes.ObjectSpecifier('cdis', 'indx', 1, None))
#	y = PyScript(ev.Get, Disk("Hermit").Folder(7).File(1).Name())
#	y = PyScript(ev.Get, Disk("Hermit").Size(), As='Integer')
#	y = PyScript(ev.Get, ps.Desktopobject(1).Startup_disk())
#	y = PyScript(ev.Get, Mailbox(1).File(), as='TEXT')
#	print 'y', y, type(y)

if __name__ == '__main__':
	test()
#	sys.exit(1)
	
