 class SchemaManager
+
+  @urnize: (identifier) ->
+    if identifier.indexOf(":") == -1
+      "urn:json:#{identifier}"
+    else
+      identifier
+
+  @normalize: (schema) ->
+    # TODO: make sure this is idempotent, just in case it gets called twice
+    # on the same schema.  Also: do try not to call this twice on the same
+    # schema
+    # TODO LATER: make this non-destructive
+    schema.id = @urnize(schema.id)
+    @top_level_ids(schema.properties, schema.id)
+    @normalize_properties(schema.properties, schema.id)
+
+  @top_level_ids: (properties, namespace) ->
+    for name, schema of properties
+      if schema.id
+        if schema.id.indexOf("#") == 0
+          schema.id = "#{namespace}#{schema.id}"
+      else
+        schema.id = "#{namespace}##{name}"
+
+  @normalize_properties: (properties, namespace) ->
+    for name, definition of properties
+      @normalize_schema(name, definition, namespace)
+
+  @normalize_schema: (name, schema, namespace) ->
+    # TODO: assess whether we care at all about additional attrs:
+    # * disallow
+    # * dependencies
+
+    if schema.$ref
+      # This schema is a reference to another schema
+      @normalize_ref(schema, namespace)
+    else if schema.extends?
+      # This schema extends (a.k.a. inherits from) another schema
+      @normalize_ref(schema.extends, namespace)
+    else if schema.type == "array"
+      @normalize_array(schema, namespace)
+    else if schema.type == "object"
+      @normalize_object(schema, namespace)
+
+    if schema.properties
+      @normalize_properties(schema.properties, namespace)
+
+
+  @normalize_extends: (schema, namespace) ->
+    # TODO: "extends" can be a schema or an array of schemas
+    if schema.$ref
+      @normalize_ref(schema, namespace)
+
+  @normalize_array: (schema, namespace) ->
+    if schema.items?.$ref
+      @normalize_ref(schema.items, namespace)
+    if schema.additionalItems?.$ref
+      @normalize_ref(schema.additionalItems, namespace)
+
+  @normalize_object: (schema, namespace) ->
+    if schema.additionalProperties?.$ref
+      @normalize_ref(schema.additionalProperties, namespace)
+
+  @normalize_ref: (schema, namespace) ->
+    index = schema.$ref.indexOf("#")
+    if index == 0
+      schema.$ref = "#{namespace}#{schema.$ref}"
+    else if index != -1
+      schema.$ref = @urnize(schema.$ref)
 
   @is_primitive: (type) ->
     for name in ["string", "number", "boolean"]
       return true if type == name
     return false
+
 
   constructor: (@schemas...) ->
     @names = {} # the part after the fragment identifier


  register_schema: (schema) ->
    for name, definition of schema.properties
      @names[name] = definition
      if definition.id
        @ids[definition.id] = definition
      if definition.mediaType
        @media_types[definition.mediaType] = definition


module.exports = SchemaManager

    @media_types = {}

    for schema in @schemas
      SchemaManager.normalize(schema)
      @register_schema(schema)

  find: (options) ->
