text: /**
  * ownCloud
  *
  * @author Vincent Petry
  * @copyright 2014 Vincent Petry <pvince81@owncloud.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  * License as published by the Free Software Foundation; either
  * version 3 of the License, or any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  *
  * You should have received a copy of the GNU Affero General Public
  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
  
  (function() {
  	/**
  	 * @class BreadCrumb
  	 * @memberof OCA.Files
  	 * @classdesc Breadcrumbs that represent the current path.
  	 *
  	 * @param {Object} [options] options
  	 * @param {Function} [options.onClick] click event handler
  	 * @param {Function} [options.onDrop] drop event handler
  	 * @param {Function} [options.getCrumbUrl] callback that returns
  	 * the URL of a given breadcrumb
  	 */
  	var BreadCrumb = function(options){
  		this.$el = $('<div class="breadcrumb"></div>');
  		options = options || {};
  		if (options.onClick) {
  			this.onClick = options.onClick;
  		}
  		if (options.onDrop) {
  			this.onDrop = options.onDrop;
  			this.onOver = options.onOver;
  			this.onOut = options.onOut;
  		}
  		if (options.getCrumbUrl) {
  			this.getCrumbUrl = options.getCrumbUrl;
  		}
  		this._detailViews = [];
  	};
  	/**
  	 * @memberof OCA.Files
  	 */
  	BreadCrumb.prototype = {
  		$el: null,
  		dir: null,
  		dirInfo: null,
  
  		/**
  		 * Total width of all breadcrumbs
  		 * @type int
  		 * @private
  		 */
  		totalWidth: 0,
  		breadcrumbs: [],
  		onClick: null,
  		onDrop: null,
  		onOver: null,
  		onOut: null,
  
  		/**
  		 * Sets the directory to be displayed as breadcrumb.
  		 * This will re-render the breadcrumb.
  		 * @param dir path to be displayed as breadcrumb
  		 */
  		setDirectory: function(dir) {
  			dir = dir.replace(/\\/g, '/');
  			dir = dir || '/';
  			if (dir !== this.dir) {
  				this.dir = dir;
  				this.render();
  			}
  		},
  
  		setDirectoryInfo: function(dirInfo) {
  			if (dirInfo !== this.dirInfo) {
  				this.dirInfo = dirInfo;
  				this.render();
  			}
  		},
  
  		/**
  		 * @param {Backbone.View} detailView
  		 */
  		addDetailView: function(detailView) {
  			this._detailViews.push(detailView);
  		},
  
  		/**
  		 * Returns the full URL to the given directory
  		 *
  		 * @param {Object.<String, String>} part crumb data as map
  		 * @param {int} index crumb index
  		 * @return full URL
  		 */
  		getCrumbUrl: function(part, index) {
  			return '#';
  		},
  
  		/**
  		 * Renders the breadcrumb elements
  		 */
  		render: function() {
  			var parts = this._makeCrumbs(this.dir || '/');
  			var $crumb;
  			this.$el.empty();
  			this.breadcrumbs = [];
  
  			for (var i = 0; i < parts.length; i++) {
  				var part = parts[i];
  				var $image;
  				var $link = $('<a></a>').attr('href', this.getCrumbUrl(part, i));
  				$link.text(part.name);
  				$crumb = $('<div class="crumb svg"></div>');
  				$crumb.append($link);
  				$crumb.attr('data-dir', part.dir);
  
  				if (part.img) {
  					$image = $('<img class="svg"></img>');
  					$image.attr('src', part.img);
  					$image.attr('alt', part.alt);
  					$link.append($image);
  				}
  				this.breadcrumbs.push($crumb);
  				this.$el.append($crumb);
  				if (this.onClick) {
  					$crumb.on('click', this.onClick);
  				}
  			}
  			$crumb.addClass('last');
  
  			_.each(this._detailViews, function(view) {
  				view.render({
  					dirInfo: this.dirInfo
  				});
  				$crumb.append(view.$el);
  			}, this);
  
  			// in case svg is not supported by the browser we need to execute the fallback mechanism
  			if (!OC.Util.hasSVGSupport()) {
  				OC.Util.replaceSVG(this.$el);
  			}
  
  			// setup drag and drop
  			if (this.onDrop) {
  				this.$el.find('.crumb:not(.last)').droppable({
  					drop: this.onDrop,
  					over: this.onOver,
  					out: this.onOut,
  					tolerance: 'pointer',
  					hoverClass: 'canDrop'
  				});
  			}
  
  			this._updateTotalWidth();
  		},
  
  		/**
  		 * Makes a breadcrumb structure based on the given path
  		 *
  		 * @param {String} dir path to split into a breadcrumb structure
  		 * @return {Object.<String, String>} map of {dir: path, name: displayName}
  		 */
  		_makeCrumbs: function(dir) {
  			var crumbs = [];
  			var pathToHere = '';
  			// trim leading and trailing slashes
  			dir = dir.replace(/^\/+|\/+$/g, '');
  			var parts = dir.split('/');
  			if (dir === '') {
  				parts = [];
  			}
  			// root part
  			crumbs.push({
  				dir: '/',
  				name: '',
  				alt: t('files', 'Home'),
  				img: OC.imagePath('core', 'places/home.svg')
  			});
  			for (var i = 0; i < parts.length; i++) {
  				var part = parts[i];
  				pathToHere = pathToHere + '/' + part;
  				crumbs.push({
  					dir: pathToHere,
  					name: part
  				});
  			}
  			return crumbs;
  		},
  
  		/**
  		 * Calculate the total breadcrumb width when
  		 * all crumbs are expanded
  		 */
  		_updateTotalWidth: function () {
  			this.totalWidth = 0;
  			for (var i = 0; i < this.breadcrumbs.length; i++ ) {
  				var $crumb = $(this.breadcrumbs[i]);
  				$crumb.data('real-width', $crumb.width());
  				this.totalWidth += $crumb.width();
  			}
  			this._resize();
  		},
  
  		/**
  		 * Show/hide breadcrumbs to fit the given width
  		 * 
  		 * @param {int} availableWidth available width
  		 */
  		setMaxWidth: function (availableWidth) {
  			if (this.availableWidth !== availableWidth) {
  				this.availableWidth = availableWidth;
  				this._resize();
  			}
  		},
  
  		_resize: function() {
  			var i, $crumb, $ellipsisCrumb;
  
  			if (!this.availableWidth) {
  				this.availableWidth = this.$el.width();
  			}
  
  			if (this.breadcrumbs.length <= 1) {
  				return;
  			}
  
  			// reset crumbs
  			this.$el.find('.crumb.ellipsized').remove();
  
  			// unhide all
  			this.$el.find('.crumb.hidden').removeClass('hidden');
  
  			if (this.totalWidth <= this.availableWidth) {
  				// no need to compute breadcrumbs, there is enough space
  				return;
  			}
  
  			// running width, considering the hidden crumbs
  			var currentTotalWidth = $(this.breadcrumbs[0]).data('real-width');
  			var firstHidden = true;
  
  			// insert ellipsis after root part (root part is always visible)
  			$ellipsisCrumb = $('<div class="crumb ellipsized svg"><span class="ellipsis">...</span></div>');
  			$(this.breadcrumbs[0]).after($ellipsisCrumb);
  			currentTotalWidth += $ellipsisCrumb.width();
  
  			i = this.breadcrumbs.length - 1;
  
  			// find the first section that would cause the overflow
  			// then hide everything in front of that
  			//
  			// this ensures that the last crumb section stays visible
  			// for most of the cases and is always the last one to be
  			// hidden when the screen becomes very narrow
  			while (i > 0) {
  				$crumb = $(this.breadcrumbs[i]);
  				// if the current breadcrumb would cause overflow
  				if (!firstHidden || currentTotalWidth + $crumb.data('real-width') > this.availableWidth) {
  					// hide it
  					$crumb.addClass('hidden');
  					if (firstHidden) {
  						// set the path of this one as title for the ellipsis
  						this.$el.find('.crumb.ellipsized')
  							.attr('title', $crumb.attr('data-dir'))
  							.tooltip();
  						this.$el.find('.ellipsis')
  							.wrap('<a class="ellipsislink" href="' + encodeURI(OC.generateUrl('apps/files/?dir=' + $crumb.attr('data-dir'))) + '"></a>');
  					}
  					// and all the previous ones (going backwards)
  					firstHidden = false;
  				} else {
  					// add to total width
  					currentTotalWidth += $crumb.data('real-width');
  				}
  				i--;
  			}
  
  			if (!OC.Util.hasSVGSupport()) {
  				OC.Util.replaceSVG(this.$el);
  			}
  		}
  	};
  
  	OCA.Files.BreadCrumb = BreadCrumb;
  })();
  
  