"""aetypes - Python objects representing various AE types."""

from AppleEvents import *
from AERegistry import *
from AEObjects import *
import struct
from types import *
import string

#
# convoluted, since there are cyclic dependencies between this file and
# aetools_convert.
#
def pack(*args):
	from aepack import pack
	return apply(pack, args)
	
def IsSubclass(cls, base):
	"""Test whether CLASS1 is the same as or a subclass of CLASS2"""
	# Loop to optimize for single inheritance
	while 1:
		if cls is base: return 1
		if len(cls.__bases__) <> 1: break
		cls = cls.__bases__[0]
	# Recurse to cope with multiple inheritance
	for c in cls.__bases__:
		if IsSubclass(c, base): return 1
	return 0

def IsInstance(x, cls):
	"""Test whether OBJECT is an instance of (a subclass of) CLASS"""
	return type(x) is InstanceType and IsSubclass(x.__class__, cls)

def nice(s):
	"""'nice' representation of an object"""
	if type(s) is StringType: return repr(s)
	else: return str(s)

class Unknown:
	"""An uninterpreted AE object"""
	
	def __init__(self, type, data):
		self.type = type
		self.data = data
	
	def __repr__(self):
		return "Unknown(%s, %s)" % (`self.type`, `self.data`)
	
	def __aepack__(self):
		return pack(self.data, self.type)

class Enum:
	"""An AE enumeration value"""
	
	def __init__(self, enum):
		self.enum = "%-4.4s" % str(enum)
	
	def __repr__(self):
		return "Enum(%s)" % `self.enum`
	
	def __str__(self):
		return string.strip(self.enum)
	
	def __aepack__(self):
		return pack(self.enum, typeEnumeration)

def IsEnum(x):
	return IsInstance(x, Enum)

def mkenum(enum):
	if IsEnum(enum): return enum
	return Enum(enum)

class Type:
	"""An AE 4-char typename object"""
	
	def __init__(self, type):
		self.type = "%-4.4s" % str(type)
	
	def __repr__(self):
		return "Type(%s)" % `self.type`
	
	def __str__(self):
		return string.strip(self.type)
	
	def __aepack__(self):
		return pack(self.type, typeType)

def IsType(x):
	return IsInstance(x, Type)

def mktype(type):
	if IsType(type): return type
	return Type(type)


class Keyword:
	"""An AE 4-char keyword object"""
	
	def __init__(self, keyword):
		self.keyword = "%-4.4s" % str(keyword)
	
	def __repr__(self):
		return "Keyword(%s)" % `self.keyword`
	
	def __str__(self):
		return string.strip(self.keyword)
	
	def __aepack__(self):
		return pack(self.keyword, typeKeyword)

def IsKeyword(x):
	return IsInstance(x, Keyword)

class Range:
	"""An AE range object"""
	
	def __init__(self, start, stop):
		self.start = start
		self.stop = stop
	
	def __repr__(self):
		return "Range(%s, %s)" % (`self.start`, `self.stop`)
	
	def __str__(self):
		return "%s thru %s" % (nice(self.start), nice(self.stop))
	
	def __aepack__(self):
		return pack({'star': self.start, 'stop': self.stop}, 'rang')

def IsRange(x):
	return IsInstance(x, Range)

class Comparison:
	"""An AE Comparison"""
	
	def __init__(self, obj1, relo, obj2):
		self.obj1 = obj1
		self.relo = "%-4.4s" % str(relo)
		self.obj2 = obj2
	
	def __repr__(self):
		return "Comparison(%s, %s, %s)" % (`self.obj1`, `self.relo`, `self.obj2`)
	
	def __str__(self):
		return "%s %s %s" % (nice(self.obj1), string.strip(self.relo), nice(self.obj2))
	
	def __aepack__(self):
		return pack({'obj1': self.obj1,
			     'relo': mkenum(self.relo),
			     'obj2': self.obj2},
			    'cmpd')

def IsComparison(x):
	return IsInstance(x, Comparison)

