{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "protocol",
  "definitions": {
    "dataType": {
      "oneOf":[
        {"$ref": "#/definitions/simpleFieldType"},
        {"$ref": "#/definitions/container"},
        {"$ref": "#/definitions/switch"},
        {"$ref": "#/definitions/array"},
        {"$ref": "#/definitions/buffer"},
        {"$ref": "#/definitions/count"},
        {"$ref": "#/definitions/option"},
        {"$ref": "#/definitions/bitfield"},
        {"$ref": "#/definitions/entityMetadataLoop"},
        {"$ref": "#/definitions/entityMetadataItem"},
        {"$ref": "#/definitions/mapper"},
        {"$ref": "#/definitions/pstring"}
      ]
    },
    "simpleFieldType": {
      "type": "string",
      "pattern": "^[0-9a-zA-Z_]+$"
    },
    "container": {
      "type": "array",
      "items":[
        {"enum":["container"]},
        {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "anon": { "type": "boolean" },
              "name": {"$ref": "#/definitions/fieldName"},
              "type": {"$ref": "#/definitions/dataType"}
            },
            "oneOf": [
              { "required": ["anon"] },
              { "required": ["name"] }
            ],
            "required": [
              "type"
            ],
            "additionalProperties": false
          },
          "additionalItems": false
        }
      ],
      "additionalItems": false
    },
    "count": {
      "type": "array",
      "items":[
        {"enum":["count"]},
        {
          "type": "object",
          "properties": {
            "countFor": {"$ref":"#/definitions/contextualizedFieldName"},
            "type": {"$ref": "#/definitions/dataType"}
          },
          "required": ["countFor", "type"],
          "additionalProperties": false
        }
      ],
      "additionalItems": false
    },
    "option": {
      "type": "array",
      "items":[
        {"enum":["option"]},
        {"$ref": "#/definitions/dataType"}
      ],
      "additionalItems": false
    },
    "pstring": {
      "type": "array",
      "items":[
        {"enum":["pstring"]},
        {
          "type":"object",
          "properties":{
            "countType": {"$ref": "#/definitions/dataType"}
          },
          "additionalProperties": false,
          "required":["countType"]
        }
      ],
      "additionalItems": false
    },
    "switch":{
      "type": "array",
      "items":[
        {"enum":["switch"]},
        {
          "type":"object",
          "properties": {
            "compareTo":{"$ref": "#/definitions/contextualizedFieldName"},
            "fields":{
              "type":"object",
              "patternProperties" : {
                "^[-a-zA-Z0-9 _]+$":{"$ref": "#/definitions/dataType"}
              },
              "additionalProperties": false
            },
            "default":{"$ref": "#/definitions/dataType"}
          },
          "required":["compareTo","fields"],
          "additionalProperties": false
        }
      ],
      "additionalItems": false
    },
    "mapper":{
      "type": "array",
      "items":[
        {"enum":["mapper"]},
        {
          "type":"object",
          "properties": {
            "type":{"$ref": "#/definitions/dataType"},
            "mappings":{
              "type":"object",
              "patternProperties" : {
                "^[-a-zA-Z0-9 _]+$":{"$ref": "#/definitions/dataType"}
              },
              "additionalProperties": false
            }
          },
          "required":["type","mappings"],
          "additionalProperties": false
        }
      ],
      "additionalItems": false
    },
    "array":{
      "type":"array",
      "items":[
        {"enum":["array"]},
        {
          "oneOf":[
            {
              "type":"object",
              "properties":{
                "type": {"$ref": "#/definitions/dataType"},
                "countType": {"$ref": "#/definitions/dataType"}
              },
              "additionalProperties": false,
              "required":["type","countType"]
            },
            {
              "type":"object",
              "properties":{
                "type": {"$ref": "#/definitions/dataType"},
                "count": {"$ref": "#/definitions/dataTypeArgsCount"}
              },
              "additionalProperties": false,
              "required":["type","count"]
            }
          ]
        }
      ],
      "additionalItems": false
    },
    "buffer":{
      "type":"array",
      "items":[
        {"enum":["buffer"]},
        {
          "oneOf":[
            {
              "type": "object",
              "properties": {
                "countType": {"$ref": "#/definitions/dataType"}
              },
              "additionalProperties": false,
              "required": [
                "countType"
              ]
            },
            {
              "type": "object",
              "properties": {
                "count": {"$ref": "#/definitions/dataTypeArgsCount"}
              },
              "additionalProperties": false,
              "required": [
                "count"
              ]
            }
          ]
        }
      ]
    },
    "bitfield":{
      "type": "array",
      "items": [
        { "enum": ["bitfield"] },
        {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "name": {"$ref": "#/definitions/fieldName"},
              "size": {"type": "number"},
              "signed": {"type": "boolean"}
            },
            "required": [
              "name",
              "size",
              "signed"
            ],
            "additionalProperties": false
          },
          "additionalItems": false
        }
      ],
      "additionalItems": false
    },
    "entityMetadataLoop":{
      "type": "array",
      "items": [
        { "enum": ["entityMetadataLoop"] },
        {
          "type": "object",
          "properties": {
            "endVal": { "type": "number" },
            "type": {"$ref": "#/definitions/dataType"}
          },
          "required": ["endVal", "type"],
          "additionalProperties": false
        }
      ]
    },
    "entityMetadataItem":{
      "type": "array",
      "items": [
        { "enum": ["entityMetadataItem"] },
        {
          "type": "object",
          "properties": {
            "compareTo":{"$ref": "#/definitions/contextualizedFieldName"}
          },
          "required": ["compareTo"],
          "additionalProperties": false
        }
      ]
    },
    "contextualizedFieldName": {
      "type": "string",
      "pattern": "^(this\\.)?.+$"
    },
    "dataTypeArgsCount": {
      "oneOf": [
        {"$ref": "#/definitions/contextualizedFieldName"},
        {"type":"number"}
      ]
    },
    "fieldName": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_]+$"
    }
  },
  "type": "object",
  "properties":{
    "types":{
      "type": "object",
      "patternProperties": {
        "^[0-9a-zA-Z_]+$": {"$ref": "#/definitions/dataType"}
      },
      "additionalProperties": false
    }
  },
  "patternProperties": {
    "^(?!types)[a-zA-Z_]+$": {"$ref": "#"}
  },
  "additionalProperties": false
}
