(function() {

	'use strict';



	var L = require('leaflet');

	var Formatter = require('./formatter');

	var ItineraryBuilder = require('./itinerary-builder');



	module.exports = L.Control.extend({

		includes: ((typeof L.Evented !== 'undefined' && L.Evented.prototype) || L.Mixin.Events),



		options: {

			pointMarkerStyle: {

				radius: 5,

				color: '#03f',

				fillColor: 'white',

				opacity: 1,

				fillOpacity: 0.7

			},

			summaryTemplate: '<h2>{name}</h2><h3>{distance}, {time}</h3>',

			timeTemplate: '{time}',

			containerClassName: '',

			alternativeClassName: '',

			minimizedClassName: '',

			itineraryClassName: '',

			totalDistanceRoundingSensitivity: -1,

			show: true,

			collapsible: undefined,

			collapseBtn: function(itinerary) {

				var collapseBtn = L.DomUtil.create('span', itinerary.options.collapseBtnClass);

				L.DomEvent.on(collapseBtn, 'click', itinerary._toggle, itinerary);

				itinerary._container.insertBefore(collapseBtn, itinerary._container.firstChild);

			},

			collapseBtnClass: 'leaflet-routing-collapse-btn'

		},



		initialize: function(options) {

			L.setOptions(this, options);

			this._formatter = this.options.formatter || new Formatter(this.options);

			this._itineraryBuilder = this.options.itineraryBuilder || new ItineraryBuilder({

				containerClassName: this.options.itineraryClassName

			});

		},



		onAdd: function(map) {

			var collapsible = this.options.collapsible;



			collapsible = collapsible || (collapsible === undefined && map.getSize().x <= 640);



			this._container = L.DomUtil.create('div', 'leaflet-routing-container leaflet-bar ' +

				(!this.options.show ? 'leaflet-routing-container-hide ' : '') +

				(collapsible ? 'leaflet-routing-collapsible ' : '') +

				this.options.containerClassName);

			this._altContainer = this.createAlternativesContainer();

			this._container.appendChild(this._altContainer);

			L.DomEvent.disableClickPropagation(this._container);

			L.DomEvent.addListener(this._container, 'mousewheel', function(e) {

				L.DomEvent.stopPropagation(e);

			});



			if (collapsible) {

				this.options.collapseBtn(this);

			}



			return this._container;

		},



		onRemove: function() {

		},



		createAlternativesContainer: function() {

			return L.DomUtil.create('div', 'leaflet-routing-alternatives-container');

		},



		setAlternatives: function(routes) {

			var i,

			    alt,

			    altDiv;



			this._clearAlts();



			this._routes = routes;



			for (i = 0; i < this._routes.length; i++) {

				alt = this._routes[i];

				altDiv = this._createAlternative(alt, i);

				this._altContainer.appendChild(altDiv);

				this._altElements.push(altDiv);

			}



			this._selectRoute({route: this._routes[0], alternatives: this._routes.slice(1)});



			return this;

		},



		show: function() {

			L.DomUtil.removeClass(this._container, 'leaflet-routing-container-hide');

		},



		hide: function() {

			L.DomUtil.addClass(this._container, 'leaflet-routing-container-hide');

		},



		_toggle: function() {

			var collapsed = L.DomUtil.hasClass(this._container, 'leaflet-routing-container-hide');

			this[collapsed ? 'show' : 'hide']();

		},



		_createAlternative: function(alt, i) {

			var altDiv = L.DomUtil.create('div', 'leaflet-routing-alt ' +

				this.options.alternativeClassName +

				(i > 0 ? ' leaflet-routing-alt-minimized ' + this.options.minimizedClassName : '')),

				template = this.options.summaryTemplate,

				data = L.extend({

					name: alt.name,

					distance: this._formatter.formatDistance(alt.summary.totalDistance, this.options.totalDistanceRoundingSensitivity),

					time: this._formatter.formatTime(alt.summary.totalTime)

				}, alt);

			altDiv.innerHTML = typeof(template) === 'function' ? template(data) : L.Util.template(template, data);

			L.DomEvent.addListener(altDiv, 'click', this._onAltClicked, this);

			this.on('routeselected', this._selectAlt, this);



			altDiv.appendChild(this._createItineraryContainer(alt));

			return altDiv;

		},



		_clearAlts: function() {

			var el = this._altContainer;

			while (el && el.firstChild) {

				el.removeChild(el.firstChild);

			}



			this._altElements = [];

		},



		_createItineraryContainer: function(r) {

			var container = this._itineraryBuilder.createContainer(),

			    steps = this._itineraryBuilder.createStepsContainer(),

			    i,

			    instr,

			    step,

			    distance,

			    text,

			    icon;



			container.appendChild(steps);



			for (i = 0; i < r.instructions.length; i++) {

				instr = r.instructions[i];

				text = this._formatter.formatInstruction(instr, i);

				distance = this._formatter.formatDistance(instr.distance);

				icon = this._formatter.getIconName(instr, i);

				step = this._itineraryBuilder.createStep(text, distance, icon, steps);



				if(instr.index) {

					this._addRowListeners(step, r.coordinates[instr.index]);

				}

			}



			return container;

		},



		_addRowListeners: function(row, coordinate) {

			L.DomEvent.addListener(row, 'mouseover', function() {

				this._marker = L.circleMarker(coordinate,

					this.options.pointMarkerStyle).addTo(this._map);

			}, this);

			L.DomEvent.addListener(row, 'mouseout', function() {

				if (this._marker) {

					this._map.removeLayer(this._marker);

					delete this._marker;

				}

			}, this);

			L.DomEvent.addListener(row, 'click', function(e) {

				this._map.panTo(coordinate);

				L.DomEvent.stopPropagation(e);

			}, this);

		},



		_onAltClicked: function(e) {

			var altElem = e.target || window.event.srcElement;

			while (!L.DomUtil.hasClass(altElem, 'leaflet-routing-alt')) {

				altElem = altElem.parentElement;

			}



			var j = this._altElements.indexOf(altElem);

			var alts = this._routes.slice();

			var route = alts.splice(j, 1)[0];



			this.fire('routeselected', {

				route: route,

				alternatives: alts

			});

		},



		_selectAlt: function(e) {

			var altElem,

			    j,

			    n,

			    classFn;



			altElem = this._altElements[e.route.routesIndex];



			if (L.DomUtil.hasClass(altElem, 'leaflet-routing-alt-minimized')) {

				for (j = 0; j < this._altElements.length; j++) {

					n = this._altElements[j];

					classFn = j === e.route.routesIndex ? 'removeClass' : 'addClass';

					L.DomUtil[classFn](n, 'leaflet-routing-alt-minimized');

					if (this.options.minimizedClassName) {

						L.DomUtil[classFn](n, this.options.minimizedClassName);

					}



					if (j !== e.route.routesIndex) n.scrollTop = 0;

				}

			}



			L.DomEvent.stop(e);

		},



		_selectRoute: function(routes) {

			if (this._marker) {

				this._map.removeLayer(this._marker);

				delete this._marker;

			}

			this.fire('routeselected', routes);

		}

	});

})();

