' Gambas module file

Public Sub ExitNode(Xml As XmlReader)

  Do While True

    If Xml.Eof Then Return
    Xml.Read()
    If Xml.Node.Type = XmlReaderNodeType.Element Then ExitNode(Xml)
    If Xml.Node.Type = XmlReaderNodetype.EndElement Then Return


  Loop

End


Public Function Find(Xml As XmlReader, Node As String) As Boolean

  Do While True

    If Xml.Eof Then Return False

    If Xml.Node.Type = XmlReaderNodeType.Element Then

      If Xml.Node.Name = Node Then Return True
      ExitNode(Xml)

    End If

    If Not Xml.Eof Then Xml.Read()

  Loop

End

Public Function FindText(Xml As XmlReader) As Boolean

  Do While True

      Xml.Read()
      If Xml.Node.Type = XmlReaderNodeType.Text Then Return True
      If Xml.Node.Type = XmlReaderNodeType.EndElement Then Return False
      If Xml.Node.Type = XmlReaderNodeType.Element Then Return False

  Loop

End


Public Function GetParam(Xml As XmlReader) As RpcAtom

  Dim hAtom As New RpcAtom
  Dim Name As String
  Dim hDate As Date
  Dim sDate As String
  Dim bAtom As RpcAtom

  If Not (Xml.Node.Type = XmlReaderNodetype.Element And Xml.Node.Name = "value") Then
    Try Xml.Read()
  End If

  If Not Find(Xml, "value") Then Return Null

  Do While True
    Try Xml.Read()
    If Xml.Node.Type = XmlReaderNodeType.EndElement Then
      hAtom.Data = ""
      hAtom.Type = XmlRpc.xString
      Return hAtom
    End If
    If Xml.Node.Type = XmlReaderNodeType.Text Then
      hAtom.Data = Xml.Node.Value
      hAtom.Type = XmlRpc.xString
      ExitNode(Xml)
      Return hAtom
    End If
    If Xml.Node.Type = XmlReaderNodeType.Element Then Break
  Loop

  Select Case Xml.Node.Name

    Case "i4"
      hAtom.Type = XmlRpc.xInteger
      If Not FindText(Xml) Then Return Null
      Try hAtom.Data = CInt(Xml.Node.Value)
      If Error Then Return Null

    Case "int"
      hAtom.Type = XmlRpc.xInteger
      If Not FindText(Xml) Then Return Null
      Try hAtom.Data = CInt(Xml.Node.Value)
      If Error Then Return Null

    Case "double"
      hAtom.Type = XmlRpc.xDouble
      If Not FindText(Xml) Then Return Null
      Try hAtom.Data = CFloat(Xml.Node.Value)
      If Error Then Return Null

    Case "boolean"
      hAtom.Type = XmlRpc.xBoolean
      If Not FindText(Xml) Then Return Null
      If Trim(Xml.Node.Value) = "0" Then
        hAtom.Data = False
      Else If Trim(Xml.Node.Value) = "1" Then
        hAtom.Data = True
      Else
        Return Null
      End If

    Case "string"
      hAtom.Type = XmlRpc.xString
      If Not FindText(Xml) Then
        hAtom.Data = ""
      Else
        hAtom.Data = Xml.Node.Value
      End If

    Case "base64"
      hAtom.Type = XmlRpc.xBase64
      If Not FindText(Xml) Then Return Null
      Try hAtom.Data = XmlReader.Decode(Xml.Node.Value, "base64")
      If Error Then Return Null

    Case "dateTime.iso8601"
      hAtom.Type = XmlRpc.xDate
      If Not FindText(Xml) Then Return Null
      sDate = Trim(Xml.Node.Value)
      If Len(sDate) = 8 Then
        Try hDate = Date(Left(sDate, 4), Mid(sDate, 5, 2), Mid(sDate, 7, 2))
        If Error Then Return Null
        hAtom.Data = hDate
      Else If Len(sDate) = 17 Then
        Try hDate = Date(Left(sDate, 4), Mid(sDate, 5, 2), Mid(sDate, 7, 2), Mid(sDate, 10, 2), Mid(sDate, 13, 2), Mid(sDate, 16, 2))
        If Error Then Return Null
        hAtom.Data = hDate
      Else
        Return Null
      End If

    Case "array"
      hAtom.Type = XmlRpc.xArray
      hAtom.Data = New RpcArray
      Do While True

        Xml.Read()
        If Xml.Node.Type = XmlReaderNodeType.Element Then

          If Xml.Node.Name <> "data" Then Return Null
          Do While True
            Xml.Read()
            If Xml.Node.Type = XmlReaderNodeType.Element Then
              If Xml.Node.Name <> "value" Then Return Null
              bAtom = Tools.GetParam(Xml)
              If bAtom = Null Then Return Null
              hAtom.Data.Add(bAtom.Data, bAtom.Type)
            End If

            If Xml.Node.Type = XmlReaderNodeType.EndElement Then

              'If Xml.Node.Name = "data" Then
              If Xml.Eof Then
                ExitNode(Xml)
                Xml.Read()
                Return hAtom
              End If

            End If
          Loop
        End If

        If Xml.Node.Type = XmlReaderNodeType.EndElement Then
          ExitNode(Xml)
          Xml.Read()
          Return hAtom
        End If

      Loop

    Case "struct"
      hAtom.Type = XmlRpc.xStruct
      hAtom.Data = New RpcStruct
      Do While True
        Xml.Read()
        If Xml.Node.Type = XmlReaderNodeType.Element Then

          If Xml.Node.Name <> "member" Then Return Null
          bAtom = Null
          Name = ""
          Do While True
            Xml.Read()
            If Xml.Node.Type = XmlReaderNodeType.EndElement Then
              If bAtom = Null Or Name = "" Then Return Null
              hAtom.Data.Add(Name, bAtom.Data, bAtom.Type)
              Break
            End If
            If Xml.Node.Type = XmlReaderNodeType.Element Then
              Select Case Xml.Node.Name
                Case "name"
                  If Not FindText(Xml) Then Return Null
                  Name = Xml.Node.Value
                  ExitNode(Xml)
                Case "value"
                  bAtom = GetParam(Xml)
                  If Not bAtom Then Return Null
                Default
                  Return Null
              End Select
            End If
          Loop

        End If

        If Xml.Node.Type = XmlReaderNodetype.EndElement Then

          If Xml.Node.Name = "struct" Then
            ExitNode(Xml)
            Xml.Read()
            Return hAtom
          End If

        End If

      Loop

    Default
      Return Null
  End Select

  ExitNode(Xml)
  Return hAtom

