import time
import random
import os
import shutil

DEFAULT_MINUTE = random.randrange(1, 59)
DEFAULT_RUN_TIMES = [x + ":" + "%02d" % DEFAULT_MINUTE for x in ["4","10","16"]]
DEFAULT_RUN_TIMES_ENABLE = ["0","0","0"]
DEFAULT_ENABLE_AUTO = "off"
DEFAULT_RUN_MODE = "specific"
DEFAULT_INTERVAL_HOURS = 12.0
DEFAULT_STARTING_AT = "00:" + "%02d" % DEFAULT_MINUTE

class SchedulerConfig:
    def __init__(self,scheduleFile):
        #defaults
        self.runTimes = DEFAULT_RUN_TIMES
        self.runTimesEnable = [int(x) for x in DEFAULT_RUN_TIMES_ENABLE]
        self.defaultMinute = DEFAULT_MINUTE
        self.runMode = DEFAULT_RUN_MODE
        self.enableAuto = DEFAULT_ENABLE_AUTO
        self.intervalHours = DEFAULT_INTERVAL_HOURS
        self.startingAt = DEFAULT_STARTING_AT
        self.scheduleFile = scheduleFile

        if not os.path.exists(self.scheduleFile):
            try:
                pf = open(self.scheduleFile,"w")
                pf.write("runTimes=")
                pf.write('"'+",".join(DEFAULT_RUN_TIMES)+'"\n')
                pf.write("runTimesEnable=")
                pf.write('"'+",".join(DEFAULT_RUN_TIMES_ENABLE)+'"\n')
                pf.write("defaultMinute="+str(DEFAULT_MINUTE)+"\n")
                pf.write("enableAuto="+DEFAULT_ENABLE_AUTO+"\n")
                pf.write("runMode="+DEFAULT_RUN_MODE+"\n")
                pf.write("intervalHours="+str(DEFAULT_INTERVAL_HOURS)+"\n")
                pf.write("startingAt="+DEFAULT_STARTING_AT+"\n")
            finally:
                pf.close()
        else:
            try:
                pf = open(self.scheduleFile,"r")
                for l in pf:
                    #print (l.strip()).split("=")
                    (key,val) = (l.strip()).split("=")
                    if key == "runTimes":
                        self.runTimes = (val.strip('"')).split(",")
                    elif key == "defaultMinute":
                        self.defaultMinute = int(val)
                    elif key == "runMode" and (val in ["specific","regular"]):
                        self.runMode = val
                    elif key == "enableAuto" and (val in ["on","off"]):
                        self.enableAuto = val
                    elif key == "intervalHours":
                        self.intervalHours = float(val)
                    elif key == "runTimesEnable":
                        self.runTimesEnable = [int(x) for x in (val.strip('"')).split(",")]
                    elif key == "startingAt":
                        self.startingAt = val
            finally:
                pf.close()

        #Ensure runTimesEnable mask is big enough
        while len(self.runTimesEnable) < len(self.runTimes):
            self.runTimesEnable.append(0)

    def DumpToFile(self):
        #make backup
        shutil.copyfile(self.scheduleFile,self.scheduleFile+".bak")
        try:
            #print "writing"
            pf = open(self.scheduleFile,"w")
            pf.write("runTimes=")
            pf.write('"'+",".join(self.runTimes)+'"\n')
            pf.write("runTimesEnable=")
            pf.write('"'+",".join([str(x) for x in self.runTimesEnable])+'"\n')
            pf.write("defaultMinute="+str(self.defaultMinute)+"\n")
            pf.write("enableAuto="+self.enableAuto+"\n")
            pf.write("runMode="+self.runMode+"\n")
            pf.write("intervalHours="+str(self.intervalHours)+"\n")
            pf.write("startingAt="+self.startingAt+"\n")
        finally:
            pf.close()

class Scheduler:

    def __init__(self,sc):
        self.config = sc
        self.scheduledRuns = []
        self.lastRun = -1
        self.lastCheck = 0

    def secondsSinceMidnight(self,timeStruct):
        return (timeStruct.tm_hour*3600) + (timeStruct.tm_min*60) + timeStruct.tm_sec


    def stringTimeToSeconds(self,stringTime):
        timeParts = stringTime.split(":")
        hour = int(timeParts[0])
        min = int(timeParts[1])

        return (hour*3600) + (min*60)

    def initScheduledRuns(self):
        self.scheduledRuns = []
        if self.config.runMode == "specific":
            for i in range(len(self.config.runTimes)):
                if self.config.runTimesEnable[i] == 1:
                    self.scheduledRuns.append(self.stringTimeToSeconds(self.config.runTimes[i]))
        elif self.config.runMode == "regular":
            for x in range(self.stringTimeToSeconds(self.config.startingAt),86400,int(self.config.intervalHours*3600)):
                self.scheduledRuns.append(x)
        self.scheduledRuns.sort()
        #print self.scheduledRuns
        #print time.asctime(self.getNextRun())

    #Return True if we should run, false otherwise
    def checkTimeToRun(self):
        if len(self.scheduledRuns) == 0:
            self.initScheduledRuns()
        if len(self.scheduledRuns) == 0:
            #Nothing to do.
            return False

        result = False

        now = self.secondsSinceMidnight(time.localtime())

        if self.lastRun == -1:
            #First sweep after startup; don't run
            self.lastRun = now
            result = False
        else:
            if self.lastRun > now:
                #The last run was yesterday.
                if self.scheduledRuns[-1] > self.lastRun:
                    result = True
            else:
                #The last run was today.
                for testTime in self.scheduledRuns:
                    if testTime > self.lastRun and testTime <= now:
                        result = True

        if self.lastCheck > now:
            #Last check was yesterday.  We must reset lastRun for our own
            #internal accounting, regardless of the result.
            self.lastRun = 0

        self.lastCheck = now

        return result

    def logLastRun(self):
        self.lastRun = self.secondsSinceMidnight(time.localtime())

    def getNextRun(self):

        if len(self.scheduledRuns) == 0:
            return None
        
        now = self.secondsSinceMidnight(time.localtime())

        if now < self.scheduledRuns[-1]:
            #next run is today
            x = time.localtime()
            midnight = time.mktime((x[0],x[1],x[2],0,0,0,0,0,x[8]))
            for secondsSinceMidnight in self.scheduledRuns:
                if secondsSinceMidnight > now:
                    return time.localtime(midnight+secondsSinceMidnight)
        else:
            #next run is tomorrow
            x = time.localtime(time.time()+86400)
            midnight = time.mktime((x[0],x[1],x[2],0,0,0,0,0,x[8]))
            return time.localtime(midnight+self.scheduledRuns[0])
