var angular = require('cla_angular');

$.fn.dataTable.defaults.autoWidth = false;

/**
 * A service to handle actions upon a datatable
 *
 *
 */

var moduleName = 'cla.core.datatable';
var module;
try {
	module = angular.module(moduleName);
}
catch (err) {
	module = angular.module(moduleName, []);
}

// manual instantiation to avoid unique instances being loaded and overwritten for multiple uses.
var instance = new TableService();
module.service('dtService', ['$resource', function ($resource) {
	instance.injectResource($resource);
	return instance;
}]);

// dependencies
function TableService() {
	var $resource = null;
	var service = {
		instances: [],
		register: register,
		get: function (index) {
			return this.instances[index];
		},
		injectResource: function ($res) {
			$resource = $res;
		}
	};

	// this object will be copied per registered instance of datatable
	var inst = {
		endpoint: '',
		resource: null,
		datatable: null,
		build: null, // overridden in table directive,

		columns: [],
		rows: [],
		filters: {},
		initial: {},

		per: null,
		info: null,
		keywords: null,

		setResource: setResource,
		dtInit: dtInit,
		redraw: redraw,
		fetch: fetch,
		perPage: perPage,
		paginate: paginate,
		search: search,
		reset: reset,
		download: download
	};

	return service;
	//////////////////

	/**
	 *
	 * @return {*}
	 */
	function register(id) {
		var instance = angular.copy(inst);

		if (!id) {
			service.instances.push(instance);
		} else {
			service.instances[id] = instance;
		}

		return instance;
	}

	/**
	 * set table data endpoint
	 *
	 * @param endpoint
	 */
	function setResource(endpoint) {
		this.endpoint = endpoint;
		this.resource = $resource('', {}, {
			query: {method: 'post', url: endpoint}
		});
	}

	/**
	 * initialise data-table
	 */
	function dtInit() {
		this.info = this.datatable.page.info();
	}

	/**
	 * redraw the table
	 */
	function redraw() {
		this.info = this.datatable.page.info();
		this.paginate(0);
	}

	/**
	 * fetch table data
	 *
	 * @param {object} data
	 * @param {function} [callback]
	 */
	function fetch(data, callback) {
		data = angular.merge({}, data, {filters: this.filters, initial: this.initial});

		this.resource.query(data).$promise.then(function (d) {
			if (callback) {
				callback(d);
			}
		});
	}

	/**
	 * set rows per page
	 *
	 * @param {integer} num
	 */
	function perPage(num) {
		this.per = num;
		this.datatable.page.len(num);
		this.redraw();
	}

	/**
	 * updates page number and redraws
	 *
	 * @param {integer} num
	 */
	function paginate(num) {
		this.datatable.page(num).draw('page');
		this.info = this.datatable.page.info();
	}

	/**
	 * updates the datatable with a search term
	 *
	 * @param {string} keywords
	 */
	function search(keywords) {
		this.keywords = keywords;
		this.datatable.search(keywords);
		this.redraw();
	}

	/**
	 * resets data-table properties
	 */
	function reset() {
		this.info = null;
		this.datatable.destroy();
		this.datatable = null;
		this.rows = [];
	}

	/**
	 * downloads the table data as a csv
	 */
	function download() {
		var form = document.createElement('form');
		form.setAttribute('method', 'post');
		form.setAttribute('action', this.endpoint + '/download');

		// add the initial attributes
		var initial = document.createElement('input');
		initial.setAttribute('type', 'hidden');
		initial.setAttribute('name', 'initial');
		initial.setAttribute('value', JSON.stringify(this.initial));

		// add the filters
		var filters = document.createElement('input');
		filters.setAttribute('type', 'hidden');
		filters.setAttribute('name', 'filters');
		filters.setAttribute('value', JSON.stringify(this.filters));

		form.appendChild(initial);
		form.appendChild(filters);

		window.document.body.appendChild(form);

		form.submit();
	}
}