End

Public Function AddValue(Xml As XmlWriter, Data As Variant, Type As Integer) As Boolean

  Dim xBool As Boolean
  Dim xBase64 As String
  Dim xDate As Date
  Dim xArr As RpcArray
  Dim xStr As RpcStruct
  Dim Bucle As Integer

  Xml.StartElement("value")
  Select Case Type
    Case XmlRpc.xInteger
      Try Xml.Element("int", CInt(Data))
      If Error Then Return False

    Case XmlRpc.xBoolean
      Try xBool = CBool(Data)
      If Error Then Return False
      If xBool Then
        Xml.Element("boolean", "1")
      Else
        Xml.Element("boolean", "0")
      End If

    Case XmlRpc.xDouble
      Try Xml.Element("double", CFloat(Data))
      If Error Then Return False

    Case Xmlrpc.xString
      Try Xml.Element("string", CStr(Data))
      If Error Then Return False

    Case XmlRpc.xBase64
      Try xBase64 = CStr(Data)
      If Error Then Return False
      Xml.StartElement("base64")
      Try Xml.Base64(xBase64)
      If Error Then Return False
      Xml.EndElement()

    Case XmlRpc.xDate
      Try xDate = CDate(Data)
      If Error Then Return False
      Xml.Element("dateTime.iso8601", Format(xDate, "yyyymmdd") & "T" & Format(xDate, "hh:nn:ss"))

    Case XmlRpc.xArray
      Try xArr = Data
      If Error Then Return False
      Xml.StartElement("array")
      Xml.StartElement("data")
      For Bucle = 0 To xArr.Count - 1
        If Not AddValue(Xml, xArr[Bucle], xArr.Datatype(Bucle)) Then Return False
      Next
      Xml.EndElement()
      Xml.EndElement()

    Case XmlRpc.xStruct
      Try xStr = Data
      If Error Then Return False
      Xml.StartElement("struct")
      For Bucle = 0 To xStr.Count - 1
        Xml.StartElement("member")
        Xml.Element("name", xStr.Key(Bucle))
        If Not AddValue(Xml, xStr.Value(Bucle), xStr.Datatype(Bucle)) Then Return False
        Xml.EndElement()
      Next
      Xml.EndElement()

  End Select
  Xml.EndElement()
  Return True

End



Public Function FaultReply(Code As Integer, Reason As String) As String

  Dim Xml As New XmlWriter

  Xml.Open("", True)
  Xml.StartElement("methodResponse")
  Xml.StartElement("fault")
  Xml.StartElement("value")
  Xml.StartElement("struct")

  Xml.StartElement("member")
  Xml.Element("name", "faultCode")
  Xml.StartElement("value")
  Xml.Element("int", Code)
  Xml.EndElement()
  Xml.EndElement()

  Xml.StartElement("member")
  Xml.Element("name", "faultString")
  Xml.StartElement("value")
  Xml.Element("string", Reason)

  Return Xml.EndDocument()


End