class Logical:
	"""An AE logical expression object"""
	
	def __init__(self, logc, term):
		self.logc = "%-4.4s" % str(logc)
		self.term = term
	
	def __repr__(self):
		return "Logical(%s, %s)" % (`self.logc`, `self.term`)
	
	def __str__(self):
		if type(self.term) == ListType and len(self.term) == 2:
			return "%s %s %s" % (nice(self.term[0]),
			                     string.strip(self.logc),
			                     nice(self.term[1]))
		else:
			return "%s(%s)" % (string.strip(self.logc), nice(self.term))
	
	def __aepack__(self):
		return pack({'logc': mkenum(self.logc), 'term': self.term}, 'logi')

def IsLogical(x):
	return IsInstance(x, Logical)

class StyledText:
	"""An AE object respresenting text in a certain style"""
	
	def __init__(self, style, text):
		self.style = style
		self.text = text
	
	def __repr__(self):
		return "StyledText(%s, %s)" % (`self.style`, `self.text`)
	
	def __str__(self):
		return self.text
	
	def __aepack__(self):
		return pack({'ksty': self.style, 'ktxt': self.text}, 'STXT')

def IsStyledText(x):
	return IsInstance(x, StyledText)

class AEText:
	"""An AE text object with style, script and language specified"""
	
	def __init__(self, script, style, text):
		self.script = script
		self.style = style
		self.text = text
	
	def __repr__(self):
		return "AEText(%s, %s, %s)" % (`self.script`, `self.style`, `self.text`)
	
	def __str__(self):
		return self.text
	
	def __aepack__(self):
		return pack({keyAEScriptTag: self.script, keyAEStyles: self.style,
				 keyAEText: self.text}, typeAEText)

def IsAEText(x):
	return IsInstance(x, AEText)

class IntlText:
	"""A text object with script and language specified"""
	
	def __init__(self, script, language, text):
		self.script = script
		self.language = language
		self.text = text
	
	def __repr__(self):
		return "IntlText(%s, %s, %s)" % (`self.script`, `self.language`, `self.text`)
	
	def __str__(self):
		return self.text
	
	def __aepack__(self):
		return pack(struct.pack('hh', self.script, self.language)+self.text,
			typeIntlText)

def IsIntlText(x):
	return IsInstance(x, IntlText)

class IntlWritingCode:
	"""An object representing script and language"""
	
	def __init__(self, script, language):
		self.script = script
		self.language = language
	
	def __repr__(self):
		return "IntlWritingCode(%s, %s)" % (`self.script`, `self.language`)
	
	def __str__(self):
		return "script system %d, language %d"%(self.script, self.language)
	
	def __aepack__(self):
		return pack(struct.pack('hh', self.script, self.language),
			typeIntlWritingCode)

def IsIntlWritingCode(x):
	return IsInstance(x, IntlWritingCode)

class QDPoint:
	"""A point"""
	
	def __init__(self, v, h):
		self.v = v
		self.h = h
	
	def __repr__(self):
		return "QDPoint(%s, %s)" % (`self.v`, `self.h`)
	
	def __str__(self):
		return "(%d, %d)"%(self.v, self.h)
	
	def __aepack__(self):
		return pack(struct.pack('hh', self.v, self.h),
			typeQDPoint)

def IsQDPoint(x):
	return IsInstance(x, QDPoint)

class QDRectangle:
	"""A rectangle"""
	
	def __init__(self, v0, h0, v1, h1):
		self.v0 = v0
		self.h0 = h0
		self.v1 = v1
		self.h1 = h1
	
	def __repr__(self):
		return "QDRectangle(%s, %s, %s, %s)" % (`self.v0`, `self.h0`,
				`self.v1`, `self.h1`)
	
	def __str__(self):
		return "(%d, %d)-(%d, %d)"%(self.v0, self.h0, self.v1, self.h1)
	
	def __aepack__(self):
		return pack(struct.pack('hhhh', self.v0, self.h0, self.v1, self.h1),
			typeQDRectangle)

def IsQDRectangle(x):
	return IsInstance(x, QDRectangle)

