; ; NOSA HEADER START ; ; The contents of this file are subject to the terms of the NASA Open ; Source Agreement (NOSA), Version 1.3 only (the "Agreement"). You may ; not use this file except in compliance with the Agreement. ; ; You can obtain a copy of the agreement at ; docs/NASA_Open_Source_Agreement_1.3.txt ; or ; https://sscweb.gsfc.nasa.gov/WebServices/NASA_Open_Source_Agreement_1.3.txt. ; ; See the Agreement for the specific language governing permissions ; and limitations under the Agreement. ; ; When distributing Covered Code, include this NOSA HEADER in each ; file and include the Agreement file at ; docs/NASA_Open_Source_Agreement_1.3.txt. If applicable, add the ; following below this NOSA HEADER, with the fields enclosed by ; brackets "[]" replaced with your own identifying information: ; Portions Copyright [yyyy] [name of copyright owner} ; ; NOSA HEADER END ; ; Copyright (c) 2013-2021 United States Government as represented by ; the National Aeronautics and Space Administration. No copyright is ; claimed in the United States under Title 17, U.S.Code. All Other ; Rights Reserved. ; ;

;+ ; This class represents the remotely callable interface to ; <a href=“https://www.nasa.gov/“>NASA&lt;/a>‘s ; <a href=“https://spdf.gsfc.nasa.gov/“>Space Physics Data Facility</a> ; (SPDF) ; <a href=“https://sscweb.gsfc.nasa.gov/“>Satellite Situation Center</a> ; (SSC). The current implementation only support the ; <a href=“https://sscweb.gsfc.nasa.gov/WebServices/REST/#Get_Locations_POST”> ; “data locations” functionality</a>. Supporting the “text (listing) ; locations”, “conjunctions” and/or “graphs” functionality is a ; future possibility if there were sufficient interest. ; ; @copyright Copyright (c) 2013-2017 United States Government as ; represented by the National Aeronautics and Space Administration. ; No copyright is claimed in the United States under Title 17, ; U.S.Code. All Other Rights Reserved. ; ; @author B. Harris ;-

;+ ; Creates an object representing SSC. ; ; @keyword endpoint {in} {optional} {type=string} ; {default=self->getDefaultEndpoint()} ; URL of SSC web service . ; @keyword userAgent {in} {optional} {type=string} {default=SscWs} ; HTTP user-agent value used in communications with SSC. ; @keyword sslVerifyPeer {in} {optional} {type=int} {default=1} ; Specifies whether the authenticity of the peer’s SSL ; certificate should be verified. When 0, the connection ; succeeds regardless of what the peer SSL certificate ; contains. ; @returns a reference to a SSC object. ;- function SpdfSsc::init, endpoint=endpoint, endpoint = endpoint, userAgent = userAgent, $ sslVerifyPeer = sslVerifyPeer compile_opt idl2

version = '%VERSION*'
currentVersionUrl = $
    'https://sscweb.gsfc.nasa.gov/WebServices/REST/spdfSscVersion.txt'

if ~keyword_set(endpoint) then begin

    endpoint = self->getDefaultEndpoint()
endif

if ~keyword_set(userAgent) then userAgent = 'SscWs'

obj = self->SpdfRest::init( $
          endpoint, version, currentVersionUrl, $
          userAgent = userAgent + '/' + version, $
          sslVerifyPeer = sslVerifyPeer)

return, obj

end

;+ ; Performs cleanup operations when this object is destroyed. ;- pro SpdfSsc::cleanup compile_opt idl2

self->SpdfRest::cleanup

end

;+ ; Gets the default endpoint value. ; ; @returns default endpoint string value. ;- function SpdfSsc::getDefaultEndpoint compile_opt idl2

endpoint = 'http'

releaseComponents = strsplit(!version.release, '.', /extract)

if (releaseComponents[0] ge '8') or $
   (releaseComponents[0] eq '8' and $
    releaseComponents[1] ge '4') then begin

; Even though earlier versions of IDL are suppose to support ; https, they do not (at least they do not support https to ; cdaweb).

    endpoint = endpoint + 's'
endif

return, endpoint + '://sscweb.gsfc.nasa.gov/WS/sscr/2'

end

;+ ; Gets a description of all the observatories that are available. ; ; @keyword httpErrorReporter {in} {optional} ; {type=SpdfHttpErrorReporter} ; used to report an HTTP error. ; @returns array of SpdfObservatoryDescription objects. ;- function SpdfSsc::getObservatories, $ httpErrorReporter=errorReporter compile_opt idl2

