#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
This program get params to send data to webservice
Need:
 -f file nam to define the file with config params and data
 -e file name used for error
 -m send_mode Manual/Json if not provided send_mode=Json (Manual need XML element into JSON, Json need Body Element whit data serialized)")

When program is called with Json mode, into the param file the element "Body" is needed at the same level as "Parametri".
Body element contain data to send to webservice stored as Json format.

When program is called with Manual mode, into the param file the element "XMLBODYFileName" element is needed into "Parametri" section.
"XMLBODYFileName" element contain file name with data to send to webservice stored as XML format, this data is sent as it is to the web service as Body data of the XML document.

Information for secuirty are taken from "Header" section of the param file and added to the XML sent to the web service.

This program prompt to the standard output information about error or debug purpouse.

When program found an error that is able to manage the message is writed into the file specified into args.
At the end of the execution the response of the webservice is writed into the file specified into Parametri section of param file

Prams are:
-f / --file_name             dest="file_name"             type="string"     set file name to process [REQUIRED]
-e / --error_file_name       dest="error_file_name"       type="string"     set file name to process [REQUIRED]"
-m / --send_mode             dest="send_mode"             type="string"     set send mode: Manual/Json
"""

from pysimplesoap.client import SoapClient
import re, sys, os, datetime, time
import json
import yaml
from pysimplesoap.simplexml import SimpleXMLElement

if not hasattr(datetime.datetime,'strptime'):  #added for Python < 2.5
    def strptime(date_string,format):
        return datetime.datetime(*(time.strptime(date_string, format)[0:6]))
else:
    strptime = datetime.datetime.strptime

def logmsg(msg,options):
    if ( options.verbose ):
        print msg

if __name__ == "__main__":
    TIMEOUT=500
    from optparse import OptionParser
    usage = "usage: %prog [options] argument"
    parser = OptionParser(usage=usage)
    parser.set_defaults(mode="query")
    parser.add_option("-f", "--file_name", dest="file_name", action="store", type="string",
                      help="set file name to process [REQUIRED]")
    parser.add_option("-e", "--error_file_name", dest="error_file_name", action="store", type="string",
                      help="set file name to process [REQUIRED]")
    parser.add_option("-m", "--send_mode", dest="send_mode", action="store", type="string",
                      help="set send mode Manual/Json if not provided send_mode=Json (Manual need XML element into JSON, Json need Body Element whit data serialized)")
#     parser.add_option("-t", "--test", dest="test", action="store_true", default=False,
#                       help="use the test environment web site")
    parser.add_option("-v", "--verbose", dest="verbose", action="count", default=0,
                      help="debug conversation")
    (options, args) = parser.parse_args()
    if not options.file_name or not options.error_file_name:
        parser.error("-f file_name  is required; try -h")
    if not options.file_name or not options.error_file_name:
        parser.error("-e error_file_name  is required; try -h")
    if not options.send_mode:
        options.send_mode = "Json"
#         parser.error("-m send_mode  is required; try -h")
    def errlog(msg):
        print >>sys.stderr,"%s - %s" % (datetime.datetime.now().ctime(), msg)
    
    #wsdlFileTestAsync = 'https://cooptest.sian.it/wsTOAST/services/wsRegVinoAsync?wsdl'
    #wsdlFile = 'https://cooptest.sian.it/wsTOAST/services/wsRegVino?wsdl'
    #wsdl=wsdlFileTestAsync
    file_error = options.error_file_name
    parametri_av2000 = ""
    wsdl = ""
    fileoutput = ""
    authHeader = ""
    data_header = ""
    data_body = ""
    username = ""
    password = ""
    nomeServizio = ""
    XML = ""
    headers = None

    datajson={}
    try:
        with open(options.file_name) as data_file:
            try:
                #datajson = json.load(data_file.read())
                datastring = data_file.read()
                datajson = yaml.safe_load(datastring)
            except Exception as e:
                errlog("ERRORE: File json di input mal formato. Errore nella conversione dei dati del file ison di input in json.")
                logmsg(e,options)
                errlog(e)
                dict_error = {"error message":str(e)}
                #Scrittura su file dei dati ritornati dalla chiamata del metodo richiesto sul webservice
                with open(file_error, 'w') as f:
                    json.dump(dict_error, f)
                sys.exit(5)
    except Exception as e:
        errlog("ERRORE: Apertura file non riuscita")
        logmsg(e,options)
        errlog(e)
        
        #Scrittura su file dei dati ritornati dalla chiamata del metodo richiesto sul webservice
        with open(file_error, 'w') as f:
            json.dump(dict_error, f)
        sys.exit(5)
    logmsg(datajson,options)
    
    try:
        #Parametri da av2000
        parametri_av2000 = datajson['Parametri']
        wsdl=parametri_av2000['wsdl']
        location = ''
        try:
            location = wsdl.split('?')[0]
        except Exception as e:
            errlog("ERRORE: WSDL FOrnito errato")
            logmsg(e,options)
            errlog(e)
            dict_error = {"error message":str(e)}
            with open(file_error, 'w') as f:
                json.dump(dict_error, f)
            sys.exit(5)
        fileoutput=parametri_av2000['EsitoFileName']
        authHeader=parametri_av2000['authHeader']
        #Dati per composizione xml (Header,Body)
        data_header = datajson['Header']
        username = data_header['username']
        password = data_header['password']
        nomeServizio = data_header['nomeServizio']
        
        if ( options.send_mode == "Json"):
            data_body = datajson['Body']
            dict_data = data_body
        else:
            XMLBODYFileName=parametri_av2000['XMLBODYFileName']
            try:
                with open(XMLBODYFileName) as data_file:
                    try:
                        XML = data_file.read()
                    except Exception as e:
                        errlog("ERRORE: XMLBODYFileName di input mal formato. Errore nella lettura di: "+XMLBODYFileName)
                        logmsg(e,options)
                        errlog(e)
                        dict_error = {"error message":str(e)}
                        #Scrittura su file dei dati ritornati dalla chiamata del metodo richiesto sul webservice
                        with open(file_error, 'w') as f:
                            json.dump(dict_error, f)
                        sys.exit(5)
            except Exception as e:
                errlog("ERRORE: Apertura file "+XMLBODYFileName+" non riuscita")
                logmsg(e,options)
                errlog(e)
                dict_error = {"error message":str(e)}
                #Scrittura su file dei dati ritornati dalla chiamata del metodo richiesto sul webservice
                with open(file_error, 'w') as f:
                    json.dump(dict_error, f)
                sys.exit(5)
    except Exception as e:
        errlog("ERRORE: ERRORE nella lettura del file json")
        logmsg(e,options)
        errlog(e)
        dict_error = {"error message":str(e)}
        #Scrittura su file dei dati ritornati dalla chiamata del metodo richiesto sul webservice
        with open(file_error, 'w') as f:
            json.dump(dict_error, f)
        sys.exit(1)
    client = None
    try:
    	wsdlurl = ''
    	wsdlurlsplit = wsdl.split('/')
    	wsdlurl = wsdlurlsplit[2]
        logmsg("Url: "+wsdlurl,options)
    	wsdlurl = "http://"+wsdlurl+"/schema/wsmrgc/" #Precedentemente era impostato a wsmrgc probabilmente per il registro degli zuccheri
        #wsdlurl = "http://cooperazione.sian.it/schema/wsmrga/"
    	logmsg("Url: "+wsdlurl,options)
        if ( options.send_mode == "Json"):
            client = SoapClient(wsdl=wsdl, timeout=TIMEOUT)
        else:
            client = SoapClient(
                location = location,
#                 namespace = wsdlurl,
                soap_ns='soap', trace = True, ns = False, timeout=TIMEOUT) #namespace = wsdlurl,
    except Exception as e:
        errlog("ERRORE: ERRORE nella creazione del client per il webservice")
        logmsg(e,options)
        errlog(e)
        dict_error = {"error message":str(e)}
        #Scrittura su file dei dati ritornati dalla chiamata del metodo richiesto sul webservice
        with open(file_error, 'w') as f:
            json.dump(dict_error, f)
        sys.exit(2)
    
    if ( options.send_mode == "Json"):
        client[authHeader]={            
          'username'                :username,
          'password'                :password,
          'nomeServizio'            :nomeServizio
        }
    else:
        headers = SimpleXMLElement("<Header/>")
        my_test_header = headers.add_child(authHeader)
        my_test_header.marshall('username', username)
        my_test_header.marshall('password', password)
        my_test_header.marshall('nomeServizio', nomeServizio)
    
    
    
    def func_not_found(): # just in case we dont have the function
        logmsg("No Function called found",options)
    
    e = None
    response = None
    error_on_webservice = False
    writemode = 'wb'
    try:
        if ( options.send_mode == "Json"):
            if nomeServizio == 'SoggSiRSoZ':
                operation = client.get_operation(nomeServizio)
                input = operation['input']
                input['SoggSiRSoZInput']['TipoRichiesta']=str
                Soggetto = input['SoggSiRSoZInput']['Soggetto']
                Soggetto[0]['TipoSoggetto']=str
        
        if ( options.send_mode == "Json"):
            method = getattr(client,nomeServizio,func_not_found)
            response = method(dict_data)
        else:
            params = SimpleXMLElement(XML)
            response = client.call(nomeServizio,params,headers=headers)
        
        logmsg(str(client.xml_request),options)
        logmsg(str(client.xml_response),options)
        logmsg(str(response),options)
    except Exception as e:
        errlog("ERRORE: ERRORE nella chiamata del metodo del webservice")
        logmsg(e,options)
        errlog(e)
        dict_error = {"error message":str(e)}
        #Scrittura su file dei dati ritornati dalla chiamata del metodo richiesto sul webservice
        with open(file_error, 'w') as f:
            json.dump(dict_error, f)
        if hasattr(e, 'faultstring') and hasattr(e, 'faultcode'):
            faultstring = e.faultstring
            faultstring_code = "0"
            if faultstring and faultstring.index("-")!=-1:
                faultstring_code = faultstring.split("-")[0]
            if e.faultcode and e.faultcode=="env:Client" and faultstring_code=="015":
                #Errore di autenticazione
                sys.exit(3)
            else:
                #Altri errori
                sys.exit(4)
        else:
            error_on_webservice = True
            #Dato il tipo di errore accodo al messaggio già registrato anche la response ottenuta dal webservice
            #per farlo reimposto la modalità di scrittura del file ed il nome del file di output con il file error
            fileoutput = file_error
            writemode = 'ab+'
    
    #Scrittura su file dei dati ritornati dalla chiamata del metodo richiesto sul webservice
    with open(fileoutput, writemode) as f:
        #f.write(client.xml_response)
        data_text = client.xml_response
        #Inizo l'elaborazioine della response in modo da posizionare ad ogni riga un valore singolo dell'xml senza spazi all'inizio ed alla fine
        #In modo da avere per ogni riga una chiava o un valore
        data_split = data_text.split('>')
        data_split_end = []
        for idx, val in enumerate(data_split):
            logmsg(str(idx)+"; "+str(val),options)
            if val:
                data_split[idx] = val+">"
                tag_end_position = data_split[idx].find("</")
                if tag_end_position>-1:
                    if tag_end_position>0:
                        #è all'interno di una stringa quindi contiene prima un valore e poi una tag di chiusura
                        data_fixed = data_split[idx].split("</")
                        for ide, elem in enumerate(data_fixed):
                            if ide > 0:
                                data_fixed[ide] = "</"+data_fixed[ide]
                            data_fixed[ide] = data_fixed[ide].strip()
                            if data_fixed[ide]:
                                if data_fixed[ide].find('\n')>-1:
                                    data_fixed[ide] = data_fixed[ide].replace("\n", " ")
                                data_split_end.append(data_fixed[ide])
                    else:
                        #è ad inizio stringa rappresenta la chiusura di una tag
                        data_split[idx] = data_split[idx].strip()
                        if data_split[idx]:
                            if data_split[idx].find('\n')>-1:
                                data_split[idx] = data_split[idx].replace("\n", " ")
                            data_split_end.append(data_split[idx])
                else:
                    #non ho rilevato il tag di chiusura elemento
                    data_split[idx] = data_split[idx].strip()
                    if data_split[idx]:
                        if data_split[idx].find('\n')>-1:
                            data_split[idx] = data_split[idx].replace("\n", " ")
                        data_split_end.append(data_split[idx])
        for idx, val in enumerate(data_split_end):
            val = val.strip()
            if val:
                end_line = "\n"
                if idx == len(data_split_end)-1:
                    end_line = ""
                f.writelines(val+end_line)
    
    if error_on_webservice:
        #Altri errori
        sys.exit(4)
    else:
        sys.exit(0)
