# basictimerapp - a really simple timer application.

import win32ui
import win32api
import win32con
import sys
import app
import dlgappcore
import timer
import time
import string
import regsub
import cmdline

class TimerAppDialog(dlgappcore.AppDialog):
	softspace=1
	def __init__(self, appName = ""):
		dlgappcore.AppDialog.__init__(self, win32ui.IDD_GENERAL_STATUS)
		self.timerAppName = appName
		self.argOff = 0
		if len(self.timerAppName)==0:
			if len(sys.argv)>1 and sys.argv[1][0]!='/': 
				self.timerAppName = sys.argv[1]
				self.argOff = 1

	def PreDoModal(self):
#		sys.stderr = sys.stdout
		pass

	def ProcessArgs(self, args):
		for arg in args:
			if arg=="/now":
				self.OnOK()

	def OnInitDialog(self,msg):
		win32ui.RegisterInstanceHandler(string.join(sys.appargv[:sys.appargvoffset]), self.GetSafeHwnd())
		win32ui.SetProfileFileName('pytimer.ini')
		self.title = win32ui.GetProfileVal(self.timerAppName, "Title", "Remote System Timer")
		self.buildTimer = win32ui.GetProfileVal(self.timerAppName, "Timer", "EachMinuteIntervaler()")
		self.doWork = win32ui.GetProfileVal(self.timerAppName, "Work", "DoDemoWork()")
		# replace "\n" with real \n.
		self.doWork =  regsub.gsub('\\\\n','\n', self.doWork)
		dlgappcore.AppDialog.OnInitDialog(self, msg)

		self.SetWindowText(self.title)
		self.prompt1 = self.GetDlgItem(win32ui.IDC_PROMPT1)
		self.prompt2 = self.GetDlgItem(win32ui.IDC_PROMPT2)
		self.prompt3 = self.GetDlgItem(win32ui.IDC_PROMPT3)
		self.butOK = self.GetDlgItem(win32con.IDOK)
		self.butCancel = self.GetDlgItem(win32con.IDCANCEL)
		self.prompt1.SetWindowText("Python Timer App")
		self.prompt2.SetWindowText("")
		self.prompt3.SetWindowText("")
		self.butOK.SetWindowText("Connect now")
		self.butCancel.SetWindowText("Close")

		self.timerManager = TimerManager(self)
		self.ProcessArgs(sys.argv[self.argOff:])
		self.timerManager.go()

	def OnDestroy(self,msg):
		dlgappcore.AppDialog.OnDestroy(self, msg)
		self.timerManager.stop()
	def OnOK(self):
		# stop the timer, then restart after setting special boolean
		self.timerManager.stop()
		self.timerManager.bConnectNow = 1
		self.timerManager.go()
		
		return
#	def OnCancel(self): default behaviour - cancel == close.
#		return 

class TimerManager:
	def __init__(self, dlg):
		self.dlg = dlg
		self.timerId = None
		self.intervaler = eval(self.dlg.buildTimer)
		self.bConnectNow = 0
		self.bHaveSetPrompt1 = 0
	def CaptureOutput(self):
		self.oldOut = sys.stdout
		self.oldErr = sys.stderr
		sys.stdout = sys.stderr = self
		self.bHaveSetPrompt1 = 0
	def ReleaseOutput(self):
		sys.stdout = self.oldOut
		sys.stderr = self.oldErr
	def write(self, str):
		s = string.strip(str)
		if len(s):
			if self.bHaveSetPrompt1:
				dest = self.dlg.prompt3
			else:
				dest = self.dlg.prompt1
				self.bHaveSetPrompt1 = 1
			dest.SetWindowText(s)
	def go(self):
		self.OnTimer(None,None)
	def stop(self):
		if self.timerId: timer.kill_timer (self.timerId)
		self.timerId = None

	def OnTimer(self, id, timeVal):
		if id: timer.kill_timer (id)
		if self.intervaler.IsTime() or self.bConnectNow :
			# do the work.
			try:
				self.dlg.SetWindowText(self.dlg.title + " - Working...")
				self.dlg.butOK.EnableWindow(0)
				self.dlg.butCancel.EnableWindow(0)
				self.CaptureOutput()
				try:
					exec(self.dlg.doWork)
					print "The last operation completed successfully."
				except:
					str = "Failed: %s: %s" % (sys.exc_type, `sys.exc_value`)
					print str
					self.oldErr.write(str)
			finally:
				self.ReleaseOutput()
				self.dlg.butOK.EnableWindow()
				self.dlg.butCancel.EnableWindow()
				self.dlg.SetWindowText(self.dlg.title)
		else:
			now = time.time()
			nextTime = self.intervaler.GetNextTime()
			if nextTime:
				timeDiffSeconds = nextTime - now
				timeDiffMinutes = int(timeDiffSeconds / 60)
				timeDiffSeconds = timeDiffSeconds % 60
				timeDiffHours = int(timeDiffMinutes / 60)
				timeDiffMinutes = timeDiffMinutes % 60
				self.dlg.prompt1.SetWindowText("Next connection due in %02d:%02d:%02d" % (timeDiffHours,timeDiffMinutes,timeDiffSeconds))
		self.timerId = timer.set_timer (self.intervaler.GetWakeupInterval(), self.OnTimer)
		self.bConnectNow = 0
		
