Option Explicit
'the URL to perform the request to
Public url As String
'the response xml
Public xml As String
'performs a REST lookup to Bing location service and parses the XML
Public Function performLookup(location As String)
    Dim data(2) As String
    
    url = ("http://dev.virtualearth.net/REST/v1/Locations?query=" & URLEncode(location, True) & "&maxResults=1&key=" & Trim(CStr(Range("bingMapsKey"))) & "&o=xml")
    
    'perform an HTTP GET
    xml = HTTPGET(url)
        
    'parse the XML to get the lat/long/confidence, note for Bing, this is only "high" / "medium" / "low" vs. numerical precision indicators like Yahoo or Google
    If (InStr(xml, "<Latitude>") <> 0 And InStr(xml, "<Longitude>") <> 0 And InStr(xml, "<Confidence>") <> 0) Then
        data(0) = getElementValue("Latitude")
        data(1) = getElementValue("Longitude")
        data(2) = getElementValue("Confidence")
    Else
        data(0) = "-"
        data(1) = "-"
        data(2) = "-"
    End If
    
    performLookup = Join(data, "|")
    
End Function
'return the request URI
Public Function getRequestURI()
    getRequestURI = url
End Function
'return the response XML
Public Function getResponseXML()
    getResponseXML = xml
End Function
'wrapper for the REST request to check proxy/OS
Public Function HTTPGET(url As String) As String
    Dim useProxy As Boolean
    
    If Range("UseProxy") = "Yes" Then
        useProxy = True
    Else
        useProxy = False
    End If
    If (isWindows()) Then
        HTTPGET = windowsHTTPGET(url, useProxy)
    Else
        HTTPGET = macHTTPGET(url, useProxy)
        
    End If
End Function
'perform the REST request on windows
Private Function windowsHTTPGET(url As String, useProxy As Boolean) As String
    Dim http As Object
    
    'create http object
    Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
    
    'proxy HTTP - [url]http://forums.aspfree.com/visual-basic-programming-38/proxy-auth-in-this-vb-script-20625.html[/url]
    If useProxy Then
        ' Set to use proxy - [url]http://msdn.microsoft.com/en-us/library/aa384059%28v=VS.85%29.aspx[/url]
        Const HTTPREQUEST_SETCREDENTIALS_FOR_PROXY = 1
        Const HTTPREQUEST_PROXYSETTING_PROXY = 2
        Const AutoLogonPolicy_Always = 0
        
        http.SetProxy HTTPREQUEST_PROXYSETTING_PROXY, [ProxyIP], "*.intra"
        http.Open "GET", url, False
        http.SetAutoLogonPolicy AutoLogonPolicy_Always
    
    Else
        http.Open "GET", url
    End If
       
    'send the request
    http.send
        
    'get response data as a string
    windowsHTTPGET = http.responseText
End Function
'perform the REST request on mac
Private Function macHTTPGET(url As String, useProxy As Boolean) As String
    Dim script As String
    
    
    'build the shell script, starts with `curl '<url>' --silent`
    If useProxy Then
        script = "do shell script " & Chr(34) & "curl '" & url & "'" & " --silent --proxy " & Range("proxyIP") & Chr(34)
    Else
        script = "do shell script " & Chr(34) & "curl '" & url & "'" & " --silent" & Chr(34)
    End If
    
    'run the shell script
    macHTTPGET = MacScript(script)
    
End Function
'URL encode a string
'From [url]http://stackoverflow.com/questions/218181/how-can-i-url-encode-a-string-in-excel-vba[/url]
Private Function URLEncode( _
   StringVal As String, _
   Optional SpaceAsPlus As Boolean = False _
) As String
On Error GoTo Catch
  Dim StringLen As Long: StringLen = Len(StringVal)
  If StringLen > 0 Then
    ReDim result(StringLen) As String
    Dim i As Long, CharCode As Integer
    Dim Char As String, Space As String
    If SpaceAsPlus Then Space = "+" Else Space = "%20"
    
    For i = 1 To StringLen
      Char = Mid(StringVal, i, 1)
      CharCode = Asc(Char)
      Select Case CharCode
        Case 97 To 122, 65 To 90, 48 To 57, 45, 46, 95, 126
          result(i) = Char
        Case 32
          result(i) = Space
        Case 0 To 15
          result(i) = "%0" & Hex(CharCode)
        Case Else
          result(i) = "%" & Hex(CharCode)
      End Select
    Next i
    URLEncode = Join(result, "")
  End If
Finally:
Exit Function
Catch:
URLEncode = ""
Resume Finally
End Function
'Check if Excel is running in Windows or Mac
'From [url]http://www.rondebruin.nl/mac.htm[/url]
Private Function isWindows() As Boolean
    'Test the OperatingSystem
    If Not Application.OperatingSystem Like "*Mac*" Then
        isWindows = True
    Else
        'Mac, but test if it is Excel 2011 or higher
        If Val(Application.Version) > 14 Then
            isWindows = False
        End If
    End If
End Function
'Get the element value in an XML document
'if excel for mac had regex support, we'd use that. it does not, so use these string functions to find lat/long/precision while maintaining win/mac compatibility
Private Function getElementValue(elementName As String)
    Dim element As String
    Dim startPosition As Long
    Dim endPosition As Long
    Dim elementLength As Long
    
    'find the start position of the start tag <ElementName> and add the length of the element to the position
    element = "<" & elementName & ">"
    startPosition = InStr(xml, element) + Len(element)
    
    'find the start position of the closing tag </ElementName>
    element = "</" & elementName & ">"
    endPosition = InStr(xml, element)
    
    'calculate the length of the element value
    elementLength = endPosition - startPosition
    
    'return the sub-string
    getElementValue = Mid(xml, startPosition, elementLength)
    
End Function