{
    "openapi": "3.0.0",
    "info": {
        "version": "2.0.0",
        "title": "Signal K Course API",
        "termsOfService": "http://signalk.org/terms/",
        "license": {
            "name": "Apache 2.0",
            "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
        }
    },
    "externalDocs": {
        "url": "http://signalk.org/specification/",
        "description": "Signal K specification."
    },
    "servers": [
        {
            "url": "/signalk/v2/api/vessels/self/navigation"
        }
    ],
    "tags": [
        {
            "name": "course",
            "description": "Course operations"
        },
        {
            "name": "destination",
            "description": "Destination operations"
        },
        {
            "name": "activeRoute",
            "description": "Route operations"
        },
        {
            "name": "calculations",
            "description": "Calculated course data"
        },
        {
            "name": "configuration",
            "description": "Course API settings."
        }
    ],
    "components": {
        "schemas": {
            "IsoTime": {
                "type": "string",
                "pattern": "^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2}(?:\\.\\d*)?)((-(\\d{2}):(\\d{2})|Z)?)$",
                "example": "2022-04-22T05:02:56.484Z"
            },
            "SignalKHrefRoute": {
                "type": "string",
                "pattern": "^/resources/routes/[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$",
                "description": "Pointer to route resource.",
                "example": "/resources/routes/ac3a3b2d-07e8-4f25-92bc-98e7c92f7f1a"
            },
            "SignalKPosition": {
                "type": "object",
                "required": ["latitude", "longitude"],
                "properties": {
                    "latitude": {
                        "type": "number",
                        "format": "float"
                    },
                    "longitude": {
                        "type": "number",
                        "format": "float"
                    },
                    "altitude": {
                        "type": "number",
                        "format": "float"
                    }
                },
                "example": {
                    "latitude": 65.4567,
                    "longitude": 3.3452
                }
            },
            "ArrivalCircle": {
                "type": "number",
                "minimum": 0,
                "description": "Radius of arrival zone in meters",
                "example": 500
            },
            "HrefWaypointAttribute": {
                "type": "object",
                "required": ["href"],
                "properties": {
                    "href": {
                        "type": "string",
                        "pattern": "^/resources/waypoints/[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$",
                        "description": "Reference to a related route resource. A pointer to the resource UUID.",
                        "example": "/resources/waypoints/ac3a3b2d-07e8-4f25-92bc-98e7c92f7f1a"
                    }
                }
            },
            "ActiveRouteModel": {
                "type": "object",
                "required": ["href", "pointIndex", "pointTotal", "reverse"],
                "properties": {
                    "href": {
                        "$ref": "#/components/schemas/SignalKHrefRoute"
                    },
                    "name": {
                        "type": "string",
                        "description": "Name of route.",
                        "example": "Here to eternity."
                    },
                    "pointIndex": {
                        "type": "number",
                        "minimum": 0,
                        "description": "0 based index of the point in the route that is the current destination"
                    },
                    "pointTotal": {
                        "type": "number",
                        "description": "Total number of points in the route"
                    },
                    "reverse": {
                        "type": "boolean",
                        "description": "When true indicates the route points are being navigated in reverse order."
                    }
                }
            },
            "PointModel": {
                "anyOf": [
                    {
                        "$ref": "#/components/schemas/HrefWaypointAttribute"
                    },
                    {
                        "$ref": "#/components/schemas/PointTypeAttribute"
                    }
                ],
                "allOf": [
                    {
                        "$ref": "#/components/schemas/PositionAttribute"
                    }
                ]
            },
            "PositionAttribute": {
                "type": "object",
                "required": ["position"],
                "properties": {
                    "position": {
                        "description": "Location coordinates.",
                        "example": {
                            "latitude": 65.4567,
                            "longitude": 3.3452
                        },
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/SignalKPosition"
                            }
                        ]
                    }
                }
            },
            "PointTypeAttribute": {
                "type": "object",
                "properties": {
                    "type": {
                        "type": "string",
                        "description": "Type of point.",
                        "example": "Point of Interest"
                    }
                }
            },
            "ArrivalCircleAttribute": {
                "type": "object",
                "properties": {
                    "arrivalCircle": {
                        "$ref": "#/components/schemas/ArrivalCircle"
                    }
                }
            },
            "CourseCalculationsModel": {
                "type": "object",
                "required": ["calcMethod"],
                "description": "Calculated course data values.",
                "properties": {
                    "calcMethod": {
                        "type": "string",
                        "description": "Calculation method by which values are derived.",
                        "enum": ["GreatCircle", "Rhumbline"],
                        "default": "GreatCircle",
                        "example": "Rhumbline"
                    },
                    "crossTrackError": {
                        "type": "number",
                        "description": "The distance in meters from the vessel's present position to the closest point on a line (track) between previousPoint and nextPoint. A negative number indicates that the vessel is currently to the left of this line (and thus must steer right to compensate), a positive number means the vessel is to the right of the line (steer left to compensate).",
                        "example": 458.784
                    },
                    "bearingTrackTrue": {
                        "type": "number",
                        "minimum": 0,
                        "description": "The bearing of a line between previousPoint and nextPoint, relative to true north. (angle in radians)",
                        "example": 4.58491
                    },
                    "bearingTrackMagnetic": {
                        "type": "number",
                        "minimum": 0,
                        "description": "The bearing of a line between previousPoint and nextPoint, relative to magnetic north. (angle in radians)",
                        "example": 4.51234
                    },
                    "estimatedTimeOfArrival": {
                        "$ref": "#/components/schemas/IsoTime",
                        "description": "The estimated time of arrival at nextPoint position."
                    },
                    "distance": {
                        "type": "number",
                        "minimum": 0,
                        "description": "The distance in meters between the vessel's present position and the nextPoint.",
                        "example": 10157
                    },
                    "bearingTrue": {
                        "type": "number",
                        "minimum": 0,
                        "description": "The bearing of a line between the vessel's current position and nextPoint, relative to true north. (angle in radians)",
                        "example": 4.58491
                    },
                    "bearingMagnetic": {
                        "type": "number",
                        "minimum": 0,
                        "description": "The bearing of a line between the vessel's current position and nextPoint, relative to magnetic north. (angle in radians)",
                        "example": 4.51234
                    },
                    "velocityMadeGood": {
                        "type": "number",
                        "description": "The velocity component of the vessel towards the nextPoint in m/s",
                        "example": 7.2653
                    },
                    "timeToGo": {
                        "type": "number",
                        "minimum": 0,
                        "description": "Time in seconds to reach nextPoint's perpendicular with current speed & direction.",
                        "example": 8491
                    },
                    "targetSpeed": {
                        "type": "number",
                        "description": "The average velocity required to reach the destination at the value of targetArriavlTime in m/s",
                        "example": 2.2653
                    },
                    "previousPoint": {
                        "type": "object",
                        "description": "Calculations relative to source position.",
                        "properties": {
                            "distance": {
                                "type": "number",
                                "minimum": 0,
                                "description": "The distance in meters between the vessel's present position and the start point.",
                                "example": 10157
                            }
                        }
                    },
                    "route": {
                        "type": "object",
                        "description": "Calculations relative to last route point.",
                        "properties": {
                            "distance": {
                                "type": "number",
                                "minimum": 0,
                                "description": "The distance in meters along the route to the last point.",
                                "example": 15936
                            },
                            "timeToGo": {
                                "type": "number",
                                "minimum": 0,
                                "description": "Time in seconds to reach perpendicular of last point in route with current speed & direction.",
                                "example": 10452
                            },
                            "estimatedTimeOfArrival": {
                                "$ref": "#/components/schemas/IsoTime",
                                "description": "The estimated time of arrival at last point in route."
                            }
                        }
                    }
                }
            }
        },
        "responses": {
            "200Ok": {
                "description": "OK",
                "content": {
                    "application/json": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "state": {
                                    "type": "string",
                                    "enum": ["COMPLETED"]
                                },
                                "statusCode": {
                                    "type": "number",
                                    "enum": [200]
                                }
                            },
                            "required": ["state", "statusCode"]
                        }
                    }
                }
            },
            "ErrorResponse": {
                "description": "Failed operation",
                "content": {
                    "application/json": {
                        "schema": {
                            "type": "object",
                            "description": "Request error response",
                            "properties": {
                                "state": {
                                    "type": "string",
                                    "enum": ["FAILED"]
                                },
                                "statusCode": {
                                    "type": "number",
                                    "enum": [404]
                                },
                                "message": {
                                    "type": "string"
                                }
                            },
                            "required": ["state", "statusCode", "message"]
                        }
                    }
                }
            },
            "CourseResponse": {
                "description": "Course details",
                "content": {
                    "application/json": {
                        "schema": {
                            "description": "Course response",
                            "type": "object",
                            "required": ["activeRoute", "nextPoint", "previousPoint"],
                            "properties": {
                                "activeRoute": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/ActiveRouteModel"
                                        }
                                    ]
                                },
                                "nextPoint": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/PointModel"
                                        }
                                    ]
                                },
                                "previousPoint": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/PointModel"
                                        }
                                    ]
                                },
                                "startTime": {
                                    "$ref": "#/components/schemas/IsoTime",
                                    "example": "2022-04-22T05:02:56.484Z",
                                    "description": "Time at which navigation to destination commenced."
                                },
                                "targetArrivalTime": {
                                    "$ref": "#/components/schemas/IsoTime",
                                    "example": "2022-04-22T05:02:56.484Z",
                                    "description": "The desired time at which to arrive at the destination."
                                },
                                "arrivalCircle": {
                                    "$ref": "#/components/schemas/ArrivalCircle"
                                }
                            }
                        }
                    }
                }
            }
        },
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "bearerFormat": "JWT"
            },
            "cookieAuth": {
                "type": "apiKey",
                "in": "cookie",
                "name": "JAUTHENTICATION"
            }
        }
    },
    "security": [{ "cookieAuth": [] }, { "bearerAuth": [] }],
    "paths": {
        "/course": {
            "get": {
                "tags": ["course"],
                "summary": "Retrieve current course details.",
                "description": "Returns the current course status.",
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/CourseResponse"
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            },
            "delete": {
                "tags": ["course"],
                "summary": "Cancel / clear course.",
                "description": "Clear all course information.",
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/200Ok"
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            }
        },
        "/course/arrivalCircle": {
            "put": {
                "tags": ["course"],
                "summary": "Set arrival zone size.",
                "description": "Sets the radius of a circle in meters centered at the current destination.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": ["value"],
                                "properties": {
                                    "value": {
                                        "$ref": "#/components/schemas/ArrivalCircle"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/200Ok"
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            }
        },
        "/course/restart": {
            "put": {
                "tags": ["course"],
                "summary": "Restart course calculations.",
                "description": "Sets previousPoint value to current vessel position and bases calculations on update.",
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/200Ok"
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            }
        },
        "/course/targetArrivalTime": {
            "put": {
                "tags": ["course"],
                "summary": "Set target arrival time.",
                "description": "Sets the desired time to arrive at the destination. Used to calculate targetSpeed.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": ["value"],
                                "properties": {
                                    "value": {
                                        "$ref": "#/components/schemas/IsoTime"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/200Ok"
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            }
        },
        "/course/destination": {
            "put": {
                "tags": ["destination"],
                "summary": "Set destination.",
                "description": "Sets nextPoint path with supplied details.",
                "requestBody": {
                    "description": "Destination details.",
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "oneOf": [
                                    {
                                        "$ref": "#/components/schemas/HrefWaypointAttribute"
                                    },
                                    {
                                        "$ref": "#/components/schemas/PositionAttribute"
                                    }
                                ],
                                "allOf": [
                                    {
                                        "$ref": "#/components/schemas/ArrivalCircleAttribute"
                                    }
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/200Ok"
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            }
        },
        "/course/activeRoute": {
            "put": {
                "tags": ["activeRoute"],
                "summary": "Set active route.",
                "description": "Sets activeRoute path and sets nextPoint to first point in the route.",
                "requestBody": {
                    "description": "Route to activate.",
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": ["href"],
                                "properties": {
                                    "href": {
                                        "$ref": "#/components/schemas/SignalKHrefRoute"
                                    },
                                    "pointIndex": {
                                        "type": "number",
                                        "default": 0,
                                        "minimum": 0,
                                        "description": "0 based index of the point in the route to set as the destination"
                                    },
                                    "reverse": {
                                        "type": "boolean",
                                        "default": false,
                                        "description": "Set to true to navigate the route points in reverse order."
                                    },
                                    "arrivalCircle": {
                                        "$ref": "#/components/schemas/ArrivalCircle"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/200Ok"
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            }
        },
        "/course/activeRoute/nextPoint": {
            "put": {
                "tags": ["activeRoute"],
                "summary": "Set next point in route.",
                "description": "Sets nextPoint / previousPoint.",
                "requestBody": {
                    "description": "Destination details.",
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": ["value"],
                                "properties": {
                                    "value": {
                                        "type": "number",
                                        "description": "Index of point in route (-ive = previous)",
                                        "default": 1
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/200Ok"
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            }
        },
        "/course/activeRoute/pointIndex": {
            "put": {
                "tags": ["activeRoute"],
                "summary": "Set point in route as destination.",
                "description": "Sets destination to the point with the provided index.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": ["value"],
                                "properties": {
                                    "value": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Index of point in route to set as destination.",
                                        "example": 2
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/200Ok"
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            }
        },
        "/course/activeRoute/reverse": {
            "put": {
                "tags": ["activeRoute"],
                "summary": "Reverse route direction.",
                "description": "Reverse the direction the active route is navigated.",
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "pointIndex": {
                                        "type": "number",
                                        "minimum": 0,
                                        "description": "Index of point in route to set as destination.",
                                        "example": 2
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/200Ok"
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            }
        },
        "/course/activeRoute/refresh": {
            "put": {
                "tags": ["activeRoute"],
                "summary": "Refresh course information.",
                "description": "Refresh course values after a change has been made.",
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/200Ok"
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            }
        },
        "/course/calcValues": {
            "get": {
                "tags": ["calculations"],
                "summary": "Course calculated values.",
                "description": "Returns the current course status.",
                "responses": {
                    "200": {
                        "description": "Course data.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/CourseCalculationsModel"
                                }
                            }
                        }
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            }
        },
        "/course/_config": {
            "get": {
                "tags": ["configuration"],
                "summary": "Retrieve Course API configuration.",
                "description": "Returns the current Course API configuration settings.",
                "responses": {
                    "200": {
                        "description": "Course data.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "apiOnly": {
                                            "type": "boolean"
                                        }
                                    },
                                    "required": ["apiOnly"]
                                }
                            }
                        }
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            }
        },
        "/course/_config/apiOnly": {
            "post": {
                "tags": ["configuration"],
                "summary": "Set API Only mode.",
                "description": "Accept REST API requests only. Ignores NMEA sources.",
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/200Ok"
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            },
            "delete": {
                "tags": ["configuration"],
                "summary": "Clear API Only mode.",
                "description": "Accept both REST API requests and NMEA source data.",
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/200Ok"
                    },
                    "default": {
                        "$ref": "#/components/responses/ErrorResponse"
                    }
                }
            }
        }
    }
}
