/**
 * Bookings Module - Cleaned Version
 * 
 * 62 controllers extracted to /controllers/ directory
 * Controllers are loaded via controllers.js manifest
 * 
 * This module now contains:
 * - Module definition and configuration
 * - Route configuration
 * - Services and factories
 * - Directives (if any)
 */

var Bookings = angular.module('bookings', []);

Bookings.config(['$routeProvider', function ($routeProvider) {

	$routeProvider.when('/bookings/repair', {
		controller: 'BookingsRepairCtrl',
		templateUrl: 'bookings/repair.html'
	});

	$routeProvider.when('/bookings/support', {
		controller: 'BookingsSupportCtrl',
		templateUrl: 'bookings/support.html'
	});

	$routeProvider.when('/bookings/message', {
		controller: 'BookingsMessageCtrl',
		templateUrl: 'bookings/message.html'
	});

	$routeProvider.when('/bookings/onsite', {
		controller: 'BookingsOnsiteCtrl',
		templateUrl: 'bookings/onsite.html'
	});

	$routeProvider.when('/bookings/order', {
		controller: 'BookingsOrderCtrl',
		templateUrl: 'bookings/order.html'
	});

	$routeProvider.when('/bookings/rma', {
		controller: 'BookingsRmaCtrl',
		templateUrl: 'bookings/rma.html'
	});

	$routeProvider.when('/bookings/project', {
		controller: 'BookingsProjectCtrl',
		templateUrl: 'bookings/project.html'
	});

	$routeProvider.when('/bookings/sale-lead', {
		controller: 'BookingsSaleLeadCtrl',
		templateUrl: 'bookings/sale-lead.html'
	});

	$routeProvider.when('/bookings/:clientType/:clientId', {
		controller: 'BookingsMainCtrl'
	});

	// nadeem added this on 12.2.17 to enable project and client task tie-ins
	$routeProvider.when('/bookings/:clientType/:clientId/project/:projectId', {
		controller: 'BookingsMainCtrl'
	});

	$routeProvider.when('/projects/overview', {
		controller: 'ProjectsOverviewCtrl',
		templateUrl: '/projects/overview.html'
	});

	$routeProvider.when('/projects/tasks', {
		controller: 'ProjectsTasksCtrl',
		templateUrl: '/projects/tasks.html'
	});

	$routeProvider.when('/projects/stats', {
		controller: 'ProjectsStatisticsCtrl',
		templateUrl: '/projects/statistics.html'
	});

	$routeProvider.when('/projects/files', {
		controller: 'ProjectsFilesCtrl',
		templateUrl: '/projects/files.html'
	});
}]);

// ------------------------------------------------------------------------
//
//	RESOURCES BELOW -->
//
// ------------------------------------------------------------------------

Bookings.factory('Tasks', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	// Additional methods
	methods['promote'] = { method: 'POST', url: apiUrl('task/promote/:taskId'), params: { taskId: '@id' } };
	methods['updateTemplateItem'] = { method: 'POST', url: apiUrl('task/update-template-item/:taskId'), params: { taskId: '@id' } };
	methods['generateInvoice'] = { method: 'POST', url: apiUrl('task/generate-invoice/:taskId'), params: { taskId: '@id' } };
	methods['createExchangeCalendarEvent'] = { method: 'POST', url: apiUrl('task/create-exchange-calendar-event/:taskId'), params: { taskId: '@id' } };
	methods['sendEmail'] = { method: 'POST', url: apiUrl('task/send-email/:taskId'), params: { taskId: '@id' } };
	methods['sendSMS'] = { method: 'POST', url: apiUrl('task/send-sms/:taskId'), params: { taskId: '@id' } };
	methods['addKeychain'] = { method: 'POST', url: apiUrl('task/addKeychain/:taskId'), params: { taskId: '@id' } };
	methods['updateTaskAndQa'] = { method: 'POST', url: apiUrl('task/update-task-and-qa/:taskId'), params: { taskId: '@id' } };

	var Tasks = $resource(apiUrl('task/:taskId'), { taskId: '@id' }, methods);
	angular.extend(Tasks.prototype, _prototype);
	return Tasks;
}]);

Bookings.factory('Repair', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var Repair = $resource(apiUrl('tasks/repairs/:taskId'), { taskId: '@id' }, methods);
	angular.extend(Repair.prototype, _prototype);
	return Repair;
}]);

Bookings.factory('Support', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var Support = $resource(apiUrl('tasks/support/:taskId'), { taskId: '@id' }, methods);
	angular.extend(Support.prototype, _prototype);
	return Support;
}]);

Bookings.factory('Onsite', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var Onsite = $resource(apiUrl('tasks/onsite/:taskId'), { taskId: '@id' }, methods);
	angular.extend(Onsite.prototype, _prototype);
	return Onsite;
}]);

Bookings.factory('Order', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var Order = $resource(apiUrl('tasks/orders/:taskId'), { taskId: '@id' }, methods);
	angular.extend(Order.prototype, _prototype);
	return Order;
}]);

Bookings.factory('Message', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var Message = $resource(apiUrl('messages/:messageId'), { messageId: '@id' }, methods);
	angular.extend(Message.prototype, _prototype);
	return Message;
}]);

Bookings.factory('Rma', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var Rma = $resource(apiUrl('tasks/rma/:taskId'), { taskId: '@id' }, methods);
	angular.extend(Rma.prototype, _prototype);
	return Rma;
}]);

Bookings.factory('RmaItem', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var RmaItem = $resource(apiUrl('tasks/rma/:taskId/items/:itemId'), { taskId: '@task_id', itemId: '@id' }, methods);
	angular.extend(RmaItem.prototype, _prototype);
	return RmaItem;
}]);

Bookings.factory('Comment', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var Comment = $resource(apiUrl('comments/:commentId'), { commentId: '@id' }, methods);
	angular.extend(Comment.prototype, _prototype);
	return Comment;
}]);

Bookings.factory('Part', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	// Additional methods
	methods['requestPart'] = { method: 'POST', url: apiUrl('parts/request-part'), params: { partId: '@id' } };
	methods['received'] = { method: 'POST', url: apiUrl('parts/:partId/received'), params: { partId: '@id' } };

	var Part = $resource(apiUrl('parts/:partId'), { partId: '@id' }, methods);
	angular.extend(Part.prototype, _prototype);
	return Part;
}]);

Bookings.factory('Build', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	// Additional methods
	methods['requestBuild'] = { method: 'POST', url: apiUrl('builds/request-build'), params: { buildId: '@id' } };
	methods['received'] = { method: 'POST', url: apiUrl('builds/:buildId/received'), params: { buildId: '@id' } };

	var Build = $resource(apiUrl('builds/:buildId'), { buildId: '@id' }, methods);
	angular.extend(Build.prototype, _prototype);
	return Build;
}]);

Bookings.factory('Manufacturer', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var Manufacturer = $resource(apiUrl('manufacturers/:manufacturerId'), { manufacturerId: '@id' }, methods);
	Manufacturer.getSearchUrl = function () { return apiUrl('manufacturers?name='); };
	angular.extend(Manufacturer.prototype, _prototype);
	return Manufacturer;
}]);