url = self.endpoint + '/observatories'

observatoryDom = $
    self->makeGetRequest(url, errorReporter=errorReporter)

if ~obj_valid(observatoryDom) then return, objarr(1)

observatoryElements = $
    observatoryDom->getElementsByTagName('Observatory')

observatories = objarr(observatoryElements->getLength(), /nozero)

for i = 0, observatoryElements->getLength() - 1 do begin

    observatoryElement = observatoryElements->item(i)

    id = $
        self->getNamedElementsFirstChildValue( $
            observatoryElement, 'Id')
    name = $
        self->getNamedElementsFirstChildValue( $
            observatoryElement, 'Name')
    resolution = $
        self->getNamedElementsFirstChildValue( $
            observatoryElement, 'Resolution')
    startTime = $
        self->getJulDate((observatoryElement->$
            getElementsByTagName('StartTime'))->item(0))
    endTime = $
        self->getJulDate((observatoryElement->$
            getElementsByTagName('EndTime'))->item(0))
    geometry = $
        self->getNamedElementsFirstChildValue( $
            observatoryElement, 'Geometry')
    trajectoryGeometry = $
        self->getNamedElementsFirstChildValue( $
            observatoryElement, 'TrajectoryGeometry')
    resourceId = $
        self->getNamedElementsFirstChildValue( $
            observatoryElement, 'ResourceId')
    groupIds = $
        self->getNamedElementsFirstChildValue( $
            observatoryElement, 'GroupId')

    observatories[i] = $
        obj_new('SpdfObservatoryDescription', id, name, $
            resolution, startTime, endTime, geometry, $
            trajectoryGeometry, resourceId, groupIds)
endfor

obj_destroy, observatoryDom

return, observatories

end

;+ ; Gets a description of all the ground stations that are available. ; ; @keyword httpErrorReporter {in} {optional} ; {type=SpdfHttpErrorReporter} ; used to report an HTTP error. ; @returns array of SpdfGroundStation objects. ;- function SpdfSsc::getGroundStations, $ httpErrorReporter=errorReporter compile_opt idl2

url = self.endpoint + '/groundStations'

gsDom = self->makeGetRequest(url, errorReporter=errorReporter)

if ~obj_valid(gsDom) then return, objarr(1)

gsElements = gsDom->getElementsByTagName('GroundStation')

groundStations = objarr(gsElements->getLength(), /nozero)

for i = 0, gsElements->getLength() - 1 do begin

    gsElement = gsElements->item(i)

    id = $
        self->getNamedElementsFirstChildValue(gsElement, 'Id')
    name = $
        self->getNamedElementsFirstChildValue(gsElement, 'Name')
    latitude = $
        self->getNamedElementsFirstChildValue( $
            gsElement, 'Latitude')
    longitude = $
        self->getNamedElementsFirstChildValue( $
            gsElement, 'Longitude')

    location = obj_new('SpdfSurfaceGeographicCoordinates', $
                   latitude, longitude)

    groundStations[i] = $
        obj_new('SpdfGroundStation', id, name, location)
endfor

obj_destroy, gsDom

return, groundStations

end

;+ ; Request the specified satellite location information from SSC. ; ; @private ; ; @param locationRequest {in} {type=SpdfLocationRequest} ; specifies the information to get. ; @keyword httpErrorReporter {in} {optional} ; {type=SpdfHttpErrorReporter} ; used to report an HTTP error. ; @returns an SpdfSscDataResult or SpdfSscFileResult object. ;- function SpdfSsc::getLocations, locationRequest, locationRequest, httpErrorReporter = errorReporter compile_opt idl2

url = self.endpoint + '/locations'

requestDoc = obj_new('IDLffXMLDOMDocument')

requestDom = $
    requestDoc->appendChild( $
        locationRequest->createDomElement(requestDoc))

requestDoc->save, string=xmlRequest

obj_destroy, requestDoc

resultDoc = self->makePostRequest(url, xmlRequest, $
                errorReporter = errorReporter)

if ~obj_valid(resultDoc) then return, obj_new()

fileNodeList= resultDoc->getElementsByTagName('Files')

if fileNodeList->getLength() eq 0 then begin

    dataResult = self->getDataResult(resultDoc)
endif else begin

    dataResult = self->getFileResult(resultDoc)
endelse

obj_destroy, resultDoc

return, dataResult

end

