text: (function (window) {
  	'use strict';
  
  	/**
  	 * Takes a model and view and acts as the controller between them
  	 *
  	 * @constructor
  	 * @param {object} model The model instance
  	 * @param {object} view The view instance
  	 */
  	function Controller(model, view) {
  		var self = this;
  		self.model = model;
  		self.view = view;
  
  		self.view.bind('newTodo', function (title) {
  			self.addItem(title);
  		});
  
  		self.view.bind('itemEdit', function (item) {
  			self.editItem(item.id);
  		});
  
  		self.view.bind('itemEditDone', function (item) {
  			self.editItemSave(item.id, item.title);
  		});
  
  		self.view.bind('itemEditCancel', function (item) {
  			self.editItemCancel(item.id);
  		});
  
  		self.view.bind('itemRemove', function (item) {
  			self.removeItem(item.id);
  		});
  
  		self.view.bind('itemToggle', function (item) {
  			self.toggleComplete(item.id, item.completed);
  		});
  
  		self.view.bind('removeCompleted', function () {
  			self.removeCompletedItems();
  		});
  
  		self.view.bind('toggleAll', function (status) {
  			self.toggleAll(status.completed);
  		});
  	}
  
  	/**
  	 * Loads and initialises the view
  	 *
  	 * @param {string} '' | 'active' | 'completed'
  	 */
  	Controller.prototype.setView = function (locationHash) {
  		var route = locationHash.split('/')[1];
  		var page = route || '';
  		this._updateFilterState(page);
  	};
  
  	/**
  	 * An event to fire on load. Will get all items and display them in the
  	 * todo-list
  	 */
  	Controller.prototype.showAll = function () {
  		var self = this;
  		self.model.read(function (data) {
  			self.view.render('showEntries', data);
  		});
  	};
  
  	/**
  	 * Renders all active tasks
  	 */
  	Controller.prototype.showActive = function () {
  		var self = this;
  		self.model.read({ completed: false }, function (data) {
  			self.view.render('showEntries', data);
  		});
  	};
  
  	/**
  	 * Renders all completed tasks
  	 */
  	Controller.prototype.showCompleted = function () {
  		var self = this;
  		self.model.read({ completed: true }, function (data) {
  			self.view.render('showEntries', data);
  		});
  	};
  
  	/**
  	 * An event to fire whenever you want to add an item. Simply pass in the event
  	 * object and it'll handle the DOM insertion and saving of the new item.
  	 */
  	Controller.prototype.addItem = function (title) {
  		var self = this;
  
  		if (title.trim() === '') {
  			return;
  		}
  
  		self.model.create(title, function () {
  			self.view.render('clearNewTodo');
  			self._filter(true);
  		});
  	};
  
  	/*
  	 * Triggers the item editing mode.
  	 */
  	Controller.prototype.editItem = function (id) {
  		var self = this;
  		self.model.read(id, function (data) {
  			self.view.render('editItem', {id: id, title: data[0].title});
  		});
  	};
  
  	/*
  	 * Finishes the item editing mode successfully.
  	 */
  	Controller.prototype.editItemSave = function (id, title) {
  		var self = this;
  
  		title = title.trim()
  
  		if (title.length !== 0) {
  			self.model.update(id, {title: title}, function () {
  				self.view.render('editItemDone', {id: id, title: title});
  			});
  		} else {
  			self.removeItem(id);
  		}
  	};
  
  	/*
  	 * Cancels the item editing mode.
  	 */
  	Controller.prototype.editItemCancel = function (id) {
  		var self = this;
  		self.model.read(id, function (data) {
  			self.view.render('editItemDone', {id: id, title: data[0].title});
  		});
  	};
  
  	/**
  	 * By giving it an ID it'll find the DOM element matching that ID,
  	 * remove it from the DOM and also remove it from storage.
  	 *
  	 * @param {number} id The ID of the item to remove from the DOM and
  	 * storage
  	 */
  	Controller.prototype.removeItem = function (id) {
  		var self = this;
  		var items;
  		self.model.read(function(data) {
  			items = data;
  		});
  
  		self.model.remove(id, function () {
  			self.view.render('removeItem', id);
  		});
  
  		self._filter();
  	};
  
  	/**
  	 * Will remove all completed items from the DOM and storage.
  	 */
  	Controller.prototype.removeCompletedItems = function () {
  		var self = this;
  		self.model.read({ completed: true }, function (data) {
  			data.forEach(function (item) {
  				self.removeItem(item.id);
  			});
  		});
  
  		self._filter();
  	};
  
  	/**
  	 * Give it an ID of a model and a checkbox and it will update the item
  	 * in storage based on the checkbox's state.
  	 *
  	 * @param {number} id The ID of the element to complete or uncomplete
  	 * @param {object} checkbox The checkbox to check the state of complete
  	 *                          or not
  	 * @param {boolean|undefined} silent Prevent re-filtering the todo items
  	 */
  	Controller.prototype.toggleComplete = function (id, completed, silent) {
  		var self = this;
  		self.model.update(id, { completed: completed }, function () {
  			self.view.render('elementComplete', {
  				id: id,
  				completed: completed
  			});
  		});
  
  		if (!silent) {
  			self._filter();
  		}
  	};
  
  	/**
  	 * Will toggle ALL checkboxes' on/off state and completeness of models.
  	 * Just pass in the event object.
  	 */
  	Controller.prototype.toggleAll = function (completed) {
  		var self = this;
  		self.model.read({ completed: !completed }, function (data) {
  			data.forEach(function (item) {
  				self.toggleComplete(item.id, completed, true);
  			});
  		});
  
  		self._filter();
  	};
  
  	/**
  	 * Updates the pieces of the page which change depending on the remaining
  	 * number of todos.
  	 */
  	Controller.prototype._updateCount = function () {
  		var self = this;
  		self.model.getCount(function (todos) {
  			self.view.render('updateElementCount', todos.active);
  			self.view.render('clearCompletedButton', {
  				completed: todos.completed,
  				visible: todos.completed > 0
  			});
  
  			self.view.render('toggleAll', {checked: todos.completed === todos.total});
  			self.view.render('contentBlockVisibility', {visible: todos.total > 0});
  		});
  	};
  
  	/**
  	 * Re-filters the todo items, based on the active route.
  	 * @param {boolean|undefined} force  forces a re-painting of todo items.
  	 */
  	Controller.prototype._filter = function (force) {
  		var activeRoute = this._activeRoute.charAt(0).toUpperCase() + this._activeRoute.substr(1);
  
  		// Update the elements on the page, which change with each completed todo
  		this._updateCount();
  
  		// If the last active route isn't "All", or we're switching routes, we
  		// re-create the todo item elements, calling:
  		//   this.show[All|Active|Completed]();
  		if (force || this._lastActiveRoute !== 'All' || this._lastActiveRoute !== activeRoute) {
  			this['show' + activeRoute]();
  		}
  
  		this._lastActiveRoute = activeRoute;
  	};
  
  	/**
  	 * Simply updates the filter nav's selected states
  	 */
  	Controller.prototype._updateFilterState = function (currentPage) {
  		// Store a reference to the active route, allowing us to re-filter todo
  		// items as they are marked complete or incomplete.
  		this._activeRoute = currentPage;
  
  		if (currentPage === '') {
  			this._activeRoute = 'All';
  		}
  
  		this._filter();
  
  		this.view.render('setFilter', currentPage);
  	};
  
  	// Export to window
  	window.app = window.app || {};
  	window.app.Controller = Controller;
  })(window);