// License: LGPL-3.0-or-later
/* A simple module for dealing with ajax-based resources in viewscript
	*
	*
	* Define a 'resource object' in appl that has these properties
	*   resource_name: 'donations' (plural name that matches the model)
	*   path_prefix: '/' (optional, defaults to empty string, or relative path)
	*   query: object of parameters to use for indexing (eg search queries)
	*   after_action: function callback run after the request (where action is fetch, index, etc)
	*   after_action_failure: callback for failed requests (where action is fetch, index, etc)
	*
	* Call the ajax functions like this:
	* in js:
	*   appl.ajax.index(appl.resource_object)
	*   appl.ajax.create(appl.donations, {amount: 420})
	* in viewscript in the dom:
	*   ajax.index resource_object
	*   ajax.create donations form_object
	*/

var request = require('../common/client')

var restful_resource = {}
module.exports = restful_resource


appl.def('ajax', {
	index: function(prop, node) {
		var resource = appl.vs(prop) || {}
		var name = resource.resource_name || prop
		var path = resource.path_prefix || ''
		before_request(prop)
		return new Promise(function(resolve, reject) {
			request.get(path + name).query(resource.query)
				.end(function(err, resp) {
					var tmp = resource.data
					after_request(prop, err, resp)
					if(resp.ok) {
						if(resource.query && resource.query.page > 1 && resource.concat_data) {
							appl.def(prop + '.data', tmp.concat(resp.body.data))
						}
						resolve(resp)
					} else {
						reject(resp)
					}
				})
		})
	},

	fetch: function(prop, id, node) {
		var resource = appl.vs(prop) || {}
		var name = resource.resource_name || prop
		var path = resource.path_prefix || ''
		before_request(prop)
		return new Promise(function(resolve, reject) {
			request.get(path + name + '/' + id).query(resource.query)
				.end(function(err, resp) {
					after_request(prop, err, resp)
					if(resp.ok) resolve(resp)
					else reject(resp)
				})
		})
	},

	create: function(prop, form_obj, node) {
		var resource = appl.vs(prop) || {}
		var name = resource.resource_name || prop
		var path = resource.path_prefix || ''
		before_request(prop)
		return new Promise(function(resolve, reject) {
			request.post(path + name).send(nested_obj(name, form_obj))
				.end(function(err, resp) {
					after_request(prop, err, resp)
					if(resp.ok) resolve(resp)
					else reject(resp)
				})
		})
	},

	update: function(prop, id, form_obj, node) {
		var resource = appl.vs(prop) || {}
		var name = resource.resource_name || prop
		var path = resource.path_prefix || ''
		before_request(prop)
		return new Promise(function(resolve, reject) {
			request.put(path + name + '/' + id).send(nested_obj(name, form_obj))
			.end(function(err, resp) {
				after_request(prop, err, resp)
				if(resp.ok) resolve(resp)
				else reject(resp)
			})
		})
	},

	del: function(prop, id, node) {
		var resource = appl.vs(prop) || {}
		var path = (resource.path_prefix || '') + (resource.resource_name || prop)
		before_request(prop)
		return new Promise(function(resolve, reject) {
			request.del(path + '/' + id)
				.end(function(err, resp) {
					after_request(prop, err, resp)
					if(resp.ok) resolve(resp)
					else reject(resp)
				})
		})
	}
})


// Given a viewscript property, set some state before every request.
// Eg. appl.ajax.index('donations') will cause appl.donations.loading to be
// true before the request finishes
function before_request(prop) {
	appl.def(prop + '.loading', true)
	appl.def(prop + '.error', '')
}


// Set some data after each request.
function after_request(prop, err, resp) {
	appl.def(prop + '.loading', false)
	if(resp.ok) {
		appl.def(prop, resp.body)
	} else {
		appl.def(prop + '.error', resp.body)
	}
}


// Simply return an object nested under 'name'
// Will singularize the given name if plural
// eg: given 'donations' and {amount: 111}, return {donation: {amount: 111}}
function nested_obj(name, child_obj) {
	var parent_obj = {}
	parent_obj[appl.to_singular(name)] = child_obj
	return parent_obj
}