<% var singularName = resource.name,

pluralName    = plural(singularName),
mixins        = {
  task: ["AttachmentUploading", "EventSubscription"],
  project: ["EventSubscription"]
},
skip          = { attachment: ["createOnTask"] },
formatComment = function formatComment(text, indentation) {
    var indent = Array(indentation + 1).join(" ")
    return text.trim().split("\n").map(function(line) {
        return indent + (line.length > 0 ? "# " : "#") + line
    }).join("\n")
}

function Action(action) {

var that = this
this.action = action
this.collection = action.collection == true
this.requiresData = action.method == "POST" || action.method == "PUT"
this.isInstanceAction = (action.method == "PUT" || action.method == "DELETE")
this.method = action.method
this.methodName = snake(action.name)
this.clientMethod = action.method.toLowerCase()
this.returnsUpdatedRecord = action.method == 'PUT' || action.comment.match(/Returns[a-z\W]+updated/) !== null
this.returnsNothing = action.comment.match(/Returns an empty/) !== null

// Params and idParams
var params = action.params || []
this.idParams = _.filter(params, function(p) { return p.type == "Id" })

// If it looks like an instance action but it's not, make it one
if (!this.isInstanceAction) {
    var mainIdParam = _.find(this.idParams, function(p) { return p.name == singularName })
    if (mainIdParam !== undefined && !action.name.match(/Id/)) {
        this.isInstanceAction = true
        this.mainIdParam = mainIdParam
    }
}

if (this.idParams.length == 1 &&
    action.path.match(/%d/) &&
    (action.name.match(/Id/) || (this.isInstanceAction && this.mainIdParam == undefined))) {
        var mainIdParam = this.idParams[0]
        this.mainIdParam = mainIdParam
        this.inferredReturnType = this.isInstanceAction ? 'self.class' : 'self'
}

if (mainIdParam !== undefined) {
    this.params = _.reject(params, function(p) { return p.name == mainIdParam.name })
} else {
    this.params = params
}

if (!this.inferredReturnType) {
    // Infer return type
    var name = action.path.match(/\/([a-zA-Z]+)$/)
    if (name !== null) {
        name = name[1]

        // Desugarize 'addProject' to 'project'
        var camelCaseTail = name.match(/.*([A-Z][a-z]+)$/)
        if (camelCaseTail !== null) { name = decap(camelCaseTail[1]) }

        name = single(name)

        var explicit = _.find(resources, function(p) { return p == name })

        if (name == singularName || name == 'parent' || name == 'children' || name.match(/^sub/) !== null) {
            this.inferredReturnType = this.isInstanceAction ? 'self.class' : 'self'
        } else if (explicit !== undefined) {
            this.inferredReturnType = cap(explicit)
        } else {
            this.inferredReturnType = 'Resource'
        }
    } else {
        this.inferredReturnType = 'Resource'
    }
}

// Endpoint path
this.path = _.reduce(this.idParams, function(acc, id) {
    var localName = that.mainIdParam == id ? "id" : id.name
    return acc.replace("\%d", "#{" + localName + "}")
}, action.path)

// Extra params (not in the URL) to be passed in the body of the call
this.extraParams = _.reject(this.params, function(p) {
    return that.path.match(new RegExp("#{" + p.name + "}"))
})

// Params processing
var paramsLocal = "data"
if (this.collection) { this.extraParams.push({ name: "per_page", apiParamName: "limit" }) }
if (this.extraParams.length > 0) {
    var paramNames = _.map(this.extraParams, function(p) { return (p.apiParamName || p.name) + ": " + p.name })
    if (this.requiresData) {
        var paramsProcessing = "with_params = data.merge(" + paramNames.join(", ") + ")"
        paramsLocal = "with_params"
    } else {
        var paramsProcessing = "params = { " + paramNames.join(", ") + " }"
        paramsLocal = "params"
    }
    paramsProcessing += ".reject { |_,v| v.nil? || Array(v).empty? }"
}

this.paramsProcessing = paramsProcessing
this.paramsLocal      = paramsLocal

// Method argument names
var argumentNames = Array()
if (!this.isInstanceAction) { argumentNames.push("client") }
if (this.mainIdParam !== undefined && !this.isInstanceAction) { argumentNames.push("id") }
_.forEach(this.params, function(param) {
    argumentNames.push(param.name + ":" + (param.required ? " required(\"" + param.name + "\")" : " nil"))
})
if (this.collection) { argumentNames.push("per_page: 20") }
if (this.method != 'DELETE')  { argumentNames.push("options: {}") }
if (this.requiresData)          { argumentNames.push("**data") }
this.argumentNames = argumentNames

// API request params
var requestParams = Array()
requestParams.push('"' + this.path + '"')
if (this.paramsProcessing || this.argumentNames.indexOf("**data") != -1) {
    var argument = this.requiresData ? "body" : "params"
    requestParams.push(argument + ": " + paramsLocal)
}
if (this.method != 'DELETE') { requestParams.push("options: options") }
this.requestParams = requestParams
this.documentation = this.renderDocumentation()

// Constructor
this.constructor = function(body) {
    var pre = '', post = ''
    var wrapWithParsing = function(body) {
        var pre = '', post = ''
        if (!that.returnsNothing) {
            pre = 'parse('
            post = ')' + (that.collection ? '' : '.first')
        }
        return pre + body + post
    }

    if (!that.returnsNothing) {
        if (that.isInstanceAction && that.returnsUpdatedRecord) {
            pre = "refresh_with("
            post = ')'
        } else {
            pre = that.collection ? "Collection.new(" : that.inferredReturnType + ".new("
            post = (that.collection ? ', type: ' + that.inferredReturnType : '') + ', client: client)'
        }
    } else { post = ' && true' }
    return pre + wrapWithParsing(body) + post
}

this.request = this.constructor("client." + this.clientMethod + "(" + this.requestParams.join(", ") + ")")

}