Bookings.factory('ModelNumber', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var ModelNumber = $resource(apiUrl('model-numbers/:modelNumberId'), { modelNumberId: '@id' }, methods);
	ModelNumber.getSearchUrl = function () { return apiUrl('model-numbers?name='); };
	angular.extend(ModelNumber.prototype, _prototype);
	return ModelNumber;
}]);

Bookings.factory('Delivery', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var Delivery = $resource(apiUrl('tasks/delivery/:deliveryId'), { deliveryId: '@id' }, methods);
	angular.extend(Delivery.prototype, _prototype);
	return Delivery;
}]);

Bookings.factory('Device', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var Device = $resource(apiUrl('devices/:deviceId'), { deviceId: '@id' }, methods);
	angular.extend(Device.prototype, _prototype);
	return Device;
}]);

Bookings.factory('Project', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var Project = $resource(apiUrl('project/:projectId'), { projectId: '@id' }, methods);
	angular.extend(Project.prototype, _prototype);
	return Project;
}]);

Bookings.factory('SaleLead', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var SaleLead = $resource(apiUrl('tasks/sale-lead/:saleLeadId'), { saleLeadId: '@id' }, methods);
	angular.extend(SaleLead.prototype, _prototype);
	return SaleLead;
}]);

Bookings.factory('Files', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	// Additional methods
	methods['download'] = { method: 'GET', url: apiUrl('files/download/:fileId'), params: { fileId: '@id' } };

	var Files = $resource(apiUrl('files/:objectType/:objectId/:fileId'), { fileId: '@id', objectType: '@object_type', objectId: '@object_id' }, methods);
	angular.extend(Files.prototype, _prototype);
	return Files;
}]);

Bookings.factory('Template', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var Template = $resource(apiUrl('templates/:templateId'), { templateId: '@id' }, methods);
	Template.getSearchUrl = function () { return apiUrl('templates?query='); };
	angular.extend(Template.prototype, _prototype);
	return Template;
}]);

Bookings.factory('TemplateItem', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var TemplateItem = $resource(apiUrl('template-items/:templateItemId'), { templateItemId: '@id' }, methods);
	angular.extend(TemplateItem.prototype, _prototype);
	return TemplateItem;
}]);

Bookings.factory('TaskFeedback', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var TaskFeedback = $resource(apiUrl('feedback/:taskFeedbackId'), { taskFeedbackId: '@id' }, methods);
	angular.extend(TaskFeedback.prototype, _prototype);
	return TaskFeedback;
}]);

Bookings.factory('TimeTracking', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	// Additional methods
	methods['start'] = { method: 'POST', url: apiUrl('time-tracking/start') };
	methods['stop'] = { method: 'POST', url: apiUrl('time-tracking/stop') };

	var TimeTracking = $resource(apiUrl('time-tracking/:timeTrackingId'), { timeTrackingId: '@id' }, methods);
	angular.extend(TimeTracking.prototype, _prototype);
	return TimeTracking;
}]);

Bookings.factory('Keychain', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	// Additional methods
	methods['types'] = { method: 'GET', url: apiUrl('keychains/types') };
	methods['addToTask'] = { method: 'GET', url: apiUrl('keychains/add') };

	var Keychain = $resource(apiUrl('keychains/:keychainId'), { keychainId: '@id' }, methods);
	angular.extend(Keychain.prototype, _prototype);
	return Keychain;
}]);


Bookings.directive('ngReallyClick', [function () {
	return {
		restrict: 'A',
		link: function (scope, element, attrs) {
			element.bind('click', function () {
				var message = attrs.ngReallyMessage;
				if (message && confirm(message)) {
					scope.$apply(attrs.ngReallyClick);
				}
			});
		}
	}
}]);

Bookings.factory('License', ['apiUrl', '$resource', 'ResourceMethods', 'ResourcePrototype', function (apiUrl, $resource, methods, _prototype) {
	var License = $resource(apiUrl('licenses/:licenseId'), { licenseId: '@id' }, methods);
	angular.extend(License.prototype, _prototype);
	return License;
}]);
/**
 *	The main controller for the bookings page.
 *
 */

Bookings.factory('BookingsLocationManager', ['$ClientsManager', function ($ClientsManager) {

	var $this = this;
	var findUser = function (user_id) {
		var user;

		_.find($ClientsManager.getClient().sites, function (site) {
			if (!site) return false;

			// Search for the user
			user = _.find(site.users, function (u) {
				return u.id == user_id;
			});

			return user;
		});

		return user;
	};

	return {
		getUsers: function (site_id) {
			// Stop here if no site_id is passed
			if (!site_id) return [];
			// Fin the site
			var site = _.find($ClientsManager.getClient().sites, function (s) { return s.id == site_id; });
			if (site && site.users)
				return site.users;
			else
				return [];
		},

		findUser: findUser,

		getUserDDI: function (user_id) {
			if (!user_id) return '';

			var user = findUser(user_id);

			if (!user) {
				return '';
			} else {
				if (user.phone && user.phone.length > 0) {
					return user.phone;
				} else {
					return user.mobile;
				}
			}
		}
	};
}]);

Bookings

Bookings.directive('saveDdi', function () {
	return {
		restrict: 'A',
		controller: ['$scope', 'ErrorsHandler', 'SiteUser', function ($scope, ErrorsHandler, SiteUser) {

			$scope.updateDDI = function (number, site_id, site_user_id) {
				SiteUser.update({ phone: number, site_id: site_id, id: site_user_id }, function (response) {
					$scope.changed_ddi = false;
				}, ErrorsHandler);
			};

		}]
	};
});

/**
 * Default controller for a Client single site.
 */

Bookings.service('repairsForm', ['ErrorsHandler', 'Messenger', '$location', 'Repair', '$ClientsManager', '$window', 'archAuthService', '$uibModal', 'socket', '$http', function (ErrorsHandler, Messenger, $location, Repair, $ClientsManager, $window, auth, $uibModal, socket, $http) {

	var $this = this;

	$this.options = {
		showErrors: true,
		showMessage: true,
		showPrintView: true,
		callback: function () { },
		message: "I've successfully created the repair!"
	};

	// This will trigger the print preview on and off
	$this.modal = {
		id: null,
		showPrintView: false
	};

	// Form data
	$this.data = {
		client_id: $ClientsManager.getClient().id,
		client_type: $ClientsManager.getClientType(),
		templates: [],
	};

	// Clears the form
	$this.clearForm = function () {
		$this.data = {
			client_id: $ClientsManager.getClient().id,
			client_type: $ClientsManager.getClientType()
		};
	};

	// Saves the repair
	$this.save = function () {

		auth.confirm(function (status, helper) {

			// User logged in successfully
			if (status) {

				// Process the error handler
				errors_handler = ($this.options.showErrors) ? ErrorsHandler : null;

				// Inject the client
				$this.data.client_id = $ClientsManager.getClient().id;
				$this.data.client_type = $ClientsManager.getClientType();

				Repair.save($this.data, function (res) {
					if (res.success) {
						$this.data.id = res.data.id;
						$window.onbeforeunload = function () { };
						if ($this.options.showMessage) Messenger($this.options.message);
						if ($this.options.callback) $this.options.callback(res.data);
						// if ($this.options.showPrintView) {
						// 	$this.modal.id = res.data.id; // set the repair id that will be loaded inside the iframe
						// 	$this.modal.showPrintView = true;
						// }
						$window.location.href = "/bookings/confirmation-sheet/" + res.data.id;
					}
				}, function (a, b) {
					helper.loading = false;
					errors_handler(a, b);
				});

			}
		});
	};

	$this.saveOnly = function () {

		auth.confirm(function (status) {

			// User logged in successfully
			if (status) {

				// Inject the client
				$this.data.client_id = $ClientsManager.getClient().id;
				$this.data.client_type = $ClientsManager.getClientType();

				Repair.save($this.data, function (res) {
					if (res.success) {
						$this.data.id = res.data.id;
						$window.onbeforeunload = function () { };
						$window.location.href = "/tasks/repairs/" + res.data.id;
					}
				}, ErrorsHandler);
			}
		});

	};

}]);

