SOAPMethod.Parameter:
Sub Parameter(name as string, Assigns value as variant)
  inputParams.value(name) = value
End Sub

SOAPMethod.Constructor:
Sub Constructor()
  initialize
End Sub

SOAPMethod.ExecuteRPC:
Private Function ExecuteRPC() As SOAPResult
  dim response as string
  
  // intialize connection
  if connection = NIL then
    connection = new httpSocket
  end
  
  // set up the post data
  connection.setRequestHeader "SOAPAction",action
  connection.setPostContent formatEnvelope(),"text/xml"
  response = connection.post(url,timeout)
  
  // handle error
  if connection.errorCode() <> 0 then
    return NIL
  end
  
  // parse the response
  return parseSOAPResult(response)
End Function

SOAPMethod.ParseSOAPResult:
Private Function ParseSOAPResult(resultData as string) As SOAPResult
  dim sr as soapResult
  dim i,j as integer
  dim xnode as xmlNode
  
  // parse soap result
  sr = new soapResult
  sr.document = new xmlDocument
  sr.document.loadXML resultData
  
  // extract envelope
  for i = 0 to sr.document.childCount-1
    xnode = sr.document.child(i)
    if xnode.localName = "Envelope" then
      sr.envelope = xnode
      exit
    end
  next
  
  // provide access to the body tag without having to go through envelope
  for i = 0 to sr.envelope.childCount-1
    xnode = sr.envelope.child(i)
    if xnode.localName = "Body" then
      sr.body = xmlElement(xnode)
      exit
    end
  next
  
  // check for faults
  for i = 0 to sr.body.childCount-1
    xnode = sr.body.child(i)
    if xnode.localName = "Fault" then// fault was found
      sr.error = true
      for j = 0  to xnode.childCount-1// extract fault code and message
        if xnode.child(j).localName = "FaultCode" then
          sr.errorCode = val(xnode.child(j).firstChild.value)
        end
        if xnode.child(j).localName = "FaultString" then
          sr.errorMessage = xnode.child(j).firstChild.value
        end
      next
      exit
    end
  next
  
  
  // return the result
  return sr
  
  
exception err as XMLException
  sr.error = true
  sr.errorCode = -1
  sr.errorMessage = err.message
  return sr
End Function

SOAPMethod.Constructor:
Sub Constructor(WSDLurl as string)
  initialize
  loadWSDLFromURL WSDLurl
End Sub

SOAPMethod.LoadWSDLFromURL:
Sub LoadWSDLFromURL(url as string)
  dim pageGrab as _soapSocket
  dim response as string
  
  // use the user defined socket if one exists
  if connection = NIL then
    pageGrab = new httpSocket
  else
    pageGrab = me.connection
  end
  
  // get the wsdl
  response = pageGrab.get(url,timeout)
  if pageGrab.errorCode <> 0 then
    raise getSOAPException("WSDL could not be loaded from URL")
  end
  
  // parse the wsdl
  wsdl = new xmlDocument
  wsdl.loadXml response
End Sub

SOAPMethod.InvokeMethod:
Private Function InvokeMethod(name as string, paramIsArray as boolean) As string
  dim sr as soapResult
  dim resultNode as xmlNode
  
  // parse wsdl if found
  if wsdl <> NIL then
    parseWSDL name,paramIsArray
  else// call function with no wsdl
    methodName = name
  end
  
  // execute the function
  sr = executeRPC()
  if sr = NIL then
    return ""
  end
  
  // find the result node
  resultNode = sr.body.firstChild.firstChild.firstChild
  if resultNode = NIL then
    resultNode = sr.body.firstChild.firstChild
    return resultNode.value
  end
  
  // return the result
  if resultNode.type = 3 then
    return resultNode.value
  else
    return resultNode.toString()
  end if
End Function

SOAPMethod.Operator_Lookup:
Function Operator_Lookup(funcName as string, ParamArray params as variant) As string
  dim i as integer
  
  if ubound(params) = -1 then// there are no parameters
    if wsdl <> NIL then// clear parameters if there is a wsdl defined
      inputParams.clear
    end
  else// parameters exist
    inputParams.clear// clear stale parameters
    for i = 0 to ubound(params)// assign new parameters
      inputParams.value(str(i)) = params(i)
    next
  end
  
  return invokeMethod(funcName,true)
