from eon_helper import *

class eon():
	"""
	#+
	# NAME:
	#	class eon
	# PURPOSE:
	#	Defines a class for storing times
	# PROCEDURE:
	#	The main instance attributes are
	#
	#	self.ticday   integer, number of days since 2000/01/01 00:00:00 UT
	#	                       i.e. Midnight, Jan 1, 2000 in the Gregorian calendar
	#	self.tictac	  integer, represents the time of day in units of 1/10^self.exponent
	#	self.exponent integer, defines the unit of self.tictac
	#
	#	These three attributes must always be set by the __init__ method.
	#
	#	Other time properties will be calculated only when needed, and are then
	#	also stored as instance attributes for later recall.
	#	This is sometimes already done by the __init__ method, but in general
	#	this task is delegated to the __getattr__ method (which calculates and
	#	stores the property when it is referenced as an attribute).
	#
	#	Currently the following extra attributes are supported:
	#
	#		jd
	#		mjd
	#		njd
	#		posix
	#		jepoch
	#		bepoch
	#
	#	Both Gregorian and Julian calendar are supported. This affects four
	#	time properties:
	#
	#	For Gregorian dates:
	#	    year
	#	    doy
	#	    month
	#	    day
	#
	#	Julian dates are tracked separately:
	#	    julian_year
	#	    julian_doy
	#	    julian_month
	#	    julian_day
	# TODO:
	#	Handle time zones. Currently everything is UTC.
	#	- Input of times with timezone has been implemented (2012-05)
	#	Probably should be handled similar to the Julian calendar.
	#
	#	Documentation
	#-
	"""

	BadTypes = [type(None),type(NotImplemented)]

	def normalize(self):
		'''
		#+
		# NAME:
		#	eon.normalize
		# PURPOSE:
		#	(Internal purposes only)
		#	Is used to normalize eon object (see PROCEDURE).
		# PROCEDURE:
		#	Ensures that self.tictac is positive and is less than one
		#	day. As a result self.ticday will always refer to the
		#	midnight at the beginning of day (in UTC) for the eon object.
		#	Note that neither self.ticday nor self.tictac are forced to
		#	be integer. This is intentional. By the time this routine is
		#	called (by eon.__init__) these quantities should already be
		#	integers.
		#-
		'''
		tictacs_per_day = g_SECONDS_PER_DAY*10**self.exponent

		(day, self.tictac) = divmod(self.tictac,tictacs_per_day)
		self.ticday += day

		return

	def adjust_for_timezone( self ):

		if self.timezone == None:
			self.timezone = 0

		elif is_string(self.timezone):
			tz_hour, tz_minute = disassemble_timezone(self.timezone)
			self.timezone = (tz_hour*60+tz_minute)*60*10**self.exponent
			if self.timezone != 0:
				self.tictac += self.timezone
	 			self.normalize()

		else:
			if self.timezone != 0:
				self.tictac -= self.timezone
	 			self.normalize()
			del self.__dict__['timezone']

		return

	def __repr__( self ):

		return 'ticday: %s, tictac: %s, exponent: %s'%(self.ticday, self.tictac, self.exponent)

	def __str__( self ):

		return 'ticday: %s, tictac: %s, exponent: %s'%(self.ticday, self.tictac, self.exponent)

	def __eq__(self, tt):

		if type(tt) in eon.BadTypes:	# This allows statement like tt == None
			return False				# (Isn't it possible to define an eon NoneType??)

		exponent = max(self.exponent, tt.exponent)
		return self.ticday == tt.ticday and self.tictac*10**(exponent-self.exponent) == tt.tictac*10**(exponent-tt.exponent)

	def __ne__(self, tt):

		if type(tt) in eon.BadTypes:	# This allows statement like tt != None
			return True

		exponent = max(self.exponent, tt.exponent)
		return self.ticday != tt.ticday or self.tictac*10**(exponent-self.exponent) != tt.tictac*10**(exponent-tt.exponent)

	def __lt__(self, tt):

		exponent = max(self.exponent, tt.exponent)
		return self.ticday < tt.ticday or (self.ticday == tt.ticday and self.tictac*10**(exponent-self.exponent) < tt.tictac*10**(exponent-tt.exponent))

	def __le__(self, tt):

		exponent = max(self.exponent, tt.exponent)
		return self.ticday < tt.ticday or (self.ticday == tt.ticday and self.tictac*10**(exponent-self.exponent) <= tt.tictac*10**(exponent-tt.exponent))

	def __gt__(self, tt):

		exponent = max(self.exponent, tt.exponent)
		return self.ticday > tt.ticday or (self.ticday == tt.ticday and self.tictac*10**(exponent-self.exponent) > tt.tictac*10**(exponent-tt.exponent))

	def __ge__(self, tt):

		exponent = max(self.exponent, tt.exponent)
		return self.ticday > tt.ticday or (self.ticday == tt.ticday and self.tictac*10**(exponent-self.exponent) >= tt.tictac*10**(exponent-tt.exponent))

	def __cmp__(self, tt):

		exponent = max(self.exponent, tt.exponent)
		self_tictac = self.tictac*10**(exponent-self.exponent)
		tt_tictac	= tt.tictac  *10**(exponent-tt.exponent  )
		return -1 if self.ticday <  tt.ticday or (self.ticday == tt.ticday and	self_tictac <  tt_tictac)	else	\
				1 if self.ticday >  tt.ticday or (self.ticday == tt.ticday and	self_tictac >  tt_tictac)	else	\
				0

	def __coerce__(self, tt):
		return (self,tt)

	def __iadd__(self, tt):
		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()
		return NotImplemented

	def __add__( self, tt ):
		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()
		return NotImplemented

	def __isub__(self, tt):
		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()
		return NotImplemented

	def __sub__(self, tt):
		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()
		return NotImplemented

	def __pos__(self):
		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()
		return self

	def __neg__(self):

		# Only dates should get here (delta have their own
		# __neg__ in the class eon_delta.
		# __neg__ in class eon_date is not implemented.
		# If a useful definition for -date can be cooked up
		# then that __neg__ should be introduced.

		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()
		raise TypeError, 'illegal operation - (negation) for '+str(self.__class__)
		#return NotImplemented

	def __imul__(self, multiplier):
		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()
		return NotImplemented

	def __mul__(self, multiplier):
		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()
		return NotImplemented

	def __rmul__(self, multiplier):
		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()
		return NotImplemented

	def __div__(self, multiplier):
		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()
		return NotImplemented

	def __idiv__(self, divider):
		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()
		return NotImplemented

	def __rdiv__(self, divider):
		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()
		return NotImplemented

	def __abs__(self):
		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()
		return NotImplemented

	def linear_transform(self, tt=None, factor=None, exponent=None ):
		if g_EON_DEBUG: print self.__class__, 'in eon', whoami()

		# Note that this does not compare the instance types, so it is the users
		# responsibility not to do anything silly, like adding a date to a date, etc.
		# When this is called from other methods, this check has been done.

		# factor =  1    : copy
		# factor =  1, exponent=exponent: smaller units of chipsec
		# factor = (0, 1): swap
		# factor = (1, 1): add
		# factor = (1,-1): subtract

		if exponent == None: exponent = self.exponent

		if type(tt) == type(None):

			if factor == None: factor = 1

			exponent = max(exponent, self.exponent)
			ticday	 = factor*self.ticday
			tictac   = factor*self.tictac*10**(exponent-self.exponent)

			eon_type = 'eon_delta' if 'eon_delta' in str(self.__class__) else 'eon_date'

		else:

			if factor == None: factor = (1,0)

			exponent = max(exponent, self.exponent, tt.exponent)
			ticday	 = factor[0]*self.ticday								+ factor[1]*tt.ticday
			tictac   = factor[0]*self.tictac*10**(exponent-self.exponent)	+ factor[1]*tt.tictac*10**(exponent-tt.exponent)

			# Really need logical exclusive-or here

			# if (isinstance(self,eon_date ) and isinstance(tt,eon_date )) or	\
			#   (isinstance(self,eon_delta) and isinstance(tt,eon_delta)):
			# Do not use 'eon_date' here, because
			# t.__class__ will contain eon_date.eon_date or eon_date.eon_delta,
			# so 'eon_date' will always match.

			eon_type = 'eon_delta'if ('eon_delta' in str(self.__class__)) == ('eon_delta' in str(tt.__class__)) else 'eon_date'

		(ticday, tictac) = fix_ds(ticday,0,0,0,tictac,exponent=exponent)

		return self.make_instance(eon_type, ticday, tictac, exponent)

	#+
	# NAME:
	#	eon.between
	# PURPOSE:
	#	Check whether time is in specified time period
	# CALLING SEQUENCE:
	#	is_between = tt.between( t0, t1)
	# PROCEDURE:
	#	if both start_time and stop_time are not None then
	#		True means start_time <= self < stop_time
	#	if only start_time is not None then
	#		True means self >= start_time.
	#	If only stop_time is not None then
	#		True mean self < stop_time
	#	If both start_time and stop_time are None then
	#		always True is returned
	#-

	def between(self, start_time, stop_time):
		#return False if (start_time != None and self < start_time) or (stop_time != None and self >= stop_time) else True

		status = True
		if start_time != None and self < start_time:
			status = False
		if stop_time  != None and self >= stop_time:
			status = False

		return status