;+ ; Gets the node’s time values from the given DOM element. ; ; @private ; ; @param domElement {in} {required} {type=IDLffXMLDOMElement} ; DOM element to search. ; @keyword name {in} {optional} {type=string} {default=‘Time’} ; name of time tag. ; @returns node’s julday time value(s) from the given DOM element. ; A scalar value of !values.d_NaN is returned if no value is found. ;- function SpdfSsc::getTime, domElement, domElement, name = name compile_opt idl2

if keyword_set(name) then name = name else name = 'Time'

nodeList = domElement->getElementsByTagName(name)

if nodeList->getLength() eq 0 then return, !values.d_NaN

values = dblarr(nodeList->getLength())

for i = 0, nodeList->getLength() - 1 do begin

    domNode = nodeList->item(i)

    values[i] = self->getJulDate(domNode)
endfor

if n_elements(values) eq 1 then return, values[0] $
                           else return, values

end

;+ ; Gets the specified node values from the given ssc:DataResult XML ; document. ; ; @private ; ; @param resultDoc {in} {type=IDLffXMLDOMDocument} ; SpdfSscDataResult XML document. ; @param type {in} {type=string} ; name of elements whose value is to be gotten. ; @returns strarr of the specified node values from the given document. ;- function SpdfSsc::getDataResultText, $ resultDoc, type compile_opt idl2

return, self->getNamedElementsFirstChildValue(resultDoc, type)

end

;+ ; Creates an SpdfSscFileResult object from the given ssc:DataResult ; XML document. ; ; @private ; ; @param doc {in} {type=IDLffXMLDOMDocument} ; SpdfSscDataResult XML document. ; @returns SpdfSscFileResult object. ;- function SpdfSsc::getFileResult, $ doc compile_opt idl2

; doc->save, filename=‘getFileResult.xml’, /pretty_print

statusCode = self->getDataResultText(doc, 'StatusCode')

statusSubCode = self->getDataResultText(doc, 'StatusSubCode')

statusText = self->getDataResultText(doc, 'StatusText')

if statusCode eq '' then begin

; This will not be necessary when the server is fixed to ; include it in a FileResult (fix is in R2.2.7). statusCode = ‘Success’ endif if statusCode ne ‘Success’ then begin

    print, 'StatusCode: ', statusCode
    print, 'StatusSubCode: ', statusSubCode
    print, 'StatusText: ', statusText

    return, obj_new()
endif

files = self->getFiles(doc)

fileResult = obj_new('SpdfSscFileResult', $
    files, $
    statusCode = statusCode, $
    statusSubCode = statusSubCode, $
    statusText = statusText)

return, fileResult

end

;+ ; Creates an array of SpdfSscFileDescription objects from the given ; ssc:Files XML document. ; ; @private ; ; @param doc {in} {type=IDLffXMLDOMDocument} ; SpdfFileResult XML document. ; @returns objarr containing SpdfSscFileDescriptions or an objarr(1) whose ; first element is ~obj_valid(). ;- function SpdfSsc::getFiles, $ doc compile_opt idl2

; doc->save, filename=‘files.xml’, /pretty_print

filesElements = $
    doc->getElementsByTagName('Files')

if filesElements->getLength() eq 0 then begin

    return, objarr(1)
endif

files = objarr(filesElements->getLength())

for i = 0, filesElements->getLength() - 1 do begin

    filesElement = filesElements->item(i)

    name = self->getNamedElementsFirstChildValue( $
               filesElement, 'Name')

    mimeType = self->getNamedElementsFirstChildValue( $
                   filesElement, 'MimeType')

    length = self->getNamedElementsFirstChildValue( $
               filesElement, 'Length')

    lastModified = self->getTime(filesElement, name='LastModified')

    files[i] = obj_new('SpdfSscFileDescription', $
        name, $
        mimeType, $
        length, $
        lastModified)
endfor

return, files

end

;+ ; Creates an SpdfSscDataResult object from the given ssc:DataResult ; XML document. ; ; @private ; ; @param doc {in} {type=IDLffXMLDOMDocument} ; SpdfSscDataResult XML document. ; @returns SpdfSscDataResult object. ;- function SpdfSsc::getDataResult, $ doc compile_opt idl2

doc->save, filename=‘getDataResult.xml’, /pretty_print

statusCode = self->getDataResultText(doc, 'StatusCode')

statusSubCode = self->getDataResultText(doc, 'StatusSubCode')

statusText = self->getDataResultText(doc, 'StatusText')