End Function

SOAPMethod.wsdlFindParamNodesParent:
Private Function wsdlFindParamNodesParent(funcName as string) As xmlNode
  dim rlist as xmlNodeList
  dim inputMessage as string
  dim inputmessageNode, sequenceNode as xmlNode
  
  // first find the port input name
  rlist = wsdlQuery("definitions/portType/operation[@name='" + funcName + "']/input")
  inputMessage = xmlElement(rlist.Item(0)).GetAttribute("message")
  inputMessage = nthField(inputMessage, ":", 2)
  
  rlist = wsdlQuery("definitions/message[@name='" + inputMessage + "']")
  inputMessageNode = rlist.Item(0)
  
  if inputMessageNode.childCount = 0 then
    return NIL
  end
  
  // some wsdl services will go ahead and have our param details here
  if inputMessageNode.childCount >= 1 AND xmlElement(inputMessageNode.firstChild).getAttribute("type") <> "" then
    return inputMessageNode
  end
  
  // if there is only one <part> tag and it has an "element" attribute, then we have to find our params
  // in the <types> node
  if inputMessageNode.childCount = 1 AND xmlElement(inputMessageNode.firstChild).getAttribute("element") <> "" then
    rlist = wsdlQuery("definitions/types/schema/element[@name='" + funcName + "']/complexType/sequence")
    sequenceNode = rlist.Item(0)
    return sequenceNode
  end
  
  return NIL
End Function

SOAPMethod.wsdlFunctionExists:
Private Function wsdlFunctionExists(funcName as string) As string
  dim rlist as xmlNodeList
  dim i as integer
  
  rlist = wsdlQuery("definitions/binding/operation[@name]")
  for i = 0 to rlist.length-1
    if xmlElement(rlist.item(i)).getAttribute("name") = funcName then
      return xmlElement(rlist.item(i)).getAttribute("name")
    end
  next
  
  return ""
End Function

SOAPMethod.wsdlGetAction:
Private Function wsdlGetAction(funcName as string) As string
  dim rlist as xmlNodeList
  dim action as string
  
  rlist = wsdlQuery("definitions/binding/operation[@name='" + funcName + "']/operation")
  action = xmlElement(rlist.item(0)).getAttribute("soapAction")
  
  return action
End Function

SOAPMethod.wsdlGetAddress:
Private Function wsdlGetAddress() As string
  dim rlist as xmlNodeList
  dim tmpNode as xmlNode
  dim address as string
  
  // lets get the real url of the service
  rlist = wsdlQuery("definitions/service/port/address")
  address = xmlElement(rlist.Item(0)).getAttribute("location")
  
  return address
End Function

SOAPMethod.wsdlGetMethodNS:
Private Function wsdlGetMethodNS(funcName as string) As string
  dim rlist as xmlNodeList
  dim ns as string
  
  rlist = wsdlQuery("definitions/binding/operation[@name='" + funcName + "']/input/body")
  ns = xmlElement(rlist.item(0)).getAttribute("namespace")
  
  if ns = "" then
    ns = wsdl.documentElement.getAttribute("targetNamespace")
  end
  
  return ns
End Function

SOAPMethod.Initialize:
Private Sub Initialize()
  inputParams = new dictionary
  
  namespaces = new dictionary
  namespaces.value("SOAP") = "http://schemas.xmlsoap.org/soap/envelope/"
  namespaces.value("xsd") = "http://www.w3.org/2001/XMLSchema"
  namespaces.value("xsi") = "http://www.w3.org/2001/XMLSchema-instance"
  namespaces.value("ENC") = "http://schemas.xmlsoap.org/soap/encoding/"
  namespaces.value("si") = "http://soapinterop.org/xsd"
  
  paramTypes = new dictionary
  paramTypes.value("0") = ""// nil
  paramTypes.value("2") = "int"// integer
  paramTypes.value("5") = "double"// double
  paramTypes.value("7") = "string"// date
  paramTypes.value("8") = "string"// string
  paramTypes.value("9") = ""// object
  paramTypes.value("11") = "boolean"// boolean
  paramTypes.value("16") = "string"// color