Action.prototype.renderDocumentation = function () {

var formatParamNotes = function(params) {
    var trimmed = _.flatten(_.map(params, function(p) {
        return _.map(p.notes, function(note) { return note.trim() })
    }))
    return (trimmed.length > 0 ? "\nNotes:\n\n" + trimmed.join("\n\n") : "")
}

var formatParam = function(p, name) {
    return (name !== undefined ? name : p.name) + " - [" + p.type + "] " + p.comment
}
var lines = _.map(this.params, function(p) { return formatParam(p) })
if (this.mainIdParam !== undefined && !this.isInstanceAction) { lines.unshift(formatParam(this.mainIdParam, "id")) }
if (this.collection) { lines.push("per_page - [Integer] the number of records to fetch per page.") }
if (this.method != 'DELETE') { lines.push("options - [Hash] the request I/O options.") }
if (this.requiresData) { lines.push("data - [Hash] the attributes to post.") }
return this.action.comment + "\n" + lines.join("\n") + formatParamNotes(this.params)

}

var actionsToSkip = skip || [] var actionsToGen = _.reject(resource.actions, function(action) {

return actionsToSkip.indexOf(action.name) != -1

})

var allActions = _.map(actionsToGen, function(action) { return new Action(action) }),

instanceActions = _.filter(allActions, function(action) { return action.isInstanceAction }),
classActions    = _.reject(allActions, function(action) { return action.isInstanceAction })

var mixinsToInclude = mixins || []

%>### WARNING: This file is auto-generated by the asana-api-meta repo. Do not ### edit it manually.

module Asana

module Resources

<%= formatComment(resource.comment, 4) %>

class <%= cap(singularName) %> < Resource

<% _.forEach(mixinsToInclude, function(mixin) { %>

include <%= mixin %>

<% }) %> <% _.forEach(resource.properties, function(property) { %>

attr_reader :<%= property.name %>

<% }) %>

class << self
  # Returns the plural name of the resource.
  def plural_name
    '<%= pluralName %>'
  end

<% _.forEach(classActions, function(action) { %> <%= formatComment(action.documentation, 8) %>

def <%= action.methodName %>(<%= action.argumentNames.join(", ") %>)

<% if (action.paramsProcessing) { %> <%= action.paramsProcessing %><% } %>

  <%= action.request %>
end

<% }) %> end <% _.forEach(instanceActions, function(action) { %> <%= formatComment(action.documentation, 6) %>

def <%= action.methodName %>(<%= action.argumentNames.join(", ") %>)

<% if (action.paramsProcessing) { %> <%= action.paramsProcessing %><% } %>

  <%= action.request %>
end

<% }) %>

  end
end

end