import sys
import time
import logging

from ardi.driver import syncdatapoints

from suds.client import Client
from suds.bindings import binding

class datapointsync:
    def __init__(self):
        self.connected = False
        self.polling = True        
        self.subscription = ''
        self.ticket = ""
        self.optimised = False
        self.prefix = ""
        self.fetchset = []

    def SetAddress(self, addr):
        self.connected = False
        bits = addr.split("^")
        self.address = bits[0]
        if (len(bits) > 1):
            self.prefix = bits[1]
    
    def Connect(self):
        try:		
            #Get WSDL file for PI Web Services
            if (self.address[4:7] == "://"):
                self.address = self.address[7:]
            
            url = 'http://' + self.address + '/PIWebServices/PITimeSeries.svc?wsdl'
            self.core.logger.info("Loading " + url)
            
            self.core.logger.debug("Connecting via SOAP 1.1")
            
            try:
                self.client = Client(url)
                #    self.client = Client(url, headers = {'Content-Type' : 'application/soap+xml' })
            except Exception as e:
                try:
                    self.core.exception('Failure During Connect: ' + str(e))
                except Exception as ex:
                    print "Exception Handling Exception: " + str(ex)
                #self.core.logger.exception('Exception During Connect')
                return
            
            try:
                ver = self.client.service.GetProductVersion()
            except Exception as e:
                self.core.exception('Failure During GetProductVersion: ' + str(e))
                return
            
            self.core.logger.info("Connected to PI Web Services version " + ver)			

            self.connected = True        
        except:			
            return False
        return True

    def Perform(self):
        strset = self.client.factory.create('ArrayOfString')
        
        strset.string = []

        for itm in self.core.pointlist:
        	strset.string.append(self.prefix + itm.address)

        try:
            results = self.client.service.GetPISnapshotData(strset)
        except Exception as e:
            self.core.logger.info("Failed Snapshot Request : " + str(strset))
            self.core.exception("Exception In Snapshot Request : " + str(e))
            try:
                for point in core.pointlist:
                    self.core.UpdateData(point.code,"^")
            except:
                pass
            return

        indx = 0
        for res in results.TimeSeries:
            val = "0"
            if res.TimedValues is None:
                val="^"
                if res._ErrDesc is not None:
                    self.core.logger.info(str(self.core.pointlist[indx].address + ": " + str(res._ErrDesc)))
            else:
                try:
                    #self.core.logger.info("Reading Timed Value: " + str(dir(res.TimedValues[0][0])))
                    val = res.TimedValues[0][0].value
                    self.fetchset.append(indx)
                    self.core.logger.info(self.core.pointlist[indx].address + " = " + str(val))
                except Exception as e:
                    self.core.logger.error("Couldn't Read " + self.core.pointlist[indx].address + " - " + str(e))

            #self.core.logger.info("Updating " + self.core.pointlist[indx].code + " with " + str(val))
            self.core.UpdateData(self.core.pointlist[indx].code,str(val))
                
            indx = indx + 1

        strset.string = []

        for itm in self.fetchset:
        	strset.string.append(self.prefix + self.core.pointlist[itm].address)

        #print dir(strset)

        if (strset.string is None) or (len(strset.string) == 0):
            self.core.logger.error("No valid points to subscribe to!")
            time.sleep(30)
            return;

        self.core.logger.info("Subscribing To PI Web Services")
        #self.core.logger.info('Subscribing To: ' + str(strset))

        try:
            results = self.client.service.SignUpForPIUpdates(strset,10)
        except Exception as e:
            self.core.logger.info("Failed Subscribing To : " + str(strset))
            self.core.exception("Exception In Subscription : " + str(e))
            return

        if (results.Errors[0] != 0):            
            self.core.logger.info("Unable to Subscribe - PIWS Call Failed")
            try:
                self.core.logger.error("SignUpForPIUpdates Error: " + results.ErrDescs[0])
            except:
                self.core.exception("Unknown Error Type (Exception While Getting Error Info)")
                
            self.ticket = ""
            self.Disconnect()
            time.sleep(10)
            return

        self.ticket = results.UpdateTicket					
        self.iswaiting = True
        self.optimised = True

    def Disconnect(self):
        self.connected = False
        #self.client.close()

    def DebugMode(self, mode):
        
        if mode == True:
            self.core.logger.info("Enabling SOAP Debugging")
            logging.getLogger('suds.client').setLevel(logging.DEBUG)
            logging.getLogger('suds.transport').setLevel(logging.DEBUG)
           
        else:
            self.core.logger.info("Disabling SOAP Debugging")
            logging.getLogger('suds.client').setLevel(logging.WARNING)
            logging.getLogger('suds.transport').setLevel(logging.WARNING)
            
    def Poll(self):

		#guid = self.client.factory.create('ns0:guid')
		#filter = self.client.factory.create('UpdateFilterType')
		
		if (self.connected == False):
		    return
		
		if (self.optimised == False):
		    self.Optimise()
		    if (self.optimised == False):
		        return

		self.core.logger.debug("Requesting Data Updates")
		values = self.client.service.GetPIUpdates(self.ticket,60,"SnapshotAndArchive")

		if values is None:
		    self.core.logger.info("Blank Update Recieved")
		else:
		    indx = 0
		    for itm in self.fetchset:
		        try:
		            #self.core.logger.debug("Updating Value For ")
		            val = values.TimeSeriesUpdates[indx].Updates.TimedValueUpdate[0].value						
		            self.core.UpdateData(self.core.pointlist[indx].code,str(val))			
		            indx = indx + 1
                            self.core.logger.info("New Data: " + self.core.pointlist[indx].address + " = " + val)
		        except Exception as e:
		            self.core.exception("Unable to update " + self.core.pointset[itm].code + " - " + str(e))
            
if __name__ == "__main__":
    sdf = driverfactory()
    base = driverbase.ardidriver()
    base.start(sdf)