class TimerIntervaler:
	def __init__(self):
		self.nextTime = None
		self.wakeUpInterval = 2000
	def GetWakeupInterval(self):
		return self.wakeUpInterval
	def GetNextTime(self):
		return self.nextTime
	def IsTime(self):
		now = time.time()
		if self.nextTime is None:
			self.nextTime = self.SetFirstTime(now)
		ret = 0
		if now >= self.nextTime:
			ret = 1
			self.nextTime = self.SetNextTime(self.nextTime, now)
			# do the work.
		return ret
	
class EachAnyIntervaler(TimerIntervaler):
	def __init__(self, timeAt, timePos, timeAdd, wakeUpInterval = None):
		TimerIntervaler.__init__(self)
		self.timeAt = timeAt
		self.timePos = timePos
		self.timeAdd = timeAdd
		if wakeUpInterval:
			self.wakeUpInterval = wakeUpInterval
	def SetFirstTime(self, now):
		timeTup = time.localtime(now)
		lst = []
		for item in timeTup:
			lst.append(item)
		bAdd = timeTup[self.timePos] > self.timeAt
		lst[self.timePos] = self.timeAt
		for pos in range(self.timePos+1, 6):
			lst[pos]=0
		ret = time.mktime(tuple(lst))
		if (bAdd):
			ret = ret + self.timeAdd
		return ret;			
		
	def SetNextTime(self, lastTime, now):
		return lastTime + self.timeAdd

class EachMinuteIntervaler(EachAnyIntervaler):
	def __init__(self, at=0):
		EachAnyIntervaler.__init__(self, at, 5, 60, 2000)

class EachHourIntervaler(EachAnyIntervaler):
	def __init__(self, at=0):
		EachAnyIntervaler.__init__(self, at, 4, 3600, 10000)

class EachDayIntervaler(EachAnyIntervaler):
	def __init__(self,at=0):
		EachAnyIntervaler.__init__(self, at, 3, 86400, 10000)

class TimerDialogApp(dlgappcore.DialogApp):
	def CreateDialog(self):
		return TimerAppDialog()
	def OnInstanceHandler(self, cmd):
		dlgappcore.DialogApp.OnInstanceHandler(self, cmd)
		self.dlg.ProcessArgs(cmdline.ParseArgs(cmd))



def DoDemoWork():
	print "Doing the work..."
	print "About to connect"
	win32api.MessageBeep(win32con.MB_ICONASTERISK)
	win32api.Sleep(2000)
	print "Doing something else..."
	win32api.MessageBeep(win32con.MB_ICONEXCLAMATION)
	win32api.Sleep(2000)
	print "More work."
	win32api.MessageBeep(win32con.MB_ICONHAND)
	win32api.Sleep(2000)
	print "The last bit."
	win32api.MessageBeep(win32con.MB_OK)
	win32api.Sleep(2000)


app.AppBuilder = TimerDialogApp

def t():
	t = TimerAppDialog("BoyerHeadOffice")
	t.DoModal()
	return t