class RGBColor:
	"""An RGB color"""
	
	def __init__(self, r, g, b):
		self.r = r
		self.g = g
		self.b = b
			
	def __repr__(self):
		return "RGBColor(%s, %s, %s)" % (`self.r`, `self.g`, `self.b`)
	
	def __str__(self):
		return "0x%x red, 0x%x green, 0x%x blue"% (self.r, self.g, self.b)
	
	def __aepack__(self):
		return pack(struct.pack('hhh', self.r, self.g, self.b),
			typeRGBColor)

def IsRGBColor(x):
	return IsInstance(x, RGBColor)

class ObjectSpecifier:
	
	"""A class for constructing and manipulation AE object specifiers in python.
	
	An object specifier is actually a record with four fields:
	
	key	type	description
	---	----	-----------
	
	'want'	type	what kind of thing we want,
			e.g. word, paragraph or property
	
	'form'	enum	how we specify the thing(s) we want,
			e.g. by index, by range, by name, or by property specifier
	
	'seld'	any	which thing(s) we want,
			e.g. its index, its name, or its property specifier
	
	'from'	object	the object in which it is contained,
			or null, meaning look for it in the application
	
	Note that we don't call this class plain "Object", since that name
	is likely to be used by the application.
	"""
	
	def __init__(self, want, form, seld, fr = None):
		self.want = want
		self.form = form
		self.seld = seld
		self.fr = fr
	
	def __repr__(self):
		s = "ObjectSpecifier(%s, %s, %s" % (`self.want`, `self.form`, `self.seld`)
		if self.fr:
			s = s + ", %s)" % `self.fr`
		else:
			s = s + ")"
		return s
	
	def __aepack__(self):
		return pack({'want': mktype(self.want),
			     'form': mkenum(self.form),
			     'seld': self.seld,
			     'from': self.fr},
			    'obj ')


def IsObjectSpecifier(x):
	return IsInstance(x, ObjectSpecifier)


class Property(ObjectSpecifier):

	def __init__(self, which, fr = None):
		ObjectSpecifier.__init__(self, 'prop', 'prop', mkenum(which), fr)

	def __repr__(self):
		if self.fr:
			return "Property(%s, %s)" % (`self.seld.enum`, `self.fr`)
		else:
			return "Property(%s)" % `self.seld.enum`
	
	def __str__(self):
		if self.fr:
			return "Property %s of %s" % (str(self.seld), str(self.fr))
		else:
			return "Property %s" % str(self.seld)


class SelectableItem(ObjectSpecifier):
	
	def __init__(self, want, seld, fr = None):
		t = type(seld)
		if t == StringType:
			form = 'name'
		elif IsRange(seld):
			form = 'rang'
		elif IsComparison(seld) or IsLogical(seld):
			form = 'test'
		else:
			form = 'indx'
		ObjectSpecifier.__init__(self, want, form, seld, fr)


class ComponentItem(SelectableItem):
	# Derived classes *must* set the *class attribute* 'want' to some constant
	
	def __init__(self, which, fr = None):
		SelectableItem.__init__(self, self.want, which, fr)
	
	def __repr__(self):
		if not self.fr:
			return "%s(%s)" % (self.__class__.__name__, `self.seld`)
		return "%s(%s, %s)" % (self.__class__.__name__, `self.seld`, `self.fr`)
	
	def __str__(self):
		seld = self.seld
		if type(seld) == StringType:
			ss = repr(seld)
		elif IsRange(seld):
			start, stop = seld.start, seld.stop
			if type(start) == InstanceType == type(stop) and \
			   start.__class__ == self.__class__ == stop.__class__:
				ss = str(start.seld) + " thru " + str(stop.seld)
			else:
				ss = str(seld)
		else:
			ss = str(seld)
		s = "%s %s" % (self.__class__.__name__, ss)
		if self.fr: s = s + " of %s" % str(self.fr)
		return s


template = """
class %s(ComponentItem): want = '%s'
"""

exec template % ("Text", 'text')
exec template % ("Character", 'cha ')
exec template % ("Word", 'cwor')
exec template % ("Line", 'clin')
exec template % ("Paragraph", 'cpar')
exec template % ("Window", 'cwin')
exec template % ("Document", 'docu')
exec template % ("File", 'file')
exec template % ("InsertionPoint", 'cins')