/**
 * Default controller for a Client single site.
 */

Bookings.service('supportForm', ['ErrorsHandler', 'Messenger', '$location', 'Support', '$ClientsManager', '$window', 'archAuthService', function (ErrorsHandler, Messenger, $location, Support, $ClientsManager, $window, auth) {
	var $this = this;

	$this.options = {
		showErrors: true,
		showMessage: true,
		callback: function () { },
		message: "I've successfully created the support ticket!"
	};

	// This will trigger the print preview on and off
	$this.modal = {
		id: null,
		showPrintView: false
	};

	// Form data
	$this.data = {
		client_id: $ClientsManager.getClient().id,
		client_type: $ClientsManager.getClientType()
	};

	// Clears the form
	$this.clearForm = function () {
		$this.data = {
			client_id: $ClientsManager.getClient().id,
			client_type: $ClientsManager.getClientType()
		};
	};

	// Saves the repair
	$this.save = function () {

		auth.confirm(function (status, helper) {

			// User logged in successfully
			if (status) {

				// Process the error handler
				errors_handler = ($this.options.showErrors) ? ErrorsHandler : null;

				// Inject the client
				$this.data.client_id = $ClientsManager.getClient().id;
				$this.data.client_type = $ClientsManager.getClientType();

				Support.save($this.data, function (res) {
					if (res.success) {
						$window.onbeforeunload = function () { };
						if ($this.options.showMessage) Messenger($this.options.message);
						if ($this.options.callback) $this.options.callback(res.data);
						window.location.href = "/tasks/support/" + res.data.id;
					}
				}, function (a, b) {
					helper.loading = false;
					errors_handler(a, b);
				});
			}
		});
	};
}]);

archDB.filter('contains', function () {

	return function (array, indexToFind) {
		var truth = false;
		angular.forEach(array, function (value, key) {
			if (key === indexToFind) {
				truth = true;
			}
		});
		return truth;
	};
});

Bookings.directive('assignTask', function () {
	return {
		templateUrl: 'bookings/projects/assign-task.html',
		replace: true,
		controller: 'assignTaskCtrl',
		link: function ($scope, $element, $attrs) {

			$element.modal({ show: false });

		}
	};
});

Bookings.directive('attachments', function () {
	return {
		restrict: 'AE',
		templateUrl: 'widgets/attachments.html',
		controller: 'AttachmentsCtrl',
		scope: {
			'task': '=',
			'type': '@'
		}
	};
});

Bookings.factory('archAuthService', ['$uibModal', '$timeout', function ($uibModal, $timeout) {

	return {
		callback: null,
		show: false,
		confirm: function (callback) {

			// Show the modal
			var modal = $uibModal.open({
				templateUrl: 'modals/auth.html',
				controller: 'archAuthCtrl',
				backdrop: 'static'
			});

			modal.opened.then(function () {
				$timeout(function () {
					$('#authPassword').focus();
				}, 50);
			});

			// Store the callback
			this.callback = callback;

		},
		respond: function (result, helper) {

			// Call the callback function
			if (typeof this.callback == 'function') this.callback(result, helper);

		}
	};
}]).directive('archAuth', function () {

	return {
		restrict: 'A',
		replace: true,
		scope: {}
	};
});

Bookings.directive('bookingPasswords', function () {
	return {
		controller: 'BookingPasswordsCtrl',
		templateUrl: 'bookings/passwords.html',
		scope: {
			'task': '=',
		}
	};
});

Bookings.factory('BuildsService', function () {

	var o = {
		total: 0,
		tax: 0,
		subtotal: 0,
		builds: []
	};

	o.setTotal = function (amount) {
		o.total = amount;
	};

	o.getTotal = function () {
		return o.total.toFixed(2);
	};

	o.setTax = function (amount) {
		o.tax = amount;
	};

	o.getTax = function () {
		return o.tax;
	};

	o.setSubtotal = function (amount) {
		o.subtotal = amount;
	};

	o.getSubtotal = function () {
		return o.subtotal;
	};

	o.setBuilds = function (b) {
		angular.copy(b, o.builds);
	};

	o.hasBuildsOnOrder = function () {
		var on_order = false;
		_.each(o.builds, function (p) {
			if (p.quantity_on_order > 0) {
				on_order = true;
				return;
			}
		});
		return on_order;
	};

	return o;
});

Bookings.directive('widgetBuilds', function () {

	return {
		restrict: 'A',
		templateUrl: 'widgets/builds.html',
		controller: 'widgetBuildsCtrl',
		scope: {
			'related': '=widgetBuilds',
			'related_type': '@relatedType'
		}
	};
});

Bookings

Bookings.directive('widgetClient', function () {

	return {
		restrict: 'A',
		templateUrl: 'widgets/client.html',
		controller: 'widgetClientCtrl',
		scope: {
			'task': '=widgetClient'
		}
	};
});

Bookings.factory("CommentsService", [
	"Comment",
	"$q",
	"ErrorsHandler",
	function (Comment, $q, ErrorsHandler) {
		var o = {
			comments: []
		};

		o.setComments = function (c, pages) {
			angular.copy(c, o.comments);
		};

		o.getComments = function () {
			return o.comments;
		};

		o.addComment = function (data) {
			var deferred = $q.defer();

			Comment.save(
				data,
				function (res) {
					if (!res.id) {
						alert(
							"Something went wrong! Try to refresh the page and enter the comment again"
						);
						return false;
					}

					// self.comments.push(res);
					data.current_page = 0;
					o.loadComments(data, function () { });
					deferred.resolve(res);
				},
				ErrorsHandler
			);

			return deferred.promise;
		};

		/**
		 * Loads all the comments for this particular task.
		 *
		 * @return void
		 */
		o.loadComments = function (data, cb) {
			o.pages = data.pages || o.pages;
			o.current_page = data.current_page || o.current_page;
			Comment.get(
				{ type: data.related_type, id: data.related_id, page: o.current_page },
				function (res) {
					o.setComments(res.data, res.last_page);
					o.pages = res.last_page;
					o.currentPage = res.current_page;
					cb(o);
				},
				ErrorsHandler
			);
		};

		return o;
	}
]);

Bookings

Bookings.directive("widgetComments", function () {
	return {
		restrict: "A",
		templateUrl: "widgets/comments.html",
		controller: "widgetCommentsCtrl",
		scope: {
			data: "=widgetComments",
			type: "@commentType"
		}
	};
});