if statusCode ne 'Success' then begin

    print, 'StatusCode: ', statusCode
    print, 'StatusSubCode: ', statusSubCode
    print, 'StatusText: ', statusText

    return, obj_new()
endif

data = self->getSatelliteData(doc)

dataResult = obj_new('SpdfSscDataResult', $
    data, $
    statusCode = statusCode, $
    statusSubCode = statusSubCode, $
    statusText = statusText)

return, dataResult

end

;+ ; Creates an SpdfSatelliteData object from the given ssc:SatelliteData ; XML document. ; ; @private ; ; @param doc {in} {type=IDLffXMLDOMDocument} ; SpdfSatelliteData XML document. ; @returns objarr containing SpdfSatelliteData or an objarr(1) whose ; first element is ~obj_valid(). ;- function SpdfSsc::getSatelliteData, $ doc compile_opt idl2

; doc->save, filename=‘satData.xml’, /pretty_print

satDataElements = $
    doc->getElementsByTagName('Data')

if satDataElements->getLength() eq 0 then begin

    return, objarr(1)
endif

satData = objarr(satDataElements->getLength())

for i = 0, satDataElements->getLength() - 1 do begin

    satDataElement = satDataElements->item(i)

    id = $
        self->getNamedElementsFirstChildValue( $
            satDataElement, 'Id')

    coordinateData = $
        self->getCoordinateData(satDataElement)

    time = self->getTime(satDataElement)

    bTraceData = self->getBTraceData(satDataElement)

    radialLength = $
        self->getDoubleSatelliteData( $
            satDataElement, 'RadialLength')

    magneticStrength = $
        self->getDoubleSatelliteData( $
            satDataElement, 'MagneticStrength')

    neutralSheetDistance = $
        self->getDoubleSatelliteData( $
            satDataElement, 'NeutralSheetDistance')

    bowShockDistance = $
        self->getDoubleSatelliteData( $
            satDataElement, 'BowShockDistance')

    magnetoPauseDistance = $
        self->getDoubleSatelliteData( $
            satDataElement, 'MagnetoPauseDistance')

    dipoleLValue = $
        self->getDoubleSatelliteData( $
            satDataElement, 'DipoleLValue')

    dipoleInvariantLatitude = $
        self->getFloatSatelliteData( $
            satDataElement, 'DipoleInvariantLatitude')

    spacecraftRegion = $
        self->getSatelliteRegionData( $
            satDataElement, 'SpacecraftRegion')

    radialTracedFootpointRegions = $
        self->getSatelliteRegionData( $
            satDataElement, 'RadialTracedFootpointRegions')

    bGseX = $
        self->getDoubleSatelliteData(satDataElement, 'BGseX')

    bGseY = $
        self->getDoubleSatelliteData(satDataElement, 'BGseY')

    bGseZ = $
        self->getDoubleSatelliteData(satDataElement, 'BGseZ')

    northBTracedFootpointRegions = $
        self->getSatelliteRegionData( $
            satDataElement, 'NorthBTracedFootpointRegions')

    southBTracedFootpointRegions = $
        self->getSatelliteRegionData( $
            satDataElement, 'SouthBTracedFootpointRegions')

    satData[i] = obj_new('SpdfSatelliteData', $
        id, $
        coordinateData, $
        time, $
        bTraceData = bTraceData, $
        radialLength = radialLength, $
        magneticStrength = magneticStrength, $
        neutralSheetDistance = neutralSheetDistance, $
        bowShockDistance = bowShockDistance, $
        magnetoPauseDistance = magnetoPauseDistance, $
        dipoleLValue = dipoleLValue, $
        dipoleInvariantLatitude = dipoleInvariantLatitude, $
        spacecraftRegion = spacecraftRegion, $
        radialTracedFootpointRegions = $
            radialTracedFootpointRegions, $
        bGseX = bGseX, $
        bGseY = bGseY, $
        bGseZ = bGseZ, $
        northBTracedFootpointRegions = $
            northBTracedFootpointRegions, $
        southBTracedFootpointRegions = $
            southBTracedFootpointRegions)
endfor

return, satData

end

;+ ; Creates an SpdfCoordinateData object from the given ssc:SatelliteData ; XML element. ; ; @private ; ; @param satDataElement {in} {type=IDLffXMLDOMElement} ; SpdfSatelliteData XML element. ; @returns SpdfCoordinateData object. ;- function SpdfSsc::getCoordinateData, $ satDataElement compile_opt idl2

