# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

openapi: 3.0.3
info:
  description: The next generation cloud-based science data service platform.
  version: 1.1.0
  title: Science Data Analytics Platform (SDAP)
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
tags:
  - name: Matchup
    description: Data Matchup API
  - name: Analytics
    description: Data Analytics API
  - name: Subsetting
    description: Data Subsetting API
paths:
  /match_spark:
    get:
      summary: Execute matchup request (AWS insitu)
      operationId: matchup
      description: Endpoint to execute matchup request. If secondary dataset is insitu, use AWS insitu API.
      tags:
        - Matchup
      parameters:
        - in: query
          name: primary
          description: |
            The primary dataset used to find matches for. One of the
            satellite "shortName" as supplied by /domslist endpoint.
          required: true
          schema:
            type: string
            x-dspopulate:
              - satellite
          example: avhrr-l4-glob-v2-daily-ncei-ghrsst-sstblend-avhrr-oi-glob-v020-fv020
        - in: query
          name: secondary
          description: |
            The dataset(s) being searched for measurements that match
            the measurements in primary. One or more (comma-separated)
            of the insitu or satellite "name" as supplied by
            https://doms.jpl.nasa.gov/domslist
          required: true
          schema:
            type: string
            x-dspopulate:
              - satellite
              - insitu
          example: icoads
        - in: query
          name: startTime
          description: |
            Starting time in format YYYY-MM-DDTHH:mm:ssZ or seconds
            since epoch
          required: true
          schema:
            type: string
            format: date-time
          example: '2012-09-25T00:00:00Z'
        - in: query
          name: endTime
          description: |
            Ending time in format YYYY-MM-DDTHH:mm:ssZ or seconds
            since epoch
          required: true
          schema:
            type: string
            format: date-time
          example: '2012-09-30T23:59:59Z'
        - in: query
          name: b
          description: |
            Minimum (Western) Longitude, Minimum (Southern) Latitude,
            Maximum (Eastern) Longitude, Maximum (Northern) Latitude
          required: true
          schema:
            type: string
          example: -45,15,-30,30
        - $ref: '#/components/parameters/Platforms'
        - in: query
          name: depthMin
          description: |
            Minimum depth of measurements allowed to be considered for
            matchup
          required: false
          schema:
            type: integer
          example: 0
        - in: query
          name: depthMax
          description: |
            Maximum depth of measurements allowed to be considered for
            matchup
          required: false
          schema:
            type: integer
          example: 5
        - in: query
          name: tt
          description: |
            Tolerance in time (seconds) when comparing two measurements.
          required: false
          schema:
            type: integer
            default: 86400
          example: 86400
        - in: query
          name: rt
          description: |
            Tolerance in radius (meters) when comparing two
            measurements.
          required: false
          schema:
            type: number
            default: 1000.0
          example: 1000.0
        - in: query
          name: parameter
          description: |
            The parameter of interest used for the match up. This is
            only used for insitu measurements. See
            [/get_cdms_schema](https://doms.jpl.nasa.gov/insitu/1.0/cdms_schema)
            endpoint for a list of valid options.
          required: false
          schema:
            type: string
            default: sea_surface_temperature
          example: sea_surface_temperature
        - in: query
          name: matchOnce
          description: |
            True/False flag used to determine if more than one match
            per primary point is returned. If true, only the nearest
            point will be returned for each primary point. If false,
            all points within the tolerances will be returned for each
            primary point.
          required: false
          schema:
            type: boolean
            default: false
          example: false
        - in: query
          name: resultSizeLimit
          description: |
            Optional integer value that limits the number of results
            returned from the matchup. If the number of primary matches
            is greater than this limit, the service will respond with
            (HTTP 202 Accepted) and an empty response body. A value of
            0 means return all results.
          required: false
          schema:
            type: integer
            default: 500
          example: 500
        - in: query
          name: prioritizeDistance
          description: |
            If true, prioritize distance over time when computing matches. 
            If false, prioritize time over distance. This is only relevant if 
            matchOnce=true, because otherwise all matches will be included 
            so long as they fit within the user-provided tolerances. 
            Default is true.
          required: false
          schema:
            type: boolean
            default: true
          example: true
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MatchupResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /match_spark_doms:
    get:
      summary: Execute matchup request (DOMS insitu)
      operationId: matchup_doms
      description: Endpoint to execute matchup request. If secondary dataset is insitu, use DOMS insitu API.
      tags:
        - Matchup
      parameters:
        - in: query
          name: primary
          description: |
            The primary dataset used to find matches for. One of the
            satellite "shortName" as supplied by /domslist endpoint.
          required: true
          schema:
            type: string
            x-dspopulate:
             - satellite
          example: avhrr-l4-glob-v2-daily-ncei-ghrsst-sstblend-avhrr-oi-glob-v020-fv020
        - in: query
          name: secondary
          description: |
            The dataset(s) being searched for measurements that match
            the measurements in primary. One or more (comma-separated)
            of the insitu or satellite "name" as supplied by
            https://doms.jpl.nasa.gov/domslist
          required: true
          schema:
            type: string
          example: icoads
        - in: query
          name: startTime
          description: |
            Starting time in format YYYY-MM-DDTHH:mm:ssZ or seconds
            since epoch
          required: true
          schema:
            type: string
            format: date-time
          example: '2012-09-25T00:00:00Z'
        - in: query
          name: endTime
          description: |
            Ending time in format YYYY-MM-DDTHH:mm:ssZ or seconds
            since epoch
          required: true
          schema:
            type: string
            format: date-time
          example: '2012-09-30T23:59:59Z'
        - in: query
          name: b
          description: |
            Minimum (Western) Longitude, Minimum (Southern) Latitude,
            Maximum (Eastern) Longitude, Maximum (Northern) Latitude
          required: true
          schema:
            type: string
          example: -45,15,-30,30
        - in: query
          name: platforms
          description: Platforms to include for matchup consideration
          required: true
          schema:
            type: string
          example: 1,2,3,4,5,6,7,8,9
        - in: query
          name: depthMin
          description: |
            Minimum depth of measurements allowed to be considered for
            matchup
          required: false
          schema:
            type: integer
          example: 0
        - in: query
          name: depthMax
          description: |
            Maximum depth of measurements allowed to be considered for
            matchup
          required: false
          schema:
            type: integer
          example: 5
        - in: query
          name: tt
          description: |
            Tolerance in time (seconds) when comparing two measurements.
          required: false
          schema:
            type: integer
            default: 86400
          example: 86400
        - in: query
          name: rt
          description: |
            Tolerance in radius (meters) when comparing two
            measurements.
          required: false
          schema:
            type: number
            default: 1000.0
          example: 1000.0
        - in: query
          name: parameter
          description: |
            The parameter of interest used for the match up.
          required: false
          schema:
            type: string
            enum: ['sst', 'sss', 'wind']
            default: sst
          example: sst
        - in: query
          name: matchOnce
          description: |
            True/False flag used to determine if more than one match
            per primary point is returned. If true, only the nearest
            point will be returned for each primary point. If false,
            all points within the tolerances will be returned for each
            primary point.
          required: false
          schema:
            type: boolean
            default: false
          example: false
        - in: query
          name: resultSizeLimit
          description: |
            Optional integer value that limits the number of results
            returned from the matchup. If the number of primary matches
            is greater than this limit, the service will respond with
            (HTTP 202 Accepted) and an empty response body. A value of
            0 means return all results.
          required: false
          schema:
            type: integer
            default: 500
          example: 500
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MatchupResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /cdmssubset:
    get:
      summary: Subset CDMS sources given the search domain
      operationId: cdmssubset
      tags:
        - Subsetting
      parameters:
        - in: query
          name: dataset
          description: |
            The NEXUS dataset. *Optional but at least one of 'dataset'
            or 'insitu' are required
          required: false
          schema:
            type: string
            x-dspopulate:
             - satellite
          example: MAVHRR_OI_L4_GHRSST_NCEI
        - in: query
          name: insitu
          description: |
            The in situ source(s). *Optional but at least one of
            'dataset' or 'insitu' are required
          required: false
          schema:
            type: string
            x-dspopulate:
             - insitu
          example: icoads,samos,spurs,spurs2
        - in: query
          name: startTime
          description: |
            Starting time in format YYYY-MM-DDTHH:mm:ssZ or seconds
            since epoch
          required: true
          schema:
            type: string
            format: date-time
          example: '2013-10-21T00:00:00Z'
        - in: query
          name: endTime
          description: |
            Ending time in format YYYY-MM-DDTHH:mm:ssZ or seconds
            since epoch
          required: true
          schema:
            type: string
            format: date-time
          example: '2013-10-21T01:00:00Z'
        - in: query
          name: b
          description: |
            Minimum (Western) Longitude, Minimum (Southern) Latitude,
            Maximum (Eastern) Longitude, Maximum (Northern) Latitude
          required: true
          schema:
            type: string
          example: -30,15,-45,30
        - in: query
          name: parameter
          description: |
            The parameter of interest.
          schema:
            type: string
          example: sea_surface_salinity
        - in: query
          name: depthMin
          description: |
            Minimum depth of measurements. Must be less than depthMax.
          required: false
          schema:
            type: integer
          example: 0
        - in: query
          name: depthMax
          description: |
            Maximum depth of measurements. Must be greater than
            depthMin.
          required: false
          schema:
            type: integer
          example: 5
        - $ref: '#/components/parameters/Platforms'
        - in: query
          name: output
          description: |
            Output type. Only 'ZIP' is currently supported
          required: true
          schema:
            type: string
            enum: ['ZIP']
            default: ZIP
          example: ZIP
      responses:
        '200':
          description: Successful operation
          content:
            application/zip:
              schema:
                type: string
                format: binary
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /version:
    get:
      summary: List the version of the API
      operationId: apiversion
      tags:
        - Matchup
      responses:
        '200':
          description: Successful operation
          content:
            text/plain:
              schema:
                type: string
                example: 1.6
        '500':
          description: Server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /cdmslist:
    get:
      summary: Provides a list of available data sets
      operationId: domslist
      tags:
        - Matchup
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DomsList'
        '500':
          description: Server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /cdmsresults:
    get:
      summary: |
        Convert matchup result
      operationId: cdmsresults
      tags:
        - Matchup
      parameters:
        - in: query
          name: id
          description: |
            The ID of the matchup execution. This comes from the
            `executionId` field in matchup output.
          required: true
          schema:
            type: string
          example: dfc907ce-b8b4-453a-b0b6-d295572ba15e
        - in: query
          name: output
          description: |
            Format for output results.
          required: true
          schema:
            type: string
            enum: ['CSV', 'NETCDF', 'JSON']
          example: CSV
        - in: query
          name: filename
          description: |
            Name of output file. Only works with CSV and NETCDF 
            output types. Do not include file extension in this field. 
            If this value is not provided, the filename will be 
            `CDMS_[execution_id].[csv|nc]`
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Successful operation
          content:
            text/csv:
              schema:
                type: string
            application/x-netcdf:
              schema:
                type: string
                format: binary
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /stats:
    get:
      summary: |
        Computes time series statistics
      operationId: stats
      tags:
        - Analytics
      description: "NOTE: Only supports satellite datasets."
      parameters:
        - in: query
          name: ds
          description: |
            The dataset on which to generate the statistics
          required: true
          schema:
            type: string
            x-dspopulate:
             - satellite
             - insitu
          example: MUR25-JPL-L4-GLOB-v04.2
        - in: query
          name: minLat
          description: |
            Minimum latitude on which to generate statistics
          required: true
          schema:
            type: string
          example: -90
        - in: query
          name: maxLat
          description: |
            Maximum latitude on which to generate statistics
          required: true
          schema:
            type: string
          example: 90
        - in: query
          name: minLon
          description: |
            Minimum longitude on which to generate statistics
          required: true
          schema:
            type: string
          example: -180
        - in: query
          name: maxLon
          description: |
            Maximum longitude on which to generate statistics
          required: true
          schema:
            type: string
          example: 180
        - in: query
          name: startTime
          description: |
            Starting time in format YYYY-MM-DDTHH:mm:ssZ or seconds
            since epoch
          required: true
          schema:
            type: string
            format: date-time
          example: '2013-10-21T00:00:00Z'
        - in: query
          name: endTime
          description: |
            Ending time in format YYYY-MM-DDTHH:mm:ssZ or seconds
            since epoch
          required: true
          schema:
            type: string
            format: date-time
          example: '2013-10-31T23:59:59Z'
        - in: query
          name: output
          description: |
            Data formatting for results. Default is ‘JSON’. Alternative
            is ‘CSV’ for comma-seperated values.
          required: false
          schema:
            type: string
            enum: ['JSON', 'CSV']
          example: JSON
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Stats'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
externalDocs:
  description: Documentation
  url: https://incubator-sdap-nexus.readthedocs.io/en/latest/index.html
components:
  parameters:
    Platforms:
      in: query
      name: platforms
      description: |
        Platforms to include for matchup consideration. Platform
        depends on which insitu dataset is selected. Use platform ID
        in the matchup query.
        
        <details>
          <summary>Expand to see a list of valid platforms IDs:</summary>
        | Platform ID | Platform Name                           | Web Link                                                   |
        | ----------- | --------------------------------------- | ---------------------------------------------------------- |
        | 3B          | autonomous surface water vehicle        | [Link](http://vocab.nerc.ac.uk/collection/L06/current/3B/) |
        | 6A          | glider                                  | [Link](http://vocab.nerc.ac.uk/collection/L06/current/6A/) |
        | 0           | unknown                                 | [Link](http://vocab.nerc.ac.uk/collection/L06/current/0/)  |
        | 16          | offshore structure                      | [Link](http://vocab.nerc.ac.uk/collection/L06/current/16/) |
        | 17          | coastal structure                       | [Link](http://vocab.nerc.ac.uk/collection/L06/current/17/) |
        | 23          | towed unmanned submersible              | [Link](http://vocab.nerc.ac.uk/collection/L06/current/23/) |
        | 30          | ship                                    | [Link](http://vocab.nerc.ac.uk/collection/L06/current/30/) |
        | 31          | research vessel                         | [Link](http://vocab.nerc.ac.uk/collection/L06/current/31/) |
        | 41          | moored surface buoy                     | [Link](http://vocab.nerc.ac.uk/collection/L06/current/41/) |
        | 42          | drifting surface float                  | [Link](http://vocab.nerc.ac.uk/collection/L06/current/42/) |
        | 46          | drifting subsurface profiling float     | [Link](http://vocab.nerc.ac.uk/collection/L06/current/46/) |
        | 48          | mooring                                 | [Link](http://vocab.nerc.ac.uk/collection/L06/current/48/) |
        </details>

      required: true
      schema:
        type: array
        items:
          type: string
          enum:
            - 0
            - 3B
            - 6A
            - 16
            - 17
            - 23
            - 30
            - 31
            - 41
            - 42
            - 46
            - 48
      example: 30
      explode: false
  schemas:
    DomsQueryResult:
      type: object
      properties:
        executionId:
          type: string
          format: uuid
    MatchupResponse:
      allOf:
        - $ref: '#/components/schemas/DomsQueryResult'
        - type: object
          properties:
            data:
              type: array
              items:
                $ref: '#/components/schemas/DomsPointPrimary'
    DomsPointPrimary:
      allOf:
        - $ref: '#/components/schemas/DomsPointBase'
        - type: object
          properties:
            matches:
              type: array
              items:
                $ref: '#/components/schemas/DomsPointSecondary'
        - type: object
          properties:
            primary:
              type: array
              items:
                $ref: '#/components/schemas/DomsDataPoint'
    DomsPointSecondary:
      allOf:
        - $ref: '#/components/schemas/DomsPointBase'
        - type: object
          properties:
            secondary:
              type: array
              items:
                $ref: '#/components/schemas/DomsDataPoint'
    DomsPointBase:
      type: object
      properties:
        platform:
          type: string
        device:
          type: string
        x:
          type: string
        y:
          type: string
        point:
          type: string
          format: wkt
        time:
          type: integer
        fileurl:
          type: string
        id:
          type: string
        source:
          type: string
    DomsDataPoint:
      type: object
      properties:
        variable_name:
          type: string
        cf_variable_name:
          type: string
        variable_value:
          type: number
    DomsList:
      allOf:
        - $ref: '#/components/schemas/DomsQueryResult'
        - type: object
          properties:
            data:
              type: object
              properties:
                satellite:
                  type: array
                  items:
                    type: object
                    properties:
                      shortName:
                        type: string
                      title:
                        type: string
                      tileCount:
                        type: integer
                      metadata:
                        type: string # TODO
                insitu:
                  type: array
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                      endpoint:
                        type: string
                        format: url
                      metadata:
                        type: string # TODO
                      depths:
                        type: string # TODO
                      facets:
                        type: array
                        items:
                          type: object
                          properties:
                            field:
                              type: string
                            values:
                              type: array
                              items:
                                type: object
                                properties:
                                  count:
                                    type: integer
                                  value:
                                    type: string
                params:
                  type: string # TODO
                bounds:
                  type: object # TODO
                count:
                  type: integer
                details:
                  type: string # TODO
    DomsValues:
      type: object
      allOf:
        - $ref: '#/components/schemas/DomsQueryResult'
        - type: object
          properties:
            data:
              type: array
              items:
                type: object
                properties:
                  x:
                    type: number
                  y:
                    type: number
                  source:
                    type: string
                  time:
                    type: number
                  device:
                    type: string
                    nullable: true
                  platform:
                    type: string
                  depth:
                    type: number
                    nullable: true
    Stats:
      type: object
      properties:
        meta:
          type: array
          items:
            type: object
            properties:
              shortname:
                type: string
              bounds:
                type: object
                properties:
                  east:
                    type: number
                  west:
                    type: number
                  north:
                    type: number
                  south:
                    type: number
              time:
                type: object
                properties:
                  start:
                    type: integer
                  stop:
                    type: integer
                  iso_start:
                    type: string
                    format: date
                  iso_stop:
                    type: string
                    format: date
        data:
          type: array
          items:
            type: object
            properties:
              min:
                type: number
              max:
                type: number
              mean:
                type: number
              cnt:
                type: integer
              std:
                type: number
              time:
                type: integer
              meanSeasonal:
                type: number
              minSeasonal:
                type: number
              maxSeasonal:
                type: number
              meanLowPass:
                type: number
              maxLowPass:
                type: number
              meanSeasonalLowPass:
                type: number
              minSeasonalLowPass:
                type: number
              maxSeasonalLowPass:
                type: number
              ds:
                type: integer
        stats:
          type: object
          properties:
            slope:
              type: number
            intercept:
              type: number
            r:
              type: number
            p:
              type: number
            err:
              type: string
    Error:
      type: object
      properties:
        error:
          type: string
        code:
          type: integer