Bookings.directive('createNonExitingBuild', function () {
	return {
		restrict: 'A',
		controller: 'CreateNonExitingBuildCtrl',
		templateUrl: 'modals/create-non-existing-build.html',
		replace: true,
		scope: {
			builds: '=',
			related: '=',
			related_type: '@relatedType',
			virtualMode: '=virtualMode'
		}
	};
});

Bookings

Bookings.directive('customerDevices', function () {
	return {
		restrict: 'A',
		controller: 'CustomerDevicesCtrl',
		templateUrl: 'bookings/repairs/devices.html',
		scope: {
			'selected_devices': '=customerDevices'
		},
		link: function ($scope, $element, $attrs) {
			if ($attrs.view && $attrs.view !== '') $scope.view = $attrs.view;
		}
	};
});

Bookings.factory('CustomerNotificationsService', function () {

	var o = {
		notifications: []
	};

	o.setNotifications = function (n) {
		angular.copy(n, o.notifications);
	};

	return o;
});

Bookings.filter('cut', function () {
	return function (value, wordwise, max, tail) {
		if (!value) return '';

		max = parseInt(max, 10);
		if (!max) return value;
		if (value.length <= max) return value;

		value = value.substr(0, max);
		if (wordwise) {
			var lastspace = value.lastIndexOf(' ');
			if (lastspace != -1) {
				value = value.substr(0, lastspace);
			}
		}

		return value + (tail || ' …');
	};
}).directive('widgetCustomerNotifications', function () {

	return {
		restrict: 'A',
		templateUrl: 'widgets/customer-notifications.html',
		controller: 'widgetCustomerNotificationsCtrl',
		scope: {
			'task': '='
		}
	};
});

Bookings.directive('customerPrebooks', function () {
	return {
		restrict: 'A',
		controller: 'CustomerPrebooksCtrl',
		templateUrl: 'bookings/repairs/prebooks.html',
	};
});

/**
 * Selects the primary location
 *
 * @return void
 */
Bookings.directive('defaultLocation', ['$ClientsManager', function (client) {

	return {
		require: 'ngModel',
		link: function ($scope, $element, $attrs, $ctrl) {

			$scope.$watch(function () {
				return client.client;
			}, function (value) {
				if (!value) return false;

				if (value.sites && value.sites.length > 0) {
					var site = value.sites[0];
					$scope.data.site_id = site.id;

					if (site.users) {
						$scope.data.site_user_id = site.users[0].id;
					}
				}
			}, true);

		}
	};
}]);

Bookings.directive('followupTask', function () {

	return {
		templateUrl: 'bookings/followup-task.html',
		scope: {
			followupId: '@',
			users: '=',
			task: '=',
		},
		controller: ['$scope', 'Page', '$timeout', 'Messenger', 'Tasks', 'ErrorsHandler', '$uibModal', 'CommentsService', function ($scope, Page, $timeout, Messenger, Tasks, ErrorsHandler, $uibModal, CommentsService) {

			/**
			 * Notifies the user if any changes have been made to the original data
			 */
			$scope.modified = false;
			$scope.initialized = false;

			$scope.$watch('followupId', function (id) {
				if (id) {
					// Update the page title
					Page.setTitle(id);

					// Fetch the QA id
					Tasks.get({ taskId: $scope.followupId }, function (response) {
						$scope.mainTask = response;
					}, ErrorsHandler);
				}
			});

			$scope.updateValue = function (params) {

				angular.extend(params, { id: $scope.mainTask.id, updated_at: $scope.mainTask.updated_at });
				Tasks.update(params, function (response) {
					angular.extend($scope.mainTask, response || {});
					Messenger("I've succesfully saved the job!");
				}, ErrorsHandler);
			};

			$scope.changeFollowupAproval = function (value) {

				var params = { id: $scope.mainTask.id, updated_at: $scope.mainTask.updated_at, satisfied_client: value, status_id: 10, completed: 1 };

				Tasks.update(params, function (response) {
					angular.extend($scope.mainTask, response || {});
					Messenger("I've succesfully saved the job!");
				}, ErrorsHandler);
			};

			$scope.aproveFollowup = function () {
				var modalInstance = $uibModal.open({
					templateUrl: 'bookings/modals/followup-aproved.html',
					controller: 'ReasonModalCtrl'
				});

				modalInstance.result.then(function (reason) {
					reason = reason ? reason : 'No comment left.';
					$scope.addComment({ message: reason, style: 'success' });
					$scope.changeFollowupAproval(true);
				});

			};

			$scope.declineFollowup = function () {

				var modalInstance = $uibModal.open({
					templateUrl: 'bookings/modals/followup-declined.html',
					controller: 'ReasonModalCtrl'
				});

				modalInstance.result.then(function (reason) {
					$scope.addComment({ message: reason, style: 'failed' });
					$scope.changeFollowupAproval(false);
				});
			};

			$scope.addComment = function (value) {

				var data = {
					related_id: $scope.task.id,
					related_type: 'task',
					type: $scope.mainTask.type,
					message: value.message,
					public: false,
					send_email: false,
					style: value.style
				};

				CommentsService.addComment(data);
			};
		}],

		link: function (scope, el, attr) {
		},
	};

});

Bookings.factory('locationHelper', function () {

	var o = {};

	/**
	 * Finds a specific site selected by id from all the sites.
	 *
	 * @param  array	sites	- an array containing the sites to be searched on
	 * @param  integer	id		- the id of the site to be found
	 * @return object / null on failure
	 */
	o.getSite = function (sites, id) {
		return _.find(sites, function (el) { return el.id == id; });
	};

	return o;
});

Bookings.directive('widgetMap', function () {

	return {
		restrict: 'A',
		controller: 'widgetMapCtrl',
		scope: {
			'task': '=widgetMap',
			'address': '='
		},
		transclude: true,
		link: function (scope, element, attrs, ctrl, transclude) {
			transclude(scope, function (clone) {
				element.append(clone);
			});
		}
	};
});

Bookings.factory('PartsService', function () {

	var o = {
		total: 0,
		tax: 0,
		subtotal: 0,
		parts: []
	};

	o.setTotal = function (amount) {
		o.total = amount;
	};

	o.getTotal = function () {
		return o.total.toFixed(2);
	};

	o.setTax = function (amount) {
		o.tax = amount;
	};

	o.getTax = function () {
		return o.tax;
	};

	o.setSubtotal = function (amount) {
		o.subtotal = amount;
	};

	o.getSubtotal = function () {
		return o.subtotal;
	};

	o.setParts = function (p) {
		angular.copy(p, o.parts);
	};

	o.addPart = function (p) {
		var index = _.findIndex(o, function (el) {
			return el.id === part.id;
		});
		if (index)
			o.parts[index] = p;
		else
			o.parts.push(p);
	}

	o.hasPartsOnOrder = function () {
		var on_order = false;
		_.each(o.parts, function (p) {
			if (p.on_order > 0) {
				on_order = true;
				return;
			}
		});
		return on_order;
	};

	return o;
})

Bookings.directive('widgetParts', function () {

	return {
		restrict: 'A',
		templateUrl: 'widgets/parts.html',
		controller: 'widgetPartsCtrl',
		scope: {
			'related': '=widgetParts',
			'related_type': '@relatedType'
		}
	};
});