nodeList = satDataElement->getElementsByTagName('Coordinates')

if nodeList->getLength() eq 0 then return, obj_new()

coordinatesElement = nodeList->item(0)

coordinateSystem = $
    self->getNamedElementsFirstChildValue( $
        coordinatesElement, 'CoordinateSystem')

x = self->getNamedElementsFirstChildDoubleValue( $
        coordinatesElement, 'X')

y = self->getNamedElementsFirstChildDoubleValue( $
        coordinatesElement, 'Y')

z = self->getNamedElementsFirstChildDoubleValue( $
        coordinatesElement, 'Z')

latitude = self->getNamedElementsFirstChildFloatValue( $
        coordinatesElement, 'Latitude')

longitude = self->getNamedElementsFirstChildFloatValue( $
        coordinatesElement, 'Longitude')

localTime = self->getNamedElementsFirstChildDoubleValue( $
        coordinatesElement, 'LocalTime')

coordinateData = $
    obj_new('SpdfCoordinateData', $
        coordinateSystem, $
        x = x, $
        y = y, $
        z = z, $
        latitude = latitude, $
        longitude = longitude, $
        localTime = localTime)

return, coordinateData

end

;+ ; Creates an SpdfBTraceData object from the given ssc:BTraceData ; XML element. ; ; @private ; ; @param satDataElement {in} {type=IDLffXMLDOMElement} ; SpdfSatelliteData XML element. ; @returns SpdfCoordinateData object. ;- function SpdfSsc::getBTraceData, $ satDataElement compile_opt idl2

bTraceDataElements = $
    satDataElement->getElementsByTagName('BTraceData')

if bTraceDataElements->getLength() eq 0 then begin

    return, objarr(1)
endif

bTraceData = objarr(bTraceDataElements->getLength())

for i = 0, bTraceDataElements->getLength() - 1 do begin

    bTraceDataElement = bTraceDataElements->item(i)

    coordinateSystem = $
        self->getNamedElementsFirstChildValue( $
            bTraceDataElement, 'CoordinateSystem')

    hemisphere = $
        self->getNamedElementsFirstChildValue( $
            bTraceDataElement, 'Hemisphere')

    latitude = self->getNamedElementsFirstChildFloatValue( $
            bTraceDataElement, 'Latitude')

    longitude = self->getNamedElementsFirstChildFloatValue( $
            bTraceDataElement, 'Longitude')

    arcLength = self->getNamedElementsFirstChildDoubleValue( $
            bTraceDataElement, 'ArcLength')

    bTraceData[i] = $
        obj_new('SpdfBTraceData', $
            coordinateSystem, $
            hemisphere, $
            latitude = latitude, $
            longitude = longitude, $
            arcLength = arcLength)
endfor

return, bTraceData

end

;+ ; Gets the specified double data values from the given satellite data. ; ; @private ; ; @param satDataElement {in} {type=IDLffXMLDOMElement} ; Satellite XML element. ; @param name {in} {type=string} ; name of satellite data to get. ; @returns array of double values. ;- function SpdfSsc::getDoubleSatelliteData, satDataElement, satDataElement, name compile_opt idl2

values = self->getNamedElementsFirstChildDoubleValue( $
        satDataElement, name)

return, values

end

;+ ; Gets the specified float data values from the given satellite data. ; ; @private ; ; @param satDataElement {in} {type=IDLffXMLDOMElement} ; Satellite XML element. ; @param name {in} {type=string} ; name of satellite data to get. ; @returns array of float values. ;- function SpdfSsc::getFloatSatelliteData, satDataElement, satDataElement, name compile_opt idl2

values = self->getNamedElementsFirstChildFloatValue( $
        satDataElement, name)

return, values

end

;+ ; Gets the specified region data values from the given satellite data. ; ; @private ; ; @param satDataElement {in} {type=IDLffXMLDOMElement} ; Satellite XML element. ; @param name {in} {type=string} ; name of region data to get. ; @returns strarr of region values. An empty string is returned ; if the value cannot be found. ;- function SpdfSsc::getSatelliteRegionData, satDataElement, satDataElement, name compile_opt idl2

values = self->getNamedElementsFirstChildValue( $
            satDataElement, name)

return, values

end

;+ ; Defines the SpdfSsc class. ; ;- pro SpdfSsc__define compile_opt idl2 struct = { SpdfSsc, inheritsSpdfRest inherits SpdfRest } end