class EntityParser
  constructor: ->
    @classes =
      Action:   require  "../model/action"
      Resource: require  "../model/resource"
      Api:      require  "../model/api"
      Type:     require  "../model/type"
      Schema:   require  "../model/schema"

    @schema =
      Api:
        title:       {type: "Primitive"}
        description: {type: "Primitive"}
        resources:   {type: "Map", options: { elems: "Resource"  }}
        types:       {type: "Map", options: { elems: "Type"      }}
        protocols:   {type: "Map", options: { elems: "Object"    }}
        actions:     {type: "Map", options: { elems: "Action"    }}
        events:      {type: "Map", options: { elems: "Event"     }}

      Action:
        title:       {type: "Primitive"}
        description: {type: "Primitive"}
        params:      {type: "Schema"}
        returns:     {type: "Schema"}

      Event:
        title:       {type: "Primitive"}
        description: {type: "Primitive"}
        params:      {type: "Schema"}
        returns:     {type: "Schema"}

      Resource:
        title:       {type: "Primitive"}
        description: {type: "Primitive"}
        type:        {type: "Primitive"}
        resources:   {type: "Map", options: {elems: "Resource"}}
        protocols:   {type: "Object"}
        actions:     {type: "Map", options: {elems: "Action"  }}
        events:      {type: "Map", options: { elems: "Event"  }}

      Type:
        title:       {type: "Primitive"}
        description: {type: "Primitive"}
        schema:      {type: "Schema"}

  applySchema: (object, type, options = {}) ->
    if type is "Schema"
      new @classes.Schema(object)
    else if type in ["Object", "Primitive"]
      object
    else if type is "Map"
      res = {}
      for k, v of object
        properties = @applySchema(v, options.elems, {})
        klass = @classes[options.elems]
        res[k] = new klass(properties)
        res[k].name = k
      res
    else if schema = @schema[type]
      res = {}
      for k, decl of schema
        if object[k]
          res[k] = @applySchema(object[k], decl.type, decl.options)
          if klass = @classes[decl.type]
            res[k] = new klass(res[k])
        else
          if decl.type is "Map"
            res[k] = {}
      res
    else
      throw "Unexpected Parser Error. Execution should never get here."

  parseApi: (object) ->
    new @classes.Api(@applySchema(object, "Api", {}))

module.exports = EntityParser