from __future__ import print_function
# Base Class
import timer

# To see if in Timespan and to determine begin of timespan
from time import localtime, mktime, time, strftime

# Config
from Components.config import config

def checkTimespan(begin):
	# Get current time
	time = localtime()

	# Check if we span a day
	if begin[0] > end[0] or (begin[0] == end[0] and begin[1] >= end[1]):
		# Check if begin of event is later than our timespan starts
		if time.tm_hour > begin[0] or (time.tm_hour == begin[0] and time.tm_min >= begin[1]):
			# If so, event is in our timespan
			return True
		# Check if begin of event is earlier than our timespan end
		if time.tm_hour < end[0] or (time.tm_hour == end[0] and time.tm_min <= end[1]):
			# If so, event is in our timespan
			return True
		return False
	else:
		# Check if event begins earlier than our timespan starts
		if time.tm_hour < begin[0] or (time.tm_hour == begin[0] and time.tm_min < begin[1]):
			# Its out of our timespan then
			return False
		# Check if event begins later than our timespan ends
		if time.tm_hour > end[0] or (time.tm_hour == end[0] and time.tm_min > end[1]):
			# Its out of our timespan then
			return False
		return True
		
class MerlinTimerEntry(timer.TimerEntry):
	"""TimerEntry ..."""
	def __init__(self, begin, tocall, nocheck = False):
		timer.TimerEntry.__init__(self, int(begin), int(begin))

		self.function = tocall
		self.nocheck = nocheck
		if nocheck:
			self.state = self.StatePrepared

	def getNextActivation(self):
		# We delay our activation so we won't rush into reprocessing a repeating one
		return self.begin+1

	def activate(self):
		if self.state == self.StateWaiting:
			# Check if in timespan
			if checkTimespan(config.plugins.merlinupdatechecker.time.value):
				return True
			else:
				print("[MerlinTimer] Not in timespan, ending timer")
				self.state = self.StateEnded
				return False
		elif self.state == self.StateRunning:
			if self.function is not None:
				self.function()

		return True

	def resetState(self):
		self.state = self.StateWaiting
		self.cancelled = False
		self.timeChanged()

	def timeChanged(self):
		if self.nocheck and self.state < self.StateRunning:
			self.state = self.StatePrepared

	def shouldSkip(self):
		return False

	def __repr__(self):
		return ''.join((
				"<MerlinTimerEntry (",
				', '.join((
					strftime("%c", localtime(self.begin)),
					str(self.repeated),
					str(self.function)
				)),
				")>"
			))

class MerlinTimer(timer.Timer):
	def __init__(self):
		timer.Timer.__init__(self)

	def remove(self, entry):
		print("[MerlinUpdateChecker] Timer removed " + str(entry))

		# avoid re-enqueuing
		entry.repeated = False

		# abort timer.
		# this sets the end time to current time, so timer will be stopped.
		entry.abort()

		if entry.state != entry.StateEnded:
			self.timeChanged(entry)

		print(("state: ", entry.state))
		print(("in processed: ", entry in self.processed_timers))
		print(("in running: ", entry in self.timer_list))
		# now the timer should be in the processed_timers list. remove it from there.
		self.processed_timers.remove(entry)

	def setUpdateTimer(self, tocall=None):
		now = localtime()
		begin = mktime(
			(now.tm_year, now.tm_mon, now.tm_mday,
			config.plugins.merlinupdatechecker.time.value[0],
			config.plugins.merlinupdatechecker.time.value[1],
			0, now.tm_wday, now.tm_yday, now.tm_isdst)
		)

		if config.plugins.merlinupdatechecker.lastscantime.value < begin and begin < time() and tocall is not None:
			print("[MerlinUpdateChecker] - we call our update function")
			tocall()
		else:
			print("[MerlinUpdateChecker] - we do not have to call the update function")
		
		if int(config.plugins.merlinupdatechecker.checkon.value) == now.tm_wday or config.plugins.merlinupdatechecker.checkon.value == "127":
			print("[MerlinUpdateChecker] - day matches config")
			if begin < time():
				print("[MerlinUpdateChecker] - we're passed the start time")
				if config.plugins.merlinupdatechecker.checkon.value == "127":
					# let's try our luck the next day	
					print("[MerlinUpdateChecker] - let's check again tomorrow - daily")
					begin = begin+86400
				else:
					# next time is in a week				
					print("[MerlinUpdateChecker] - let's check again in one week")
					begin = begin+(7*86400)
			else:
				print("[MerlinUpdateChecker] - we've not yet reached the start time")
				
		else:
			print("[MerlinUpdateChecker] - day does not match config")
			delta = now.tm_wday - int(config.plugins.merlinupdatechecker.checkon.value)
			if delta < 0:
				remdays = delta*-1
			else:
				remdays = 7 - delta
			begin = begin+(remdays*86400)			

		updateTimer = MerlinTimerEntry(begin, tocall, nocheck = True)
		print("[MerlinUpdateChecker] - Timer is set to ", updateTimer)

		i = 0
		while i < 7:
			updateTimer.setRepeated(i)
			i += 1

		self.addTimerEntry(updateTimer)

	def add(self, entry):
		entry.timeChanged()
		print("[MerlinUpdateChecker] Timer added " + str(entry))
		self.addTimerEntry(entry)

	def clear(self):
		self.timer_list = []

	def isActive(self):
		return len(self.timer_list) > 0
	      
	def calcNextActivation(self):
		self.processActivation()
		self.lastActivation = time()
	
		min = int(time()) + self.MaxWaitTime
		
		# calculate next activation point
		timer_list = [ t for t in self.timer_list if not t.disabled ]
		if timer_list:
			w = timer_list[0].getNextActivation()
			if w < min:
				min = w
			else:
				print ("[MerlinUpdateChecker] next real activation is %s" % (strftime("%c", localtime(w))))
		
		self.setNextActivation(min)      

merlintimer = MerlinTimer()