Bookings.directive('projectTasks', function () {
	return {
		restrict: 'AE',
		templateUrl: 'widgets/project-tasks.html',
		controller: 'ProjectTasksCtrl',
		scope: {
			'projectId': '=projectTasks'
		}
	};
});

Bookings.directive('promoteProjectBtn', ['$uibModal', function ($uibModal) {

	return {
		scope: {
			task_id: '=promoteProjectBtn',
			redirect_url: '@redirectUrl'
		},
		templateUrl: 'bookings/modals/promote.html',
		link: function ($scope, $element, $attrs) {

			$scope.promote = function () {
				$uibModal.open({
					templateUrl: 'modals/promote-project.html',
					controller: 'PromoteProjectCtrl'
				});
			};

		}
	};
}]);

Bookings

Bookings.directive('qaTask', function () {

	return {
		templateUrl: 'bookings/qa-task.html',
		scope: {
			qaId: '@',
			users: '=',
			task: '=',
			loadData: '&'
		},
		controller: ['$scope', 'Page', '$timeout', 'Messenger', 'Tasks', 'ErrorsHandler', '$uibModal', 'CommentsService', function ($scope, Page, $timeout, Messenger, Tasks, ErrorsHandler, $uibModal, CommentsService) {

			/**
			 * Notifies the user if any changes have been made to the original data
			 */
			$scope.modified = false;
			$scope.initialized = false;

			$scope.$watch('qaId', function (id) {
				if (id) {
					// Update the page title
					Page.setTitle(id);

					// Fetch the QA id
					Tasks.get({ taskId: $scope.qaId }, function (response) {
						$scope.mainTask = response;
					}, ErrorsHandler);
				}
			});

			$scope.updateValue = function (params) {
				angular.extend(params, { id: $scope.mainTask.id, updated_at: $scope.mainTask.updated_at });
				Tasks.update(params, function (response) {
					angular.extend($scope.mainTask, response || {});
					Messenger("I've succesfully saved the job!");
				}, ErrorsHandler);
			};

			$scope.customerCalled = function () {

				// Prepare parameters to update the QA related task
				var params = {
					id: $scope.mainTask.id,
					updated_at: $scope.mainTask.updated_at,
					needs_calling: false
				};

				Tasks.update(params, function (response) {
					angular.extend($scope.mainTask, response || {});
					// Write a comment
					$scope.addComment({ type: 'call' });
					Messenger("I've succesfully saved the job!");

				}, ErrorsHandler);
			};

			$scope.changeQAAproval = function (value) {

				var params = {
					id: $scope.mainTask.id, //related task
					needs_calling: ($scope.task.type == 'repair' && value.passed_qa) ? true : false,
					qa_updated_at: $scope.mainTask.updated_at,
					related_task_updated_at: $scope.task.updated_at,
					passed_qa: value.passed_qa,
					qa_task_status_id: value.qa_task_status_id,
					related_task_status_id: value.task_status_id,
				};

				// If the QA related task is successful updated, update the QA task and write a comment
				Tasks.updateTaskAndQa(params, function (response) {

					angular.extend($scope.mainTask, response || {});

					// Write a comment
					$scope.addComment({ message: value.comment, style: value.style, type: 'qa' });

					Messenger("I've succesfully saved the job!");

					// Refresh task data
					$scope.loadData();

				}, ErrorsHandler);
			};

			$scope.quickAproveQA = function () {

				//update the QA related task
				var params = {
					passed_qa: true, //related task
					qa_task_status_id: 10, //Change status to work completed
					task_status_id: 10,
					comment: 'No comment left.',
					style: 'success',
				};

				$scope.changeQAAproval(params);

			};

			$scope.aproveQA = function () {

				var modalInstance = $uibModal.open({
					templateUrl: 'bookings/modals/qa-aproved.html',
					controller: 'ReasonModalCtrl',
					size: 'lg',
				});

				//Shows a modal to ask for reason
				modalInstance.result.then(function (reason) {
					//update the QA related task
					var params = {
						passed_qa: true, //related task
						qa_task_status_id: 10, //Change status to work completed
						task_status_id: 10,
						comment: reason ? reason : 'No comment left.',
						style: 'success',
					};

					$scope.changeQAAproval(params);
					$scope.sendNotification();

				});

			};

			$scope.declineQA = function () {

				var modalInstance = $uibModal.open({
					templateUrl: 'bookings/modals/qa-declined.html',
					controller: 'ReasonModalCtrl'
				});

				//Shows a modal to ask for reason
				modalInstance.result.then(function (reason) {
					//update the QA related task
					var params = {
						passed_qa: false,
						qa_task_status_id: 10, //work completed
						task_status_id: 4, //Work in progress
						comment: reason,
						style: "failed",
					};

					$scope.changeQAAproval(params);

				});
			};

			//Add a comment to the task this qa is related to
			$scope.addComment = function (value) {

				var data = {
					related_id: $scope.task.id,
					related_type: 'task',
					type: value.type,
					message: value.message,
					public: true,
					send_email: false,
					style: value.style
				};
				CommentsService.addComment(data);
			};

			//Open a modal to send a notification to the customer
			$scope.sendNotification = function () {

				var modalInstance = $uibModal.open({
					templateUrl: 'bookings/modals/new-customer-notification.html',
					controller: 'CustomerNotificationCtrl',
					windowClass: 'modal-fixed',
					resolve: {
						taskId: function () {
							return $scope.task.id;
						},
						notification: null,
					}

				});

			};

		}]
	};

});

// Pickup Task Directive
Bookings.directive('pickupTask', function () {
	return {
		templateUrl: 'bookings/pickup-task.html',
		scope: {
			users: '=',
			task: '='
		},
		controller: ['$scope', 'Tasks', 'ErrorsHandler', 'Messenger', 'CommentsService', '$uibModal', function ($scope, Tasks, ErrorsHandler, Messenger, CommentsService, $uibModal) {

			// Watch for task changes and initialize data
			$scope.$watch('task', function(newVal) {
				if (newVal) {
					$scope.data = newVal;
				}
			});

			$scope.updateValue = function (params) {
				if (!$scope.data) return;
				angular.extend(params, { id: $scope.data.id, updated_at: $scope.data.updated_at });
				Tasks.update(params, function (response) {
					angular.extend($scope.data, response || {});
					Messenger("Pickup information updated successfully!");
				}, ErrorsHandler);
			};

			$scope.getUserName = function(userId) {
				if (!userId) return 'Not assigned';
				var user = _.find($scope.users, function(u) { return u.id == userId; });
				return user ? user.name : 'Not assigned';
			};

			$scope.markPickedUp = function () {
				if (!$scope.data) {
					Messenger("Error: Task data not loaded", 'error');
					return;
				}
				var params = {
					id: $scope.data.id,
					updated_at: $scope.data.updated_at,
					picked_up_at: new Date().toISOString()
				};

				Tasks.update(params, function (response) {
					angular.extend($scope.data, response || {});

					// Add comment
					var commentData = {
						related_id: $scope.data.id,
						related_type: 'task',
						message: 'Item picked up successfully',
						public: true,
						send_email: false,
						style: 'success'
					};
					CommentsService.addComment(commentData);

					Messenger("Marked as picked up!");
					location.reload();
				}, ErrorsHandler);
			};

			$scope.cancelPickup = function () {
				if (!$scope.data) {
					Messenger("Error: Task data not loaded", 'error');
					return;
				}
				var modalInstance = $uibModal.open({
					templateUrl: 'bookings/modals/cancelled-reason.html',
					controller: 'ReasonModalCtrl'
				});

				modalInstance.result.then(function (reason) {
					var params = {
						id: $scope.data.id,
						updated_at: $scope.data.updated_at,
						needs_pickup: false,
						pickup_by: null
					};

					Tasks.update(params, function (response) {
						angular.extend($scope.data, response || {});

						// Add comment
						var commentData = {
							related_id: $scope.data.id,
							related_type: 'task',
							message: 'Pickup cancelled: ' + reason,
							public: true,
							send_email: false,
							style: 'failed'
						};
						CommentsService.addComment(commentData);

						Messenger("Pickup cancelled!");
						location.reload();
					}, ErrorsHandler);
				});
			};

		}]
	};
});

