{
  "$schema": "http://json-schema.org/draft-07/schema",
  "description": "A CoverageJSON object",
  "type": "object",
  "properties": {
    "type": {
      "enum": [
        "Domain",
        "NdArray",
        "TiledNdArray",
        "Coverage",
        "CoverageCollection"
      ]
    }
  },
  "required": [
    "type"
  ],
  "allOf": [
    {
      "if": {
        "properties": {
          "type": {
            "const": "Domain"
          }
        }
      },
      "then": {
        "$ref": "#/definitions/domain"
      }
    },
    {
      "if": {
        "properties": {
          "type": {
            "const": "NdArray"
          }
        }
      },
      "then": {
        "$ref": "#/definitions/ndArray"
      }
    },
    {
      "if": {
        "properties": {
          "type": {
            "const": "TiledNdArray"
          }
        }
      },
      "then": {
        "$ref": "#/definitions/tiledNdArray"
      }
    },
    {
      "if": {
        "properties": {
          "type": {
            "const": "Coverage"
          }
        }
      },
      "then": {
        "$ref": "#/definitions/coverage"
      }
    },
    {
      "if": {
        "properties": {
          "type": {
            "const": "CoverageCollection"
          }
        }
      },
      "then": {
        "$ref": "#/definitions/coverageCollection"
      }
    }
  ],
  "definitions": {
    "anyAxis": {
      "description": "Validates any axis",
      "if": {
        "required": [
          "values"
        ]
      },
      "then": {
        "$ref": "#/definitions/valuesAxis"
      },
      "else": {
        "$ref": "#/definitions/numericRegularlySpacedAxis"
      }
    },
    "coverage": {
      "allOf": [
        {
          "$ref": "#/definitions/coverageBase"
        },
        {
          "required": [
            "parameters"
          ],
          "properties": {
            "domain": {
              "if": {
                "type": "object"
              },
              "then": {
                "required": [
                  "referencing"
                ]
              }
            }
          }
        }
      ]
    },
    "coverageBase": {
      "description": "A Coverage, representing a mapping from a domain to sets of data values described by parameters.",
      "type": "object",
      "properties": {
        "type": {
          "const": "Coverage"
        },
        "id": {
          "type": "string"
        },
        "domainType": {
          "type": "string"
        },
        "domain": {
          "allOf": [
            {
              "type": [
                "string",
                "object"
              ]
            },
            {
              "if": {
                "type": "object"
              },
              "then": {
                "$ref": "#/definitions/domainBase"
              }
            }
          ]
        },
        "parameters": {
          "type": "object",
          "patternProperties": {
            ".+": {
              "$ref": "#/definitions/parameter"
            }
          }
        },
        "parameterGroups": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/parameterGroup"
          }
        },
        "ranges": {
          "type": "object",
          "patternProperties": {
            ".+": {
              "allOf": [
                {
                  "type": [
                    "string",
                    "object"
                  ]
                },
                {
                  "if": {
                    "type": "object"
                  },
                  "then": {
                    "properties": {
                      "type": {
                        "enum": [
                          "NdArray",
                          "TiledNdArray"
                        ]
                      }
                    },
                    "required": [
                      "type"
                    ]
                  }
                },
                {
                  "if": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "NdArray"
                      }
                    }
                  },
                  "then": {
                    "$ref": "#/definitions/ndArray"
                  }
                },
                {
                  "if": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "const": "TiledNdArray"
                      }
                    }
                  },
                  "then": {
                    "$ref": "#/definitions/tiledNdArray"
                  }
                }
              ]
            }
          }
        },
        "rangeAlternates": {
          "type": "object"
        }
      },
      "required": [
        "type",
        "domain",
        "ranges"
      ]
    },
    "coverageCollection": {
      "description": "A collection of coverage objects",
      "properties": {
        "type": {
          "const": "CoverageCollection"
        },
        "domainType": {
          "type": "string"
        },
        "parameters": {
          "type": "object",
          "patternProperties": {
            ".+": {
              "$ref": "#/definitions/parameter"
            }
          }
        },
        "parameterGroups": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/parameterGroup"
          }
        },
        "referencing": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/referenceSystemConnection"
          }
        },
        "coverages": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/coverageBase"
          }
        }
      },
      "required": [
        "type",
        "coverages"
      ],
      "allOf": [
        {
          "$comment": "If no parameters are present at collection level then each coverage must have their own",
          "if": {
            "not": {
              "required": [
                "parameters"
              ]
            }
          },
          "then": {
            "properties": {
              "coverages": {
                "items": {
                  "required": [
                    "parameters"
                  ]
                }
              }
            }
          }
        },
        {
          "$comment": "If no \"referencing\" member is present at collection level then each coverage domain must have its own",
          "if": {
            "not": {
              "required": [
                "referencing"
              ]
            }
          },
          "then": {
            "properties": {
              "coverages": {
                "items": {
                  "properties": {
                    "domain": {
                      "if": {
                        "type": "object"
                      },
                      "then": {
                        "required": [
                          "referencing"
                        ]
                      }
                    }
                  }
                }
              }
            }
          }
        }
      ]
    },
    "domain": {
      "allOf": [
        {
          "$ref": "#/definitions/domainBase"
        },
        {
          "required": [
            "referencing"
          ]
        }
      ]
    },
    "domainBase": {
      "description": "A Domain, which defines a set of positions and their extent in one or more referencing systems",
      "type": "object",
      "properties": {
        "type": {
          "const": "Domain"
        },
        "domainType": {
          "type": "string"
        },
        "axes": {
          "type": "object",
          "description": "Set of Axis objects, keyed by axis identifier",
          "patternProperties": {
            ".+": {
              "$ref": "#/definitions/anyAxis"
            }
          }
        },
        "referencing": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/referenceSystemConnection"
          }
        }
      },
      "required": [
        "type",
        "axes"
      ],
      "dependencies": {
        "domainType": {
          "allOf": [
            {
              "if": {
                "properties": {
                  "domainType": {
                    "const": "Grid"
                  }
                }
              },
              "then": {
                "description": "Grid domain: x and y are required, z and t optional",
                "properties": {
                  "axes": {
                    "properties": {
                      "x": {
                        "$ref": "#/definitions/numericAxis"
                      },
                      "y": {
                        "$ref": "#/definitions/numericAxis"
                      },
                      "z": {
                        "$ref": "#/definitions/numericAxis"
                      },
                      "t": {
                        "$ref": "#/definitions/stringValuesAxis"
                      }
                    },
                    "required": [
                      "x",
                      "y"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "domainType": {
                    "const": "Trajectory"
                  }
                }
              },
              "then": {
                "description": "Trajectory domain: mandatory composite axis and optional z axis",
                "properties": {
                  "axes": {
                    "properties": {
                      "composite": {
                        "allOf": [
                          {
                            "$ref": "#/definitions/tupleValuesAxis"
                          },
                          {
                            "properties": {
                              "values": {
                                "items": {
                                  "$comment": "In a Trajectory, tuples always have 3 (txy) or 4 (txyz) values",
                                  "minItems": 3,
                                  "maxItems": 4
                                }
                              },
                              "coordinates": {
                                "enum": [
                                  [
                                    "t",
                                    "x",
                                    "y",
                                    "z"
                                  ],
                                  [
                                    "t",
                                    "x",
                                    "y"
                                  ]
                                ]
                              }
                            }
                          }
                        ]
                      },
                      "z": {
                        "$ref": "#/definitions/numericSingleValueAxis"
                      }
                    },
                    "required": [
                      "composite"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "domainType": {
                    "const": "VerticalProfile"
                  }
                }
              },
              "then": {
                "description": "Vertical Profile domain: mandatory x, y and z axis and optional t axis",
                "properties": {
                  "axes": {
                    "properties": {
                      "x": {
                        "$ref": "#/definitions/numericSingleValueAxis"
                      },
                      "y": {
                        "$ref": "#/definitions/numericSingleValueAxis"
                      },
                      "z": {
                        "$ref": "#/definitions/numericAxis"
                      },
                      "t": {
                        "$ref": "#/definitions/stringSingleValueAxis"
                      }
                    },
                    "required": [
                      "x",
                      "y",
                      "z"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "domainType": {
                    "const": "Point"
                  }
                }
              },
              "then": {
                "description": "Point domain: mandatory x and y axis, optional z and t axis",
                "properties": {
                  "axes": {
                    "properties": {
                      "x": {
                        "$ref": "#/definitions/numericSingleValueAxis"
                      },
                      "y": {
                        "$ref": "#/definitions/numericSingleValueAxis"
                      },
                      "z": {
                        "$ref": "#/definitions/numericSingleValueAxis"
                      },
                      "t": {
                        "$ref": "#/definitions/stringSingleValueAxis"
                      }
                    },
                    "required": [
                      "x",
                      "y"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "domainType": {
                    "const": "PointSeries"
                  }
                }
              },
              "then": {
                "description": "PointSeries domain: mandatory x, y and t axis, optional z axis",
                "properties": {
                  "axes": {
                    "properties": {
                      "x": {
                        "$ref": "#/definitions/numericSingleValueAxis"
                      },
                      "y": {
                        "$ref": "#/definitions/numericSingleValueAxis"
                      },
                      "z": {
                        "$ref": "#/definitions/numericSingleValueAxis"
                      },
                      "t": {
                        "$ref": "#/definitions/stringValuesAxis"
                      }
                    },
                    "required": [
                      "x",
                      "y",
                      "t"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "domainType": {
                    "const": "MultiPoint"
                  }
                }
              },
              "then": {
                "description": "MultiPoint domain: mandatory composite axis, optional t axis",
                "properties": {
                  "axes": {
                    "properties": {
                      "composite": {
                        "allOf": [
                          {
                            "$ref": "#/definitions/tupleValuesAxis"
                          },
                          {
                            "properties": {
                              "values": {
                                "items": {
                                  "$comment": "In a MultiPoint, tuples always have 2 (xy) or 3 values (xyz)",
                                  "minItems": 2,
                                  "maxItems": 3
                                }
                              },
                              "coordinates": {
                                "enum": [
                                  [
                                    "x",
                                    "y",
                                    "z"
                                  ],
                                  [
                                    "x",
                                    "y"
                                  ]
                                ]
                              }
                            }
                          }
                        ]
                      },
                      "t": {
                        "$ref": "#/definitions/stringSingleValueAxis"
                      }
                    },
                    "required": [
                      "composite"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "domainType": {
                    "const": "MultiPointSeries"
                  }
                }
              },
              "then": {
                "description": "MultiPointSeries domain: mandatory composite and t axes",
                "properties": {
                  "axes": {
                    "properties": {
                      "composite": {
                        "allOf": [
                          {
                            "$ref": "#/definitions/tupleValuesAxis"
                          },
                          {
                            "properties": {
                              "values": {
                                "items": {
                                  "$comment": "In a MultiPointSeries, tuples always have 2 (xy) or 3 values (xyz)",
                                  "minItems": 2,
                                  "maxItems": 3
                                }
                              },
                              "coordinates": {
                                "enum": [
                                  [
                                    "x",
                                    "y",
                                    "z"
                                  ],
                                  [
                                    "x",
                                    "y"
                                  ]
                                ]
                              }
                            }
                          }
                        ]
                      },
                      "t": {
                        "$ref": "#/definitions/stringValuesAxis"
                      }
                    },
                    "required": [
                      "composite",
                      "t"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "domainType": {
                    "const": "Section"
                  }
                }
              },
              "then": {
                "description": "Section domain: mandatory composite and z axes",
                "properties": {
                  "axes": {
                    "properties": {
                      "composite": {
                        "allOf": [
                          {
                            "$ref": "#/definitions/tupleValuesAxis"
                          },
                          {
                            "properties": {
                              "values": {
                                "items": {
                                  "$comment": "In a Section, tuples always have 3 values (txy)",
                                  "minItems": 3,
                                  "maxItems": 3
                                }
                              },
                              "coordinates": {
                                "const": [
                                  "t",
                                  "x",
                                  "y"
                                ]
                              }
                            }
                          }
                        ]
                      },
                      "z": {
                        "$ref": "#/definitions/numericAxis"
                      }
                    },
                    "required": [
                      "composite",
                      "z"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "domainType": {
                    "const": "Polygon"
                  }
                }
              },
              "then": {
                "description": "Polygon domain: mandatory composite axis, optional z and t axes",
                "properties": {
                  "axes": {
                    "properties": {
                      "composite": {
                        "allOf": [
                          {
                            "$ref": "#/definitions/polygonValuesAxis"
                          },
                          {
                            "properties": {
                              "values": {
                                "$comment": "There can only be one polygon in the axis",
                                "maxItems": 1
                              },
                              "coordinates": {
                                "const": [
                                  "x",
                                  "y"
                                ]
                              }
                            }
                          }
                        ]
                      },
                      "z": {
                        "$ref": "#/definitions/numericSingleValueAxis"
                      },
                      "t": {
                        "$ref": "#/definitions/stringSingleValueAxis"
                      }
                    },
                    "required": [
                      "composite"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "domainType": {
                    "const": "PolygonSeries"
                  }
                }
              },
              "then": {
                "description": "PolygonSeries domain: mandatory composite axis, optional z and t axes",
                "properties": {
                  "axes": {
                    "properties": {
                      "composite": {
                        "allOf": [
                          {
                            "$ref": "#/definitions/polygonValuesAxis"
                          },
                          {
                            "properties": {
                              "values": {
                                "$comment": "There can only be one polygon in the axis",
                                "maxItems": 1
                              },
                              "coordinates": {
                                "const": [
                                  "x",
                                  "y"
                                ]
                              }
                            }
                          }
                        ]
                      },
                      "z": {
                        "$ref": "#/definitions/numericSingleValueAxis"
                      },
                      "t": {
                        "$ref": "#/definitions/stringValuesAxis"
                      }
                    },
                    "required": [
                      "composite"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "domainType": {
                    "const": "MultiPolygon"
                  }
                }
              },
              "then": {
                "description": "MultiPolygon domain: mandatory composite axis, optional z and t axes",
                "properties": {
                  "axes": {
                    "properties": {
                      "composite": {
                        "allOf": [
                          {
                            "$ref": "#/definitions/polygonValuesAxis"
                          },
                          {
                            "properties": {
                              "coordinates": {
                                "const": [
                                  "x",
                                  "y"
                                ]
                              }
                            }
                          }
                        ]
                      },
                      "z": {
                        "$ref": "#/definitions/numericSingleValueAxis"
                      },
                      "t": {
                        "$ref": "#/definitions/stringSingleValueAxis"
                      }
                    },
                    "required": [
                      "composite"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            },
            {
              "if": {
                "properties": {
                  "domainType": {
                    "const": "MultiPolygonSeries"
                  }
                }
              },
              "then": {
                "description": "MultiPolygonSeries domain: mandatory composite axis, optional z and t axes",
                "properties": {
                  "axes": {
                    "properties": {
                      "composite": {
                        "allOf": [
                          {
                            "$ref": "#/definitions/polygonValuesAxis"
                          },
                          {
                            "properties": {
                              "coordinates": {
                                "const": [
                                  "x",
                                  "y"
                                ]
                              }
                            }
                          }
                        ]
                      },
                      "z": {
                        "$ref": "#/definitions/numericSingleValueAxis"
                      },
                      "t": {
                        "$ref": "#/definitions/stringValuesAxis"
                      }
                    },
                    "required": [
                      "composite"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            }
          ]
        }
      }
    },
    "i18n": {
      "type": "object",
      "description": "Object representing an internationalised string where keys are BCP 47 language tags.",
      "patternProperties": {
        "^(((([A-Za-z]{2,3}(-([A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-([A-Za-z]{4}))?(-([A-Za-z]{2}|[0-9]{3}))?(-([A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-([0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*))$": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "ndArray": {
      "type": "object",
      "description": "Object representing a multidimensional (>= 0D) array with named axes, encoded as a flat one-dimensional array in row-major order",
      "properties": {
        "type": {
          "const": "NdArray"
        },
        "dataType": {
          "enum": [
            "float",
            "integer",
            "string"
          ]
        },
        "shape": {
          "type": "array",
          "items": {
            "type": "number"
          }
        },
        "axisNames": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "uniqueItems": true
        },
        "values": {
          "type": "array",
          "minItems": 1
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "dataType": {
                "const": "float"
              }
            }
          },
          "then": {
            "properties": {
              "values": {
                "items": {
                  "type": [
                    "number",
                    "null"
                  ]
                }
              }
            }
          }
        },
        {
          "if": {
            "properties": {
              "dataType": {
                "const": "integer"
              }
            }
          },
          "then": {
            "properties": {
              "values": {
                "items": {
                  "type": [
                    "integer",
                    "null"
                  ]
                }
              }
            }
          }
        },
        {
          "if": {
            "properties": {
              "dataType": {
                "const": "string"
              }
            }
          },
          "then": {
            "properties": {
              "values": {
                "items": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          }
        },
        {
          "if": {
            "anyOf": [
              {
                "properties": {
                  "values": {
                    "minItems": 2
                  }
                }
              },
              {
                "properties": {
                  "shape": {
                    "minItems": 1
                  }
                },
                "required": [
                  "shape"
                ]
              },
              {
                "properties": {
                  "axisNames": {
                    "minItems": 1
                  }
                },
                "required": [
                  "axisNames"
                ]
              }
            ]
          },
          "then": {
            "properties": {
              "shape": {
                "minItems": 1
              },
              "axisNames": {
                "minItems": 1
              }
            },
            "required": [
              "shape",
              "axisNames"
            ]
          }
        }
      ],
      "required": [
        "type",
        "dataType",
        "values"
      ]
    },
    "numericAxis": {
      "description": "Simple axis with numeric values",
      "if": {
        "required": [
          "values"
        ]
      },
      "then": {
        "$ref": "#/definitions/numericValuesAxis"
      },
      "else": {
        "$ref": "#/definitions/numericRegularlySpacedAxis"
      }
    },
    "numericRegularlySpacedAxis": {
      "description": "A regularly-spaced numeric axis",
      "properties": {
        "start": {
          "type": "number"
        },
        "stop": {
          "type": "number"
        },
        "num": {
          "type": "integer",
          "minimum": 1
        }
      },
      "required": [
        "start",
        "stop",
        "num"
      ],
      "additionalProperties": false
    },
    "numericSingleValueAxis": {
      "description": "Axis defined by single numeric value",
      "allOf": [
        {
          "$ref": "#/definitions/numericValuesAxis"
        },
        {
          "properties": {
            "values": {
              "maxItems": 1
            }
          }
        }
      ]
    },
    "numericValuesAxis": {
      "description": "Axis defined by list of numeric axis values and optional bounds",
      "allOf": [
        {
          "$ref": "#/definitions/valuesAxisBase"
        },
        {
          "properties": {
            "values": {
              "items": {
                "type": "number"
              }
            },
            "bounds": {
              "items": {
                "type": "number"
              }
            }
          },
          "additionalProperties": false
        }
      ]
    },
    "observedProperty": {
      "type": "object",
      "description": "A definition of the quantity being measured.",
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "$ref": "#/definitions/i18n"
        },
        "description": {
          "$ref": "#/definitions/i18n"
        },
        "categories": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "label": {
                "$ref": "#/definitions/i18n"
              },
              "description": {
                "$ref": "#/definitions/i18n"
              }
            },
            "required": [
              "id",
              "label"
            ]
          },
          "minItems": 1
        }
      },
      "required": [
        "label"
      ]
    },
    "parameter": {
      "type": "object",
      "description": "Represents metadata about the values of the coverage",
      "properties": {
        "id": {
          "type": "string"
        },
        "type": {
          "description": "Type of the parameter object, must be \"Parameter\"",
          "const": "Parameter"
        },
        "description": {
          "$ref": "#/definitions/i18n"
        },
        "observedProperty": {
          "$ref": "#/definitions/observedProperty"
        },
        "unit": {
          "$ref": "#/definitions/unit"
        },
        "categoryEncoding": {
          "type": "object",
          "description": "Maps IDs of categories in the observedProperty to range values",
          "patternProperties": {
            ".+": {
              "oneOf": [
                {
                  "type": "integer"
                },
                {
                  "type": "array",
                  "items": {
                    "type": "integer"
                  },
                  "minItems": 1,
                  "uniqueItems": true
                }
              ]
            }
          }
        }
      },
      "required": [
        "type",
        "observedProperty"
      ]
    },
    "parameterGroup": {
      "type": "object",
      "description": "Represents logical groups of parameters",
      "properties": {
        "type": {
          "description": "Type of the parameter group object, must be \"ParameterGroup\"",
          "const": "ParameterGroup"
        },
        "id": {
          "type": "string"
        },
        "label": {
          "$ref": "#/definitions/i18n"
        },
        "description": {
          "$ref": "#/definitions/i18n"
        },
        "observedProperty": {
          "$ref": "#/definitions/observedProperty"
        },
        "members": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "minItems": 1,
          "uniqueItems": true
        }
      },
      "required": [
        "type",
        "members"
      ],
      "anyOf": [
        {
          "required": [
            "label"
          ]
        },
        {
          "required": [
            "observedProperty"
          ]
        }
      ]
    },
    "polygonValuesAxis": {
      "description": "Polygon-based axis",
      "allOf": [
        {
          "$ref": "#/definitions/valuesAxisBase"
        },
        {
          "properties": {
            "dataType": {
              "const": "polygon"
            },
            "values": {
              "items": {
                "description": "A GeoJSON polygon",
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "description": "The inner array: the coordinates themselves",
                    "type": "array",
                    "items": {
                      "type": "number"
                    },
                    "minItems": 2
                  },
                  "minItems": 1
                },
                "minItems": 1
              }
            },
            "coordinates": {}
          },
          "required": [
            "dataType",
            "values",
            "coordinates"
          ],
          "additionalProperties": false
        }
      ]
    },
    "primitiveValuesAxis": {
      "description": "Validates any axis with primitive values",
      "allOf": [
        {
          "$ref": "#/definitions/valuesAxisBase"
        },
        {
          "$comment": "This redundant branch exists to fail early with succinct errors",
          "properties": {
            "values": {
              "items": {
                "oneOf": [
                  {
                    "type": "number"
                  },
                  {
                    "type": "string"
                  }
                ]
              }
            }
          }
        },
        {
          "if": {
            "properties": {
              "values": {
                "items": {
                  "type": "number"
                }
              }
            }
          },
          "then": {
            "$ref": "#/definitions/numericValuesAxis"
          },
          "else": {
            "$ref": "#/definitions/stringValuesAxis"
          }
        }
      ]
    },
    "referenceSystem": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string"
        }
      },
      "required": [
        "type"
      ],
      "allOf": [
        {
          "if": {
            "properties": {
              "type": {
                "const": "TemporalRS"
              }
            }
          },
          "then": {
            "description": "Temporal reference system",
            "properties": {
              "calendar": {
                "type": "string"
              },
              "timeScale": {
                "type": "string"
              }
            },
            "required": [
              "calendar"
            ]
          }
        },
        {
          "if": {
            "properties": {
              "type": {
                "const": "IdentifierRS"
              }
            }
          },
          "then": {
            "description": "An identifier-based reference system",
            "properties": {
              "id": {
                "type": "string"
              },
              "label": {
                "$ref": "#/definitions/i18n"
              },
              "description": {
                "$ref": "#/definitions/i18n"
              },
              "targetConcept": {
                "$ref": "#/definitions/targetConcept"
              },
              "identifiers": {
                "type": "object",
                "patternProperties": {
                  ".+": {
                    "$ref": "#/definitions/targetConcept"
                  }
                }
              }
            },
            "required": [
              "targetConcept"
            ]
          }
        }
      ]
    },
    "referenceSystemConnection": {
      "description": "Reference System Connection object: connects coordinates to reference systems",
      "type": "object",
      "properties": {
        "coordinates": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "minItems": 1
        },
        "system": {
          "$ref": "#/definitions/referenceSystem"
        }
      },
      "required": [
        "coordinates",
        "system"
      ]
    },
    "stringSingleValueAxis": {
      "description": "Axis defined by single string value",
      "allOf": [
        {
          "$ref": "#/definitions/stringValuesAxis"
        },
        {
          "properties": {
            "values": {
              "maxItems": 1
            }
          }
        }
      ]
    },
    "stringValuesAxis": {
      "description": "Simple axis with string values (e.g. time strings)",
      "allOf": [
        {
          "$ref": "#/definitions/valuesAxisBase"
        },
        {
          "properties": {
            "values": {
              "items": {
                "type": "string"
              }
            },
            "bounds": {
              "items": {
                "type": "string"
              }
            }
          },
          "additionalProperties": false
        }
      ]
    },
    "targetConcept": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "$ref": "#/definitions/i18n"
        },
        "description": {
          "$ref": "#/definitions/i18n"
        }
      },
      "required": [
        "label"
      ]
    },
    "tiledNdArray": {
      "type": "object",
      "description": "Object representing a multidimensional (>= 1D) array with named axes split up into sets of linked NdArray documents",
      "properties": {
        "type": {
          "const": "TiledNdArray"
        },
        "dataType": {
          "enum": [
            "float",
            "integer",
            "string"
          ]
        },
        "shape": {
          "type": "array",
          "items": {
            "type": "number"
          },
          "minItems": 1
        },
        "axisNames": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "minItems": 1,
          "uniqueItems": true
        },
        "tileSets": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "properties": {
              "tileShape": {
                "type": "array",
                "items": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "minItems": 1
              },
              "urlTemplate": {
                "type": "string",
                "description": "RFC 6570 Level 1 URI template"
              }
            },
            "required": [
              "tileShape",
              "urlTemplate"
            ]
          }
        }
      },
      "required": [
        "type",
        "dataType",
        "shape",
        "axisNames",
        "tileSets"
      ]
    },
    "tupleValuesAxis": {
      "description": "Tuple-based axis",
      "allOf": [
        {
          "$ref": "#/definitions/valuesAxisBase"
        },
        {
          "properties": {
            "dataType": {
              "const": "tuple"
            },
            "values": {
              "items": {
                "description": "A tuple of axis values (numbers or strings)",
                "type": "array",
                "items": {
                  "type": [
                    "number",
                    "string"
                  ]
                },
                "minItems": 2
              }
            },
            "coordinates": {}
          },
          "required": [
            "dataType",
            "values",
            "coordinates"
          ],
          "additionalProperties": false
        }
      ]
    },
    "unit": {
      "type": "object",
      "description": "The units of measure",
      "properties": {
        "id": {
          "type": "string"
        },
        "label": {
          "$ref": "#/definitions/i18n"
        },
        "symbol": {
          "allOf": [
            {
              "type": [
                "string",
                "object"
              ]
            },
            {
              "if": {
                "type": "object"
              },
              "then": {
                "properties": {
                  "type": {
                    "type": "string"
                  },
                  "value": {
                    "type": "string"
                  }
                },
                "required": [
                  "type",
                  "value"
                ]
              }
            }
          ]
        }
      },
      "anyOf": [
        {
          "required": [
            "label"
          ]
        },
        {
          "required": [
            "symbol"
          ]
        }
      ]
    },
    "valuesAxis": {
      "description": "Validates any values-based axis",
      "allOf": [
        {
          "$ref": "#/definitions/valuesAxisBase"
        },
        {
          "if": {
            "not": {
              "required": [
                "dataType"
              ]
            }
          },
          "then": {
            "$ref": "#/definitions/primitiveValuesAxis"
          }
        }
      ],
      "dependencies": {
        "dataType": {
          "allOf": [
            {
              "if": {
                "properties": {
                  "dataType": {
                    "const": "tuple"
                  }
                }
              },
              "then": {
                "$ref": "#/definitions/tupleValuesAxis"
              }
            },
            {
              "if": {
                "properties": {
                  "dataType": {
                    "const": "polygon"
                  }
                }
              },
              "then": {
                "$ref": "#/definitions/polygonValuesAxis"
              }
            }
          ]
        }
      }
    },
    "valuesAxisBase": {
      "$comment": "Base schema for values-based axis schemas",
      "properties": {
        "dataType": {
          "type": "string",
          "not": {
            "const": "primitive"
          }
        },
        "values": {
          "type": "array",
          "minItems": 1,
          "uniqueItems": true
        },
        "coordinates": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "minItems": 2
        },
        "bounds": {
          "description": "Optional axis bounds. Must be twice as long (and same data type) as \"values\"",
          "type": "array",
          "minItems": 2
        }
      },
      "required": [
        "values"
      ]
    }
  }
}