End Sub

SOAPMethod.Invoke:
Function Invoke(name as string) As SOAPResult
  // record the method name
  methodName = name
  
  // if a wsdl exists then use its definition of the method
  if wsdl <> NIL then
    parseWSDL name,false
  end
  
  // return result
  return executeRPC()
End Function

SOAPMethod.ParseWSDL:
Private Sub ParseWSDL(name as string, paramIsArray as boolean)
  dim paramParent as xmlNode
  dim i as integer
  
  // set method name
  methodName = wsdlFunctionExists(name)
  
  // does the function exist
  if methodName = "" then
    raise getSOAPException("Method name does not exist in WSDL")
  end
  
  // extract method properties from wsdl
  url = wsdlGetAddress()
  action = wsdlGetAction(methodName)
  methodNamespace = wsdlGetMethodNS(methodName)
  paramParent = wsdlFindParamNodesParent(methodName)
  
  // validate parameter count
  if paramParent = NIL then// no parameters found
    if inputParams.count > 0 then// parameters were passed in
      raise getSOAPException("Incorrect parameters")
    end
    return// no parameters so we are done
  end
  if paramParent.childCount <> inputParams.count then// compare input params with needed params
    raise getSOAPException("Incorrect parameters")
  end
  
  // set up parameters
  for i = 0 to paramParent.childCount-1
    if paramIsArray = true then// change array index to name
      inputParams.value(xmlElement(paramParent.child(i)).getAttribute("name")) = inputParams.value(str(i))
      inputParams.remove str(i)
    else// verify parameter names
      if inputParams.hasKey(xmlElement(paramParent.child(i)).getAttribute("name")) = false then
        raise getSOAPException("Incorrect parameters")
      end
    end
  next
End Sub

SOAPMethod.GetSOAPException:
Private Function GetSOAPException(message as string) As SOAPException
  dim err as SOAPException
  
  err = new SOAPException
  err.message = message
  
  return err
End Function

SOAPMethod.FormatEnvelope:
Private Function FormatEnvelope() As string
  dim env as xmlDocument
  dim xbody,xdef as xmlNode
  dim i as integer
  
  // create document
  env = new xmlDocument
  
  // setup envelope and namespaces
  env.appendChild env.createElement(namespaces.value("SOAP"),"SOAP:Envelope")
  for i = 0 to namespaces.count-1
    env.documentElement.setAttribute "xmlns:"+namespaces.key(i),namespaces.value(namespaces.key(i))
  next
  
  // create body
  xbody = env.createElement(namespaces.value("SOAP"),"SOAP:Body")
  env.documentElement.appendChild xbody
  
  // create method
  xdef = env.createElement(methodNameSpace,methodName)
  xbody.appendChild xdef
  
  // set parameters
  for i = 0 to inputParams.count-1
    xdef.appendChild getParameterNode(env,i)
  next
  
  // return envelope string
  return env.toString()
End Function

SOAPMethod.GetParameterNode:
Private Function GetParameterNode(env as xmlDocument, idx as integer) As xmlNode
  dim xnode as xmlElement
  dim pname,ptype,pval as string
  
  // extract parameter name and type
  pname = inputParams.key(idx)
  ptype = "xsd:"+ paramTypes.value(str(inputParams.value(pname).type))
  
  // format parameter types
  select case inputParams.value(pname).type
  case 11// boolean
    if inputParams.value(pname).booleanValue = true then
      pval = "1"
    else
      pval = "0"
    end
    
  case 9// object
    if inputParams.value(pname).objectValue isa XMLNode then
      xnode = xmlElement(inputParams.value(pname).objectValue)
    end
    
  else
    pval = inputParams.value(pname).stringValue
  end
  
  // create node from parameter data if parameter value wasn't already a node
  if xnode = NIL then
    xnode = env.createElement(pname)
    xnode.setAttribute namespaces.value("xsi"),"xsi:type",ptype
    xnode.appendChild env.createTextNode(pval)
  end
  
  // return parameter node
  return xnode