// Delivery Task Directive
Bookings.directive('deliveryTask', function () {
	return {
		templateUrl: 'bookings/delivery-task.html',
		scope: {
			users: '=',
			task: '='
		},
		controller: ['$scope', 'Tasks', 'ErrorsHandler', 'Messenger', 'CommentsService', '$uibModal', function ($scope, Tasks, ErrorsHandler, Messenger, CommentsService, $uibModal) {

			// Watch for task changes and initialize data
			$scope.$watch('task', function(newVal) {
				if (newVal) {
					$scope.data = newVal;
				}
			});

			$scope.updateValue = function (params) {
				if (!$scope.data) return;
				angular.extend(params, { id: $scope.data.id, updated_at: $scope.data.updated_at });
				Tasks.update(params, function (response) {
					angular.extend($scope.data, response || {});
					Messenger("Delivery information updated successfully!");
				}, ErrorsHandler);
			};

			$scope.getUserName = function(userId) {
				if (!userId) return 'Not assigned';
				var user = _.find($scope.users, function(u) { return u.id == userId; });
				return user ? user.name : 'Not assigned';
			};

			$scope.markDelivered = function () {
				if (!$scope.data) {
					Messenger("Error: Task data not loaded", 'error');
					return;
				}
				var params = {
					id: $scope.data.id,
					updated_at: $scope.data.updated_at,
					delivered: 1
				};

				Tasks.update(params, function (response) {
					angular.extend($scope.data, response || {});

					// Add comment
					var commentData = {
						related_id: $scope.data.id,
						related_type: 'task',
						message: 'Item delivered successfully',
						public: true,
						send_email: false,
						style: 'success'
					};
					CommentsService.addComment(commentData);

					Messenger("Marked as delivered!");
					location.reload();
				}, ErrorsHandler);
			};

			$scope.cancelDelivery = function () {
				if (!$scope.data) {
					Messenger("Error: Task data not loaded", 'error');
					return;
				}
				var modalInstance = $uibModal.open({
					templateUrl: 'bookings/modals/cancelled-reason.html',
					controller: 'ReasonModalCtrl'
				});

				modalInstance.result.then(function (reason) {
					var params = {
						id: $scope.data.id,
						updated_at: $scope.data.updated_at,
						needs_delivery: false,
						delivered_by: null
					};

					Tasks.update(params, function (response) {
						angular.extend($scope.data, response || {});

						// Add comment
						var commentData = {
							related_id: $scope.data.id,
							related_type: 'task',
							message: 'Delivery cancelled: ' + reason,
							public: true,
							send_email: false,
							style: 'failed'
						};
						CommentsService.addComment(commentData);

						Messenger("Delivery cancelled!");
						location.reload();
					}, ErrorsHandler);
				});
			};

		}]
	};
});

Bookings

Bookings.directive('quickNewTask', [function () {
	return {
		templateUrl: 'templates/quick-new-task.html',
		replace: true,
		restrict: 'AEC',
		scope: true,
		controller: 'QuickNewTaskCtrl'
	};
}]);

Bookings.directive('quickTask', ['Tasks', 'Messenger', 'ErrorsHandler', 'Message', 'Onsite', function (Tasks, Messenger, ErrorsHandler, Message, Onsite) {
	return {
		restrict: 'AE',
		scope: {
			client: '=',
			clientType: '@',
			projectId: '@',
			site: '=',
			siteUser: '=',
			onCreate: '&',
			users: '=',
			open: '&'
		},
		templateUrl: 'templates/quick-task.html',
		link: function ($scope, $element, $attrs) {

			$element.parents('.popover:first').addClass('large');
			var textarea = $element.find('textarea');
			textarea.focus();

			$scope.add = function () {
				// Validation checks
				if (!$scope.tags.task) {
					$scope.quickAddError = 'You must select a task type!';
					textarea.focus();
					return false;
				}
				if (!$scope.tags.client && !$scope.client) {
					$scope.quickAddError = 'No client is selected!';
					textarea.focus();
					return false;
				}
				if ($scope.tags.task.id == 'onsite' && !$scope.tags.date) {
					$scope.quickAddError = 'You need to specify a date when booking an onsite!';
					textarea.focus();
					return false;
				}
				if ($scope.tags.task.id == 'onsite' && !$scope.tags.time) {
					$scope.quickAddError = 'You need to specify a time when booking an onsite!';
					textarea.focus();
					return false;
				}

				// Clear the title
				var clean_title = $scope.quick_task;
				if ($scope.tags.task) clean_title = clean_title.replace('^' + $scope.tags.task.name, '');
				if ($scope.tags.client) clean_title = clean_title.replace('#' + $scope.tags.client.name, '');
				if ($scope.tags.staff) clean_title = clean_title.replace('@' + $scope.tags.staff.name, '');
				if ($scope.tags.date) clean_title = clean_title.replace('$' + $scope.tags.date.name, '');
				if ($scope.tags.time) clean_title = clean_title.replace('!' + $scope.tags.time, '');

				var data = {
					type: $scope.tags.task.id,
					title: clean_title,
					problem: clean_title,
					message: clean_title,
					project_id: $scope.projectId,
					severity_id: 2
				};

				if (!$scope.client) {
					data['client_id'] = $scope.tags.client.id;
					data['client_type'] = $scope.tags.client.hasOwnProperty('contract_id') ? 'client' : 'customer';
				}
				else {
					data['client_id'] = $scope.client.id;
					data['client_type'] = $scope.clientType;
				}

				// If a member of staff is mentioned then assign this to him
				if ($scope.tags.staff) data['assigned_to'] = $scope.tags.staff.id;

				// If the task is an onsite then check the dates and format them
				if ($scope.tags.task.id == 'onsite') {
					data['onsite_start'] = $scope.tags.date.value.format("YYYY-MM-DD") + ' ' + $scope.tags.time + ':00';
					data['onsite_end'] = moment(data['onsite_start']).add('hours', 1).format("YYYY-MM-DD HH:mm:ss");
				}

				// Deal with the case where this is a business, where we need
				// to determine the site and the site user
				if (data['client_type'] == 'client') {
					if (($scope.tags.client && !$scope.tags.client.sites) && !$scope.site) {
						$scope.quickAddError = 'The client is missing the site!';
						textarea.focus();
						return false;
					}

					if ($scope.site && $scope.siteUser) {
						data['site_id'] = $scope.site.id;
						data['site_user_id'] = $scope.siteUser.id;
					}
					else {
						data['site_id'] = $scope.tags.client.sites[0].id;
						data['site_user_id'] = $scope.tags.client.sites[0].users[0].id;
					}
				}

				// Determine the model used
				var model;
				switch ($scope.tags.task.id) {
					case 'message': model = Message; break;
					case 'onsite': model = Onsite; break;
					default: model = Tasks;
				}

				// Finally, create the task
				model.save(data, function (response) {
					if (typeof $scope.onCreate == 'function') $scope.onCreate({ data: response });
					Messenger("Task created succesfully");
					$scope.tags = {};
					$scope.quick_task = null;
					$scope.quickAddError = null;

				}, ErrorsHandler);
			};
		}
	};
}]);

