# xbu_main.py (v0.3.1)
# main program to run for upgrade script
#
# 9-18-2010 NWF
#
# TODO:
# 
import os
import sys
import string
import threading
import config
import xbu_upgr
import datetime
from time import sleep
from time import strftime
from xbu_upgr import XBeeFwUpgrade
# take out, debug only
from msvcrt import getch

# idigiInfo offsets 
IDIGI_ADDR_OFFSET = 0
HTTP_PORT_OFFSET = 1
USERNAME_OFFSET = 2
PASSWORD_OFFSET = 3

# fileInfo offsets
DIRNAME_OFFSET = 0
FILENAME_OFFSET = 1
VER_REQ_OFFSET = 2

# upg task offsets
CWID_OFFSET = 0
CONN_STATUS = 1

try:
    # idigi server information
    idigiInfo = ((config.idigi_addr), (config.port), \
                 (config.username), (config.password))

    # firmware file information
    fwInfo = ((config.firmwaredir), (config.zb_filename), \
              (config.zb_version_required))

    # setting the firmware file will encode and store in the obj
    fwFullPath = fwInfo[DIRNAME_OFFSET] + fwInfo[FILENAME_OFFSET] 
    zbVerRequired = fwInfo[VER_REQ_OFFSET]

    # misc settings
    logfiledir = config.logfiledir
    logfilename = config.logfilename
    logfilepath = logfiledir + logfilename
    radio_upg_candidates = config.radio_upg_candidates

    # check firmware interval
    interval = config.interval_sec

    specialFlags = {}
    # check for force update
    specialFlags['forceupg'] = config.forceUpdate

except AttributeError:
    print "error loading prefernces"
else:
    pass

def DumpToFile(xmlfilename, xmldata):
    filenamepath = "./" + xmlfile
    print "DumpToFile: filepath= ", filenamepath
    if (os.path.exists(filenamepath)):    
        handle = open(filenamepath, 'a')
    else:
        handle = open(filenamepath, 'w')
    handle.write(xmldata)
    handle.close()
    return True   

# DO: "useImgIndex" will be used for upgrader to support upgrading
#       ZNET and ZB firwmare.  Only ZB supported on first release.
# task format = [request, cwid, origFw, curFw, status, cb, <timestamp>]
# task = ["UPGR",  key, origfw, curfw, reason, cb, "na", useImgIndex]
# task = ["STORE", key, origfw, curfw, reason, cb, "na", "", <timestamp>]
# task = ["QUIT"]


class TaskMonitor(threading.Thread):
    def __init__(self, upgrdr):
        
        self._isRunning = True
        self._upgrader = upgrdr
        self.encFirmware = upgrdr._encodedFwImg
        self.logfilepath = upgrdr.logFilePath
        self.tasksprocessed = 0
        # DO: To support ZNET and ZB upgrade monitoring
        #self.encFirmwareImages = []
        threading.Thread.__init__(self)

    def run(self):
        print "run"
        while self._isRunning == True:
            try:
                status = ""
                message = ""
                verified = False
                task = self._upgrader.dequeue()
                print "\nthread: ", task
                taskType = task[0]
                print taskType
                if taskType is None:
                    sleep(20)
                elif (taskType == "QUIT"):
                    break
                elif (taskType == "STORE"):
                    print "TaskMonitor: STORING..."
                    #taskCallback(task, self.logfilepath)
                elif (taskType == "UPGR"):
                    print "TaskMonitor: UPGRADING..."
                    cwid = task[1]
                    #taskCallback = task[6]
                    print "TaskMonitor: upgrade task in progress..."
                    status, msg, verified = self._upgrader.upgrade_dev_fw(cwid)
                    # timestamp task finished, log to file, update main dict
                    
                    print "TaskMonitor: status = ", status
                    print "TaskMonitor: msg = ", msg
                    print "TaskMonitor: verified = ", verified
                    print "TaskMonitor: (type)", type(task)

                self.tasksprocessed += 1
                taskCallback = task[6]
                # make tuple a list
                print "TaskMonitor: task[4] BEFORE = ", task[4]
                if (verified == True):
                    task[4] = zbVerRequired #currVer
                print "TaskMonitor: task[4] AFTER = ", task[4]
                # For debug only
                #print "TaskMonitor: PRESS SPACEBAR TO CONTINUE..."
                #getch()
                taskCallback(task, self.logfilepath)

            except Exception, ex:
                print "TaskMonitor: exception= ", ex 
                self.stop_thread()
            else:
                continue
        print "Thread exiting, returning processed = ", self.tasksprocessed
        return self.tasksprocessed
    
    def stop_thread(self):
        print "stop_thread: enter"
        self._isRunning = False
        
    def upgrade_device(self, cwid):
        print "upgrade_device: enter"
        status = self._upgrader.send_fw_file(cwid)
        print "thread upg_dev status= ", status