End Function

SOAPMethod.UseSocket:
Sub UseSocket(SOAPsocket as _SOAPSocket)
  me.connection = soapSocket
End Sub

SOAPMethod.ClearParameters:
Sub ClearParameters()
  inputParams.clear
End Sub

SOAPMethod.wsdlQuery:
Private Function wsdlQuery(query as string) As xmlNodeList
  dim i,x as integer
  dim output,qstr,tmp,attr as string
  
  // Format the XQL query to support namespaces.  We these queries after the fact
  // in order to keep them more human readable in code for debugging.
  for i = 1 to countFields(query,"/")
    tmp = nthField(query,"/",i)
    
    x = instr(tmp,"[")
    if x > 0 then
      attr = mid(tmp,x)
      tmp = nthField(tmp,"[",1)
    end
    
    qstr = "*[local-name()='"+ tmp +"']"
    if x > 0 then
      qstr = qstr + attr
    end
    
    output = output +"/"+ qstr
  next
  output = mid(output,2)
  
  // run the query
  return wsdl.xql(output)
End Function

MainWindow.DLSocket.DownloadComplete:
Sub DownloadComplete(url as string, httpStatus as integer, headers as internetHeaders, file as folderItem)
  DLButton.enabled=true
  SuccessWindow.show
End Sub

MainWindow.DLSocket.Error:
Sub Error(code as integer)
  ErrorWindow.show
End Sub

MainWindow.PushButton1.Action:
Sub Action()
  AboutWindow.show
End Sub

MainWindow.StupidButton.Action:
Sub Action()
  
  dim f as folderItem
  dim savedName as string
  dim actualURL as string
  
  actualURL = "http://old.jojo2k.com/finalweather.txt"
  
  savedName = "SnazzyWeatherData.txt"
  f = getSaveFolderItem("any",savedName)
  if f = NIL then
    return
  end
  
  DLSocket.get(actualURL,f)
End Sub

MainWindow.FullReportButton.Action:
Sub Action()
  ConditionsWindow.show
End Sub

MainWindow.DLButton.Action:
Sub Action()
  dim f as folderItem
  dim t as TextInputStream
  dim savedName as string
  dim localFullReport as string
  
  savedName = "SnazzyWeatherData.txt"
  
  f = GetFolderItem(savedName)
  
  if f <> NIL then
    t=f.OpenAsTextFile
    D1HighDisplay.text = t.Readline
    WindValue.text = t.Readline
    WindDirectionValue.text = t.Readline
    ConditionsValue.text = t.Readline
    D1LowDisplay.text = t.Readline
    D2HighDisplay.text = t.Readline
    D2LowDisplay.text = t.Readline
    localFullReport = t.Readline
    t.Close
    
  End if
  
End Sub

ErrorWindow.ErrorOKBtn.Action:
Sub Action()
  ErrorWindow.close
End Sub

AboutWindow.PushButton3.Action:
Sub Action()
  AboutWindow.close
End Sub

SuccessWindow.PushButton1.Action:
Sub Action()
  SuccessWindow.close
End Sub

ConditionsWindow.FullConditionsText.Open:
Sub Open()
  dim f as folderItem
  dim t as TextInputStream
  dim savedName as string
  dim localFullReport as string
  dim b2,b3,b4,b5,b6,b7,b8 as string
  
  savedName = "SnazzyWeatherData.txt"
  
  f = GetFolderItem(savedName)
  
  if f <> NIL then
    t=f.OpenAsTextFile
    b2 = t.Readline
    b3 = t.Readline
    b4 = t.Readline
    b5 = t.Readline
    b6 = t.Readline
    b7 = t.Readline
    b8 = t.Readline
    FullConditionsText.text = t.Readline
    t.Close
    
  End if
  
End Sub

ConditionsWindow.ConditionsCloseButton.Action:
Sub Action()
  ConditionsWindow.close
End Sub