Bookings.directive('requestExistingPart', function () {
	return {
		restrict: 'A',
		controller: 'RequestExistingPartCtrl',
		templateUrl: 'modals/request-existing-part.html',
		replace: true,
		scope: {
			parts: '=requestExistingPart',
			related: '=',
			related_type: '@relatedType',
			virtualMode: '=virtualMode'
		}
	};
});

Bookings.directive('requestNonExistingPart', function () {
	return {
		restrict: 'A',
		controller: 'RequestNonExistingPartCtrl',
		templateUrl: 'modals/request-non-existing-part.html',
		replace: true,
		scope: {
			parts: '=requestNonExistingPart',
			related: '=',
			related_type: '@relatedType',
			virtualMode: '=virtualMode'
		}
	};
});

Bookings.directive('widgetSla', function () {

	return {
		restrict: 'A',
		templateUrl: 'widgets/sla.html',
		controller: 'widgetSlaCtrl',
		scope: {
			'task': '=widgetSla'
		}
	};
});

Bookings.factory('PasswordsService', ['Keychain', function (Keychain) {

	var o = {
		passwords: {},
		types: {},
		task_passwords: {}
	};

	o.setPasswords = function (p) {

		p = _.groupBy(p, function (password) {
			return password.device_id ? password.device_id : 'General';
		});

		angular.copy(p, o.passwords);
	};

	o.addPassword = function (item) {

		if (!o.passwords.hasOwnProperty('General'))
			o.passwords['General'] = [];

		if (item.device_id == null) {
			o.passwords['General'].push(item);
			return;
		}

		if (!o.passwords.hasOwnProperty(item.device_id)) {
			o.passwords[item.device_id] = [];
		}

		o.passwords[item.device_id].push(item);
	};

	o.deletePassword = function (item) {
		_.each(o.passwords, function (k, i) {

			o.passwords[i] = _.reject(k, function (el) {
				return el === item;
			});

		});
	};

	o.loadKeychainTypes = function () {
		Keychain.types({}, function (response) {
			o.types = response.data;
		});
	};

	angular.element(document).ready(function () {
		o.loadKeychainTypes();
	});

	return o;
}]);

Bookings.directive('widgetPasswords', function () {

	return {
		restrict: 'A',
		templateUrl: 'widgets/task-passwords.html',
		controller: 'widgetPasswordsCtrl',
		scope: {
			'task': '='
		}
	};
});

Bookings.directive('taskTemplates', function () {

	return {
		restrict: 'A',
		controller: 'TaskTemplatesCtrl',
		templateUrl: 'widgets/templates.html',
		scope: {
			'task': '=taskTemplates'
		}
	};
});

Bookings.directive('timeTracking', [function () {
	return {
		templateUrl: 'bookings/time-tracking.html',
		restrict: 'A',
		scope: {
			'taskId': '@'
		},
		controller: ['$scope', 'TimeTracking', 'ErrorsHandler', 'Messenger', '$interval', 'helpers', function ($scope, TimeTracking, ErrorsHandler, Messenger, $interval, helpers) {

			/**
			 * If the user has a timer running, this will
			 * contain that object instance
			 *
			 * @type Object
			 */
			$scope.activeSession = null;

			/**
			 * An array containing all the history for this particular task
			 *
			 * @type Array
			 */
			$scope.history = [];

			/**
			 * Determines if the history is collapsed or not
			 *
			 * @type Boolean
			 */
			$scope.showHistory = true;

			/**
			 * Load a history of time tracking records
			 *
			 * @return null
			 */
			$scope.load = function () {
				TimeTracking.get({ task_id: $scope.taskId }, function (response) {
					$scope.history = response.data;

					$scope.activeSession = _.find(response.data, function (el) {
						return el.active == true;
					});
				}, ErrorsHandler);
			};

			/**
			 * Starts the timer
			 *
			 * @return null
			 */
			$scope.start = function () {
				if ($scope.activeSession)
					Messenger("The timer is already running");

				TimeTracking.start({ task_id: $scope.taskId }, function (response) {
					$scope.activeSession = response;
					$scope.history.push(response);
				}, ErrorsHandler);
			};

			/**
			 * Stops the timer
			 *
			 * @return null
			 */
			$scope.stop = function () {
				if (!$scope.activeSession)
					Messenger("The timer is not running at the moment");

				TimeTracking.stop({ task_id: $scope.taskId }, function (response) {
					$scope.activeSession = null;
					$scope.duration = null;
					if ($scope.timer) $interval.cancel($scope.timer);

					_.each($scope.history, function (el) {
						if (el.id == response.id) {
							angular.extend(el, response || {});
						}
					});
				}, ErrorsHandler);
			};

			/**
			 * Returns the duration as a formatted string.
			 *
			 * @return string
			 */
			$scope.getTimer = function () {
				if (!$scope.activeSession)
					return '00:00:00';

				if (!$scope.duration) {
					$scope.duration = moment.duration($scope.activeSession.duration * 1000);
					$scope.timer = $interval(function () {
						$scope.duration.add(1, 'second');
					}, 1000);
				}

				return helpers.addZeroNumberPadding($scope.duration.get('hours')) + ':' + helpers.addZeroNumberPadding($scope.duration.get('minutes')) + ':' + helpers.addZeroNumberPadding($scope.duration.get('seconds'));
			};

			/**
			 * Returns the total duration as a formatted string
			 *
			 * @return string
			 */
			$scope.getTotalTime = function () {
				var seconds = 0;
				_.each($scope.history, function (el) {
					if (el != $scope.activeSession) {
						seconds += el.duration;
					}
				});

				// Add the active session
				seconds += $scope.duration ? $scope.duration.asSeconds() : 0;
				var duration = moment.duration(seconds * 1000);

				return helpers.addZeroNumberPadding(duration.get('hours')) + ':' + helpers.addZeroNumberPadding(duration.get('minutes')) + ':' + helpers.addZeroNumberPadding(duration.get('seconds'));
			};

		}], // End of controller

		link: function ($scope) {
			$scope.$watch('taskId', function (v) {
				if (v) $scope.load();
			});
		}
	};
}]);

/**
 * Booking Message Form Service
 * @return service
 */