def log_dlist_to_file(dList):
    if (os.path.exists("./disconn.py")):    
        handle = open("./disconn.py", 'a')
    else:
        lIndex = 0
        handle = open("./disconn.py", 'w')
        handle.write("# disconn.py\n")
        handle.write("#\n")
        handle.write("# Disconnected Devices")
        handle.write("\n# (File created %s)\n" % datetime.datetime.now())
        handle.write("# ============================================\n")
        handle.write("#\n")
        handle.write("dList= [\\\n")

    timestamp = strftime("%d-%m-%Y %H:%M:%S")
    for lst in dList:
        logStr = repr(lst) + ",\\\n"
        handle.write(logStr)
    handle.close()
    print "returning TRUE"
    return True


def ProcComplHandler(data):
    print "ProcCompleteHandler: ", data

def main():
    initialized = False

    #if (os.path.exists("./output.txt")):    
    #    fh = open("./output.txt", 'a')
    #else:
    #    fh = open("./output.txt", 'w')
    #fh.write("\n(started %s)\n" % datetime.datetime.now())
    #fh.write("====================================\n")

    xbUpgrMan = XBeeFwUpgrade(idigiInfo, fwInfo, logfilepath)
    status = xbUpgrMan.set_firmware_file(fwFullPath)
    status = xbUpgrMan.set_hwtype_ok(radio_upg_candidates)

    #status = xbUpgrMan.blast_upgrade()

    while 1:
        try:
            print "Start: checking for upgrades..."
            # clears existing, query idigi, builds new device dict
            status = xbUpgrMan.build_device_dict(True)

            if (status == True):
                # query idigi, add version info to master list
                status = xbUpgrMan.add_radio_info_to_devices(True)
                
                if (status == True):
                    # processes all devices in master list and returns
                    numQ = xbUpgrMan.process_devices(ProcComplHandler,\
                                                     specialFlags)
                    print numQ
                    print "%d upgrade tasks, %d no changes\n" % \
                                            (numQ[0], numQ[1])

                    if numQ[0] > 1: # incl "QUIT" task
                        print "Processing upgrade tasks..."
                        mon_thread = TaskMonitor(xbUpgrMan)
                        
                        mon_thread.daemon = True
                        print "Start thread"
                        mon_thread.start()
                        mon_thread.join()
    
                    print "Task processing has stopped.\n"

                    print "Next check: %d seconds.\n"  % (interval)
                    print "Press <cntrl-c> to immediately start another upgrade check.\n"
                    print "Press <cntrl-break> to exit program."
                    print "\nWaiting..."
                    sleep(interval)
                else:
                    return False
            else:
                return False
        except (KeyboardInterrupt):
            pass
        except (SystemExit):
            print "main: Application exit request. Exiting."
        except Exception, ex:
            print "main: A problem as occured = ", ex
            sys.exit(0)
        else:    
            return True

if __name__ == '__main__':
    print "** MAIN ENTER **"
    ret = main()
    print "** MAIN EXIT: returned ", ret
