# basictimerapp - a really simple timer application.
# This should be run using the command line:
# pythonwin /app demos\basictimerapp.py
import win32ui
import win32api
import win32con
import sys
from pywin.framework import app, cmdline, dlgappcore, cmdline
import timer
import time
import string

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):
		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 =  self.doWork.replace('\\n','\n')
		dlgappcore.AppDialog.OnInitDialog(self)

		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("Do it now")
		self.butCancel.SetWindowText("Close")

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

	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 = str.strip()
		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:
					t, v, tb = sys.exc_info()
					str = "Failed: %s: %s" % (t, repr(v))
					print(str)
					self.oldErr.write(str)
					tb = None # Prevent cycle
			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 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 = TimerDialogApp()

def t():
	t = TimerAppDialog("Test Dialog")
	t.DoModal()
	return t

if __name__=='__main__':
		import demoutils
		demoutils.NeedApp()