Bookings.service('_messageForm', ['ErrorsHandler', 'Messenger', '$location', 'Message', '$ClientsManager', '$window', 'archAuthService', function (ErrorsHandler, Messenger, $location, Message, $ClientsManager, $window, auth) {
	var $this = this;

	$this.options = {
		showErrors: true,
		showMessage: true,
		callback: function () { },
		message: "I've successfully saved the message!"
	};

	// This will trigger the print preview on and off
	$this.modal = {
		id: null,
		showPrintView: false
	};

	// Form data
	$this.data = {
		client_id: $ClientsManager.getClient().id,
		client_type: $ClientsManager.getClientType()
	};

	// Clears the form
	$this.clearForm = function () {
		$this.data = {
			client_id: $ClientsManager.getClient().id,
			client_type: $ClientsManager.getClientType()
		};
	};

	// Saves the repair
	$this.save = function () {

		auth.confirm(function (status, helper) {

			// User logged in successfully
			if (status) {

				// Process the error handler
				errors_handler = ($this.options.showErrors) ? ErrorsHandler : null;

				// Inject the client
				$this.data.client_id = $ClientsManager.getClient().id;
				$this.data.client_type = $ClientsManager.getClientType();

				Message.save($this.data, function (res) {
					$window.onbeforeunload = function () { };
					if ($this.options.showMessage) Messenger($this.options.message);
					if ($this.options.callback) $this.options.callback(res);
					window.location.href = "/messages/" + res.id;
				}, function (a, b) {
					helper.loading = false;
					errors_handler(a, b);
				});
			}
		});
	};
}]);

/**
 * Booking Onsite Form Service
 * @return service
 */

Bookings.service('_onsiteForm', ['ErrorsHandler', 'Messenger', '$location', 'Onsite', '$ClientsManager', '$window', 'archAuthService', function (ErrorsHandler, Messenger, $location, Onsite, $ClientsManager, $window, auth) {
	var $this = this;

	$this.options = {
		showErrors: true,
		showMessage: true,
		callback: function () { },
		message: "I've successfully saved the onsite!"
	};

	// This will trigger the print preview on and off
	$this.modal = {
		id: null,
		showPrintView: false
	};

	// Form data
	$this.data = {
		client_id: $ClientsManager.getClient().id,
		client_type: $ClientsManager.getClientType()
	};

	// Clears the form
	$this.clearForm = function () {
		$this.data = {
			client_id: $ClientsManager.getClient().id,
			client_type: $ClientsManager.getClientType()
		};
	};

	// Saves the repair
	$this.save = function () {

		auth.confirm(function (status, helper) {

			// User logged in successfully
			if (status) {

				// Process the error handler
				errors_handler = ($this.options.showErrors) ? ErrorsHandler : null;

				// Inject the client
				$this.data.client_id = $ClientsManager.getClient().id;
				$this.data.client_type = $ClientsManager.getClientType();

				Onsite.save($this.data, function (res) {
					$window.onbeforeunload = function () { };
					if ($this.options.showMessage) Messenger($this.options.message);
					if ($this.options.callback) $this.options.callback(res.data);
					window.location.href = "/tasks/onsite/" + res.data.id;
				}, function (a, b) {
					helper.loading = false;
					errors_handler(a, b);
				});
			}
		});
	};
}]);

/**
 * Booking Order Form Service
 * @return service
 */

Bookings.service('_orderForm', ['ErrorsHandler', 'Messenger', '$location', 'Order', '$ClientsManager', '$window', 'archAuthService', function (ErrorsHandler, Messenger, $location, Order, $ClientsManager, $window, auth) {
	var $this = this;

	$this.options = {
		showErrors: true,
		showMessage: true,
		callback: function () { },
		message: "I've successfully saved the order!"
	};

	// This will trigger the print preview on and off
	$this.modal = {
		id: null,
		showPrintView: false
	};

	// Form data
	$this.data = {
		client_id: $ClientsManager.getClient().id,
		client_type: $ClientsManager.getClientType()
	};

	// Clears the form
	$this.clearForm = function () {
		$this.data = {
			client_id: $ClientsManager.getClient().id,
			client_type: $ClientsManager.getClientType()
		};
	};

	// Saves the repair
	$this.save = function () {

		auth.confirm(function (status, helper) {

			// User logged in successfully
			if (status) {

				// Process the error handler
				errors_handler = ($this.options.showErrors) ? ErrorsHandler : null;

				// Inject the client
				$this.data.client_id = $ClientsManager.getClient().id;
				$this.data.client_type = $ClientsManager.getClientType();

				Order.save($this.data, function (res) {
					$window.onbeforeunload = function () { };
					if ($this.options.showMessage) Messenger($this.options.message);
					if ($this.options.callback) $this.options.callback(res.data);
					window.location.href = "/tasks/orders/" + res.data.id;
				}, function (a, b) {
					helper.loading = false;
					errors_handler(a, b);
				});
			}
		});
	};
}]);

/**
 * Booking RMA Form Service
 * @return service
 */

Bookings.service('_rmaForm', ['ErrorsHandler', 'Messenger', '$location', 'Rma', '$ClientsManager', '$window', 'archAuthService', function (ErrorsHandler, Messenger, $location, Rma, $ClientsManager, $window, auth) {
	var $this = this;

	$this.options = {
		showErrors: true,
		showMessage: true,
		callback: function () { },
		message: "I've successfully saved the RMA!"
	};

	// This will trigger the print preview on and off
	$this.modal = {
		id: null,
		showPrintView: false
	};

	// Form data
	$this.data = {
		client_id: $ClientsManager.getClient().id,
		client_type: $ClientsManager.getClientType(),
		items: []
	};

	// Clears the form
	$this.clearForm = function () {
		$this.data = {
			client_id: $ClientsManager.getClient().id,
			client_type: $ClientsManager.getClientType(),
			items: []
		};
	};

	// Saves the repair
	$this.save = function () {

		auth.confirm(function (status, helper) {

			// User logged in successfully
			if (status) {

				// Process the error handler
				errors_handler = ($this.options.showErrors) ? ErrorsHandler : null;

				// Inject the client
				$this.data.client_id = $ClientsManager.getClient().id;
				$this.data.client_type = $ClientsManager.getClientType();

				Rma.save($this.data, function (res) {
					$window.onbeforeunload = function () { };
					if ($this.options.showMessage) Messenger($this.options.message);
					if ($this.options.callback) $this.options.callback(res.data);
					window.location.href = "/tasks/rma/" + res.data.id;
				}, function (a, b) {
					helper.loading = false;
					errors_handler(a, b);
				});
			}
		});
	};
}]);

archDB.service('TaskTemplatesService', ['Template', 'apiUrl', '$q', 'ErrorsHandler', function (Template, apiUrl, $q, ErrorsHandler) {

	this.ajax = {
		url: apiUrl('templates'),
		dataType: 'json',
		quietMillis: 100,
		cache: true,
		data: function (term, page) {
			return {
				query: term,
				page: page
			};
		},
		results: function (response, page) {
			return { results: response.data, more: response.current_page < response.last_page };
		}
	};

	this.formatResult = function (obj, container, query) {
		return obj.name;
	};

	this.formatSelection = function (obj) {
		return obj.name;
	};

	this.getTemplates = function (type) {

		var deferred = $q.defer();

		Template.get({ task_type: type, order_by: 'priority' }, function (res) {

			deferred.resolve(res);

		}, ErrorsHandler);

		return deferred.promise;
	};

}]);
