var angular = require('cla_angular');

/**
 * A table full of data (using jQuery DataTables)
 *
 *
 */
(function () {
	'use strict';

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

	// dependencies
	module.directive('claDataTable', DataTable);
	DataTable.$inject = ['dtService', '$interpolate'];

	/**
	 *
	 * @param dtService
	 * @param $interpolate
	 * @constructor
	 */
	function DataTable(dtService, $interpolate) {
		var directive = {
			controller: controller,
			controllerAs: 'dt',
			replace: true,
			restrict: 'E',
			scope: {
				rows: '=',
				columns: '=',
				id: '@',
				endpoint: '@',
				sortable: '@',
				serverSide: '@',
				per: '@',
				cellPath: '@'
			}
		};
		directive.controller.$inject = ['$scope', '$element'];

		return directive;
		//////////////////


		/** directive controller */
		function controller($scope, $element) {
		    var ctl = this;

            this.$onInit = function() {
                ctl.myService = dtService.register($scope.id);

                init();
            };

			var initialised = false;

			// column template cache
			var templates = [];
			//////////////////

			/**
			 * Initialize
			 */
			function init() {

				$element = $element.find("table");

				setTemplates();

				ctl.myService.build = function () {
					return build($element);
				};

				set();

				if (!$scope.columns)
					return;

				initialised = true;
			}

			/**
			 * Sets scope properties
			 */
			function set() {
				// if no columns provided, check service
				if (!$scope.columns && ctl.myService.columns.length > 0)
					$scope.columns = ctl.myService.columns;

				// if no rows provided, check service
				if (!$scope.rows && ctl.myService.rows.length > 0)
					$scope.rows = ctl.myService.rows;

				// update service with rows
				if (!ctl.myService.rows.length && $scope.rows)
                    ctl.myService.rows = $scope.rows;

				// update service with columns
				if (!ctl.myService.columns.length && $scope.columns)
                    ctl.myService.columns = $scope.columns;

				// set endpoint if given
				if ($scope.endpoint)
                    ctl.myService.setResource($scope.endpoint);
			}

			/**
			 * Format thead
			 */
			function thead() {
				var head = [], col_key;

				// set column headers
				for (var i = 0; i < $scope.columns.length; i ++) {
					col_key = $scope.columns[i].key;

					if (!col_key)
						col_key = $scope.columns[i].name.replace(/\s/g, '_').toLowerCase();

					head.push({
						title: $scope.columns[i].name,
						data: col_key,
						orderable: $scope.columns[i].orderable,
						createdCell: (function () {
							return function (cell, cData, rData, rIndex, cIndex) {
								if (templates[cIndex]) {
									// $interpolate() the template to bind properties to template variables.
									var output = $interpolate(templates[cIndex])({ content: cData });
									angular.element(cell).html(output);
								}
							}
						}())
					});
				}

				return head;
			}

			/**
			 * Destroy the data-table
			 * @param element
			 */
			function destroy(element) {
                ctl.myService.reset();
				element.empty();
			}

			/**
			 * Build data-table
			 * @param element
			 */
			function build(element) {

				if (!initialised) {
					window.alert("Cannot build, table not initialised.");
					return;
				}

				if (ctl.myService.datatable)
					destroy(element);

				var opts = options();
                ctl.myService.datatable = element.DataTable(opts);

				// table info
                ctl.myService.dtInit();

                ctl.myService.datatable.on(
                    'order.dt column-reorder.dt',
                    function () {
                        updateSortIcons(element);
                    }
                );

                // .active class on thead tr
                $("#" + element[0].id + " thead tr").addClass("active");

                $('thead th', element).each(function () {
                    var $th = $(this);

                    if (($th.hasClass('sorting') || $th.hasClass('sorting_asc') || $th.hasClass('sorting_desc'))) {
                        $th.attr("tabindex", "-1");

                        var currentText = $th.text();
                        var $button = $('<button type="button" class="btn btn-sm btn-link font-weight-bold sort-button"></button>');

                        $button.append(currentText);
                        $th.empty().append($button);
                    }
                });

                updateSortIcons(element);
			}

            /**
             * Add appropriate icons to orderable table headers
             */
            function updateSortIcons(el) {
                $('thead th', el).each(function () {
                    var $th = $(this);
                    var icon = 'sort-outline-filled';

                    if ($th.hasClass('sorting_asc')) {
                        icon = 'sort-ascending-outline-filled';
                    } else if ($th.hasClass('sorting_desc')) {
                        icon = 'sort-descending-outline-filled';
                    }

                    var $button = $th.find('.sort-button');
                    $button.find('ion-icon').remove();
                    $button.append('<ion-icon class="ml-1" src="/assets/icons/' + icon + '.svg" aria-hidden="true"></ion-icon>');
                });
            }

			/**
			 * Set the options for data-tables
			 */
			function options() {
                ctl.myService.per = ctl.myService.per || $scope.per || 10;

				var opts = {
					columns: thead(),
					pageLength: ctl.myService.per,
					order: [],
					colReorder: false,
					serverSide: !!parseInt($scope.serverSide),
					deferRender: false,
					dom: 't'
				};

				// ajax callback
				opts.ajax = function (data, internalCallback) {
					// delegate responsibility of data fetching to the data-table service
                    ctl.myService.fetch(data, function (d) {
						internalCallback(d);
                        ctl.myService.dtInit();
					});
				};

				return opts;
			}

			/**
			 * Fetches template for each column
			 */
			function setTemplates() {
				for (var i = 0; i < $scope.columns.length; i ++) {
					if ($scope.columns.hasOwnProperty(i)) {
						var template_id = $scope.id+'_'+$scope.columns[i].template_key+'_tmpl';
						var template_element = angular.element('#'+template_id);

						// have we found the template element set on the component?
						if (template_element.length > 0 && !(i in templates)) {
							templates[i] = template_element.html();
						}
					}
				}
			}
		}
	}
}());
