Source: temp/jsdocinputdirs/cercalia.widget.routing.js

/**
 * Constructor del widget Routing
 * @class
 * @constructor
 * @param {cercaliax.widget.RoutingOptions} options Opciones del widget de Routing.
 */
cercalia.widget.Routing = function(options) {

    /**
     * Nombre de la classe
     * @private
     * @type {string}
     */
    this.CLASS_NAME_ = "cercalia.widget.Routing";

    /* OPTIONS */

    /**
     * Id del div contenedor.
     * @private
     * @type {string}
     */
    this.divId_ = options.div ? options.div : null;

    /**
     * Height que tendrà el div.
     * @private
     * @type {string|Function}
     */
    this.height_ = options.height ? options.height : "auto";

    /**
     * Número de cajas iniciales
     * @private
     * @type {number}
     */
    this.initialBoxes_ = options.initialBoxes ? options.initialBoxes : 2;

    /**
     * Máximo de cajas permitidas (hasta 10)
     * @private
     * @type {number}
     */
    this.maxBoxes_ = options.maxBoxes ? (options.maxBoxes < 2 ? 2 : (options.maxBoxes > 12 ? 12 : options.maxBoxes)) : 12; // Valor entre 2 i 12

    /**
     * Función para mostrar el DIV del widget al modificar la ruta con el mapa.
     * @private
     * @type {Function}
     */
    this.showUICallback_ = options.showUI ? options.showUI : null;

    /**
     * Activa (opcionalmente o obligatoriamente) o desactiva el calculo de las rutas con la red de logistics. 
     * Valores possibles: 'off', 'optional', 'on'. Default 'off'
     * @private
     * @type {string}
     */
    this.logistics_ = options.logistics ? options.logistics : 'off';

    /**
     * @private
     * @type {string}
     */
    this.defaultCountry_ = options.defaultCountry ? options.defaultCountry : null; 
    
    
    /* Variables privadas */

    /**
     * Mapa. Mejor añadirlo via función setMap.
     * @private
     * @type {cercalia.map}
     */
    this.map_ = options.map ? options.map : null;

    /**
     * @private
     * @type {Object}
     */
    this.sortList_ = null;

    /**
     * Número de cajas instanciadas
     * @private
     * @type {number}
     */
    this.stopCounter_ = 0;

    /**
     * Opciones de busqueda de la ruta
     * @private
     * @type {Object}
     */
    this.optionsRoute_ = {
        weight: "time",
        reorder: false
    };

    /**
     * Ruta actual (respuesta de cercalia)
     * @private
     * @type {Object}
     */
    this.currentRoute_ = null;


    /**
     * Panel para configurar la ruta
     * @private
     * @type {Object}
     */
    this.routingPane_ = null;

    /**
     * Panel del report
     * @private
     * @type {Object}
     */
    this.reportPane_ = null;

    /**
     * @private
     * @type {boolena}
     */
    this.logisticsRoute_ = false;

    /**
     * @private
     * @type {Array.<string>}
     */
    this.logisticsRouteValues_ = {};

    /* Servicios y Widgets de cercalia */

    /**
     * Lista de objetos Autocompletes
     * @private
     * @type {Array.<cercalia.widget.GeocodingSuggest>}
     */
    this.autocompleteList_ = [];

    /**
     * Lista de objetos Autocompletes
     * @private
     * @type {Array.<cercalia.widget.GeocodingSuggest>}
     */
    this.stepsSortList_ = [ ];
    
    /**
     * Servicio routing para calcular la ruta
     * @private
     * @type {cercalia.RouteMap}
     */
    this.routing_ = null;

    /**
     * Servicio routing para calcular la ruta tipo logistics
     * @private
     * @type {cercalia.service.LogisticsRouting}
     */
    this.routingLogistics_ = null;

    /**
     * Servicio routing que se utiliza en este momento.
     * @private
     * @type {cercalia.service.Routing|cercalia.service.LogisticsRouting}
     */
    this.routingUsed_ = null;

    /**
     * Servicio geocoding para obtener datos de origen y destino si no los tenemos.
     * @private
     * @type {cercalia.service.ReverseGeocoding}
     */
    this.reverseGeocoding_ = null;

    /**
     * Reporte lateral.
     * @private
     * @type {cercalia.widget.RoutingReport}
     */
    this.lateralRoutingReport_ = null;
    
	/**
	 * @private
	 * @type {jQueryElement}
	 */
	this.dialogPrint_ = null;

    this.initialize_();
};

/**
 * Inicializa el elemento
 * @private
 */
cercalia.widget.Routing.prototype.initialize_ = function() {
	
    if (!this.divId_) {
        cercalia.Exception(cercalia.i18n._('WIDGET_ERR_NO_DIV "%"', this.CLASS_NAME_));
    } else {

        // Inicializamos componentes
        var height;
        if (typeof (this.height_) === "function") {
            height = this.height_();
        } else {
            height = this.height_;
        }

        var element = cercalia.jQuery("#" + this.divId_)
        				.addClass("cercalia-widget cercalia-widget-routing");
        
        this.routingLogistics_ = new cercalia.service.LogisticsRouting({
            report: true
        });

        //this.routingUsed_ = this.routing_;
        this.reverseGeocoding_ = new cercalia.service.ReverseGeocoding();
        var self = this;

        // Panel de routing
        this.routingPane_ = cercalia.jQuery("<div />")
        						.attr("id", this.divId_ + "-routingPane")
        						.addClass("cercalia-widget-routing-routingPane")
        					.appendTo(element);

        // Panel del report
        this.reportPane_ = cercalia.jQuery("<div />")
        						.addClass("cercalia-widget-routing-reportPane cercalia-widget-routing-reportPane-normal")
        						.hide()
        					.appendTo(element);

        cercalia.jQuery("<i />")
        	.addClass("cercalia-widget-routing-reportPane-normalText")
        	.html(cercalia.i18n._('ROUTING_NORMAL'))
        	.hide()
        .appendTo(this.reportPane_);
        
        cercalia.jQuery("<i />")
        	.addClass("cercalia-widget-routing-reportPane-logisticsText")
        	.html(cercalia.i18n._('ROUTING_LOGISTICS'))
        	.hide()
        .appendTo(this.reportPane_);
        	

        cercalia.jQuery("<button />")
			.addClass("cercalia-widget-routing-reportPane-new")
			.html(cercalia.i18n._('ROUTING_MODIFY'))
			.button()
			.click(function() {
				//self.lateralRoutingReport_.clean();
				//self.reportPane_.hide();
				self.routingPane_.show();
				//self.routing_.removeRoute();
			})
		.appendTo(this.reportPane_);
		
        cercalia.jQuery("<button />")
			.addClass("cercalia-widget-routing-reportPane-print")
			.button()
			.click(function() {
				self.printReport();
			})
		.appendTo(this.reportPane_);
		
        cercalia.jQuery("<button />")
			.addClass("cercalia-widget-routing-reportPane-save")
			.button()
			.click(function() {
				self.saveKml();
			})
		.appendTo(this.reportPane_);

        var reportPane = cercalia.jQuery("<div />").attr("id", this.divId_ + "-reportPane").appendTo(this.reportPane_);

        this.lateralRoutingReport_ = new cercalia.widget.RoutingReport({
            div: reportPane.attr("id"),
            map: this._map,
            routingService: this.routingUsed_
        });

        // Creamos la lista de cajas ordenables y dragables.
        this.sortList_ = cercalia.jQuery("<ul />").addClass("cercalia-widget-routing-draggable").appendTo(this.routingPane_).sortable({
            axis: "y",
            start: function(event, ui) {
                cercalia.jQuery("#" + self.divId_ + " .cercalia-widget-routing-revert").hide();
                cercalia.jQuery(ui.item).addClass("cercalia-widget-routing-dragging");
            },
            stop: function(event, ui) {
                self.refresh(false, true);
                cercalia.jQuery(ui.item).removeClass("cercalia-widget-routing-dragging");
            }
        });

        // Añadimos las cajas iniciales predefinidas.
        for (this.stopCounter_ = 0; this.stopCounter_ < this.initialBoxes_;) { // Se incrementa en el addBox_!
            this.addBox_();
        }
        this.refresh();

        // Añadimos controles y opciones.
        var control = cercalia.jQuery("<div />")
        				.addClass("cercalia-widget-routing-controls")
        			.appendTo(this.routingPane_);

        // - Añadir destino
        var addControl = cercalia.jQuery("<div />")
        					.addClass("cercalia-widget-routing-control")
        				.appendTo(control);

        var addControlLink = cercalia.jQuery("<a />")
        						.attr("href", "#")
        						.addClass("cercalia-widget-routing-control-text")
        						.html(cercalia.i18n._("ROUTING_ADD_BOX"))
        						.click(function() {
        							self.addStop(); // Añadimos caja.
        					})
        					.appendTo(addControl);

        
        cercalia.jQuery("<span />")
        	.addClass("ui-icon cercalia-icon cercalia-icon-poiAdd cercalia-widget-routing-control-first-icon")
        .appendTo(addControlLink);

        // - Opciones ruta
        var optionsRouteControl = cercalia.jQuery("<div />")
        							.addClass("cercalia-widget-routing-control ui-widget")
        						.appendTo(control);

        var show = false;
        var optionsRouteControlLink = cercalia.jQuery("<a />")
        								.attr("href", "#")
        								.addClass("cercalia-widget-routing-control-text")
        								.html(cercalia.i18n._("ROUTING_OPTIONS_ROUTE"))
        								.click(function() {
        									optionsRouteDivControl.toggle({
        										effect: "blind"
        									});
        									if (!show) { 
        										arrow.removeClass("cercalia-icon-arrowDown").addClass("cercalia-icon-arrowUp");
        									} else {
        										arrow.addClass("cercalia-icon-arrowDown").removeClass("cercalia-icon-arrowUp");
        									}
        									show = !show;
        								})
        							.appendTo(optionsRouteControl);

        cercalia.jQuery("<span />")
        	.addClass("ui-icon cercalia-icon cercalia-icon-options cercalia-widget-routing-control-first-icon")
        .appendTo(optionsRouteControlLink);
        
        var arrow = cercalia.jQuery("<span />")
        				.addClass("ui-icon cercalia-icon cercalia-icon-arrowDown cercalia-widget-routing-control-second-icon")
        			.appendTo(optionsRouteControlLink);

        var optionsRouteDivControl = cercalia.jQuery("<div />")
        								.addClass("cercalia-widget-routing-control-optionsRoute ui-widget-content")
        							.appendTo(optionsRouteControl);
        
        this.optionsRouteDraw_(optionsRouteDivControl);

        // - Logistics. 'off' -> nada, 'on' -> opciones siempre visibles, 'optional' -> opciones solo visibles si check on
      if (this.logistics_ == 'optional' || this.logistics_ == 'on') {

            var logisticsRouteControl = cercalia.jQuery("<div />")
            								.addClass("cercalia-widget-routing-control ui-widget")
            							.appendTo(control);
            
            var logisitcsRouteControlLink = cercalia.jQuery("<a />")
            									.attr("href", "#")
            									.addClass("cercalia-widget-routing-control-text")
            									.html(cercalia.i18n._("ROUTING_LOGISTICS_ROUTE"))
            						            .click(function(ev) {
            						            	if (self.logistics_ == 'optional') {
            						            		ev.stopPropagation();
            						            		logisticsCheck.click();
            						            	}
            						            })
            								.appendTo(logisticsRouteControl);

            cercalia.jQuery("<span />")
            	.addClass("ui-icon cercalia-icon cercalia-icon-truck cercalia-widget-routing-control-first-icon")
            .appendTo(logisitcsRouteControlLink);

            var logisticView = false;
            var logisticsCheck = cercalia.jQuery("<input />").attr('type', 'checkbox').addClass("cercalia-widget-routing-control-logistics").appendTo(logisitcsRouteControlLink).click(function(ev) {
                ev.stopPropagation();
                if (!logisticView) {
                    // Servicio de rutas logistics
                    self.logisticsRoute_ = true;

                    // Modificamos el servicio en uso al de routing logistics
                    self.routingUsed_ = self.routingLogistics_;
                    self.lateralRoutingReport_.setRoutingService(self.routingLogistics_);

                    // Cambio de estilos del report
                    self.reportPane_.addClass('cercalia-widget-routing-reportPane-logistics');
                    self.reportPane_.removeClass('cercalia-widget-routing-reportPane-normal');

                } else {
                    // Servicio de rutas normal
                    self.logisticsRoute_ = false;

                    // Modificamos el servicio en uso al de routing
                    self.routingUsed_ = self.routing_.getService();
                    self.lateralRoutingReport_.setRoutingService(self.routingUsed_);

                    // Cambio de estilos del report
                    self.reportPane_.removeClass('cercalia-widget-routing-reportPane-logistics');
                    self.reportPane_.addClass('cercalia-widget-routing-reportPane-normal');
                }

                logisticsRouteDivControl.toggle({
                    effect: "blind"
                });
                
                logisticView = !logisticView;
            });

            var logisticsRouteDivControl = cercalia.jQuery("<div />").addClass("cercalia-widget-routing-control-optionsRoute ui-widget-content").appendTo(logisticsRouteControl);

            if (this.logistics_ == 'on') {
                logisticsCheck.hide();
                logisticsCheck.click();
            }

            this.logisticsRouteDraw_(logisticsRouteDivControl);
       }

        // - Calcular ruta
        cercalia.jQuery("<button />")
        	.attr("id", this.divId_ + "_find")
        	.addClass("cercalia-widget-routing-find")
        	.html(cercalia.i18n._("ROUTING_FIND"))
        	.button().click(function() {            
        		self.reInitStepList_();
        		self.routing_.sincronize(self);
        		self.routing_.calculateRoute(); // Calculamos la ruta.
        	})
        .appendTo(this.routingPane_);

        cercalia.jQuery("<div />")
        	.addClass("cercalia-clean")
        .appendTo(this.routingPane_);

        // Resize del component
        cercalia.jQuery(window).resize(function() {
            window.setTimeout(self.resize, 500);
        });
        
        this.resize();
    }
};

/**
 * Muestra las opciones de la ruta en el panel.
 * @private
 * @param {Object} divContent Div donde se muestran las opciones.
 */
cercalia.widget.Routing.prototype.optionsRouteDraw_ = function(divContent) {

    // Tipo de ruta
    var self = this;
    var routeType = cercalia.jQuery("<div />").addClass("cercalia-widget-routing-control-optionRoute cercalia-widget-routing-control-optionRoute-type").appendTo(divContent);
    cercalia.jQuery("<span />").html(cercalia.i18n._("ROUTING_ROUTE_TYPE")).appendTo(routeType);
    cercalia.jQuery("<br />").appendTo(routeType);

    cercalia.jQuery("<input />").attr("type", "radio").attr("name", this.divId_ + "_optionRoute_type").attr("value", "time").appendTo(routeType);
    cercalia.jQuery("<span />").html(cercalia.i18n._("ROUTING_ROUTE_TYPE_TIME")).appendTo(routeType);
    cercalia.jQuery("<input />").attr("type", "radio").attr("name", this.divId_ + "_optionRoute_type").attr("value", "distance").appendTo(routeType);
    cercalia.jQuery("<span />").html(cercalia.i18n._("ROUTING_ROUTE_TYPE_DISTANCE")).appendTo(routeType);
	cercalia.jQuery("<br/>").appendTo(routeType);
    cercalia.jQuery("<input />").attr("type", "radio").attr("name", this.divId_ + "_optionRoute_type").attr("value", "money").appendTo(routeType);
    cercalia.jQuery("<span />").html(cercalia.i18n._("ROUTING_ROUTE_TYPE_MONEY")).appendTo(routeType);
    cercalia.jQuery("<input />").attr("type", "radio").attr("name", this.divId_ + "_optionRoute_type").attr("value", "realtime").appendTo(routeType);
    cercalia.jQuery("<span />").html(cercalia.i18n._("ROUTING_ROUTE_TYPE_REALTIME")).appendTo(routeType);

    cercalia.jQuery("input[value='" + this.optionsRoute_.weight + "']").attr("checked", "checked");
    cercalia.jQuery("input[name='" + this.divId_ + "_optionRoute_type']").change(function() {
        self.optionsRoute_.weight = cercalia.jQuery(this).val();
    });

    // Reordenar puntos de paso
    var reorder = cercalia.jQuery("<div />").addClass("cercalia-widget-routing-control-optionRoute cercalia-widget-routing-control-optionRoute-reorder").appendTo(divContent);
    var reorderCheckbox = cercalia.jQuery("<input />").attr("type", "checkbox").attr("name", this.divId_ + "_optionRoute_reorder").appendTo(reorder);
    
    cercalia.jQuery("<span />")
    	.html(cercalia.i18n._("ROUTING_ROUTE_REORDER"))
    .appendTo(reorder);

    if (this.optionsRoute_.reorder) reorderCheckbox.attr("checked", "checked");
    reorderCheckbox.change(function() {
        self.optionsRoute_.reorder = reorderCheckbox[0].checked;
    });
};

/**
 * Muestra las opciones de la ruta en el panel.
 * @private
 * @param {Object} divContent Div donde se muestran las opciones.
 */
cercalia.widget.Routing.prototype.logisticsRouteDraw_ = function(divContent) {

    // Tipo de ruta
    var self = this;
    // var routeType = cercalia.jQuery("<div />").appendTo(divContent);

    // Peso máximo total
    var elementPesoMaximoTotal = cercalia.jQuery('<div />').addClass("cercalia-widget-routing-logistics-optionRoute").appendTo(divContent);
    var chkPesoMaximo = cercalia.jQuery('<input />').attr('type', 'checkbox').addClass('cercalia-logistics-check').appendTo(elementPesoMaximoTotal).click(function() {

        if (this.checked) {
            self.logisticsRouteValues_["WEIGHT"] = true;
        } else {
            self.logisticsRouteValues_["WEIGHT"] = false;
        }
    });
    cercalia.jQuery("<span />").addClass("ui-icon cercalia-logistics-icon cercalia-logistics-icon-weight").appendTo(elementPesoMaximoTotal);
    cercalia.jQuery('<span />').html(cercalia.i18n._('Total maximum weight')).addClass('cercalia-logistics-text').appendTo(elementPesoMaximoTotal);
    cercalia.jQuery('<input />').attr('title', cercalia.i18n._('tonnes')).attr('type', 'text').addClass('cercalia-logistics-value').appendTo(elementPesoMaximoTotal).change(function() {

        self.logisticsRouteValues_["WEIGHT_VALUE"] = this.value;
        if (!chkPesoMaximo[0].checked) {
        	chkPesoMaximo.click();
        }
        if (chkPesoMaximo[0].checked && (this.value == null || this.value.length <= 0)) {
        	chkPesoMaximo.click();
        }

    });
    cercalia.jQuery('<span />').html('tn').addClass('cercalia-logistics-units').appendTo(elementPesoMaximoTotal);

    // Peso máximo del eje
    var elementPesoMaximoEje = cercalia.jQuery('<div />').addClass("cercalia-widget-routing-logistics-optionRoute").appendTo(divContent);
    var chkPesoMaximoEje = cercalia.jQuery('<input />').attr('type', 'checkbox').addClass('cercalia-logistics-check').appendTo(elementPesoMaximoEje).click(function() {
    	self.logisticsRouteValues_["WEIGHTAXL"] = this.checked;
    });
    cercalia.jQuery("<span />").addClass("ui-icon cercalia-logistics-icon cercalia-logistics-icon-weightaxl").appendTo(elementPesoMaximoEje);
    cercalia.jQuery('<span />').html(cercalia.i18n._('Maximum axle weight')).addClass('cercalia-logistics-text').appendTo(elementPesoMaximoEje);
    cercalia.jQuery('<input />').attr('title', cercalia.i18n._('tonnes')).attr('type', 'text').addClass('cercalia-logistics-value').appendTo(elementPesoMaximoEje).change(function() {

        self.logisticsRouteValues_["WEIGHTAXL_VALUE"] = this.value;
        if (!chkPesoMaximoEje[0].checked) chkPesoMaximoEje.click();
        if (chkPesoMaximoEje[0].checked && (this.value == null || this.value.length <= 0)) chkPesoMaximoEje.click();

    });
    cercalia.jQuery('<span />').html('tn').addClass('cercalia-logistics-units').appendTo(elementPesoMaximoEje);

    // Altura máxima
    var elementAltoMaximo = cercalia.jQuery('<div />').addClass("cercalia-widget-routing-logistics-optionRoute").appendTo(divContent);
    var chkAltoMaximo = cercalia.jQuery('<input />').attr('type', 'checkbox').addClass('cercalia-logistics-check').appendTo(elementAltoMaximo).click(function() {
    	self.logisticsRouteValues_["HEIGHT"] = this.checked;
    });
    cercalia.jQuery("<span />").addClass("ui-icon cercalia-logistics-icon cercalia-logistics-icon-height").appendTo(elementAltoMaximo);
    cercalia.jQuery('<span />').html(cercalia.i18n._('Maximum height')).addClass('cercalia-logistics-text').appendTo(elementAltoMaximo);
    cercalia.jQuery('<input />').attr('title', cercalia.i18n._('meters')).attr('type', 'text').addClass('cercalia-logistics-value').appendTo(elementAltoMaximo).change(function() {

        self.logisticsRouteValues_["HEIGHT_VALUE"] = this.value;
        if (!chkAltoMaximo[0].checked) {
        	chkAltoMaximo.click();
        }
        if (chkAltoMaximo[0].checked && (this.value == null || this.value.length <= 0)) {
        	chkAltoMaximo.click();
        }

    });
    cercalia.jQuery('<span />').html('m').addClass('cercalia-logistics-units').appendTo(elementAltoMaximo);

    // Longitud máxima
    var elementLongitudMaxima = cercalia.jQuery('<div />').addClass("cercalia-widget-routing-logistics-optionRoute").appendTo(divContent);
    var chkLongitudMaxima = cercalia.jQuery('<input />').attr('type', 'checkbox').addClass('cercalia-logistics-check').appendTo(elementLongitudMaxima).click(function() {
    	self.logisticsRouteValues_["LENGTH"] = this.checked;
    });
    cercalia.jQuery("<span />").addClass("ui-icon cercalia-logistics-icon cercalia-logistics-icon-length").appendTo(elementLongitudMaxima);
    cercalia.jQuery('<span />').html(cercalia.i18n._('Maximum length')).addClass('cercalia-logistics-text').appendTo(elementLongitudMaxima);
    cercalia.jQuery('<input />').attr('title', cercalia.i18n._('meters')).attr('type', 'text').addClass('cercalia-logistics-value').appendTo(elementLongitudMaxima).change(function() {
        self.logisticsRouteValues_["LENGTH_VALUE"] = this.value;
        if (!chkLongitudMaxima[0].checked) {
        	chkLongitudMaxima.click();
        }
        if (chkLongitudMaxima[0].checked && (this.value == null || this.value.length <= 0)) {
        	chkLongitudMaxima.click();
        }
    });
    cercalia.jQuery('<span />').html('m').addClass('cercalia-logistics-units').appendTo(elementLongitudMaxima);

    // Anchura máxima
    var elementAnchoMaximo = cercalia.jQuery('<div />').addClass("cercalia-widget-routing-logistics-optionRoute").appendTo(divContent);
    var chkAnchoMaximo = cercalia.jQuery('<input />').attr('type', 'checkbox').addClass('cercalia-logistics-check').appendTo(elementAnchoMaximo).click(function() {
    	self.logisticsRouteValues_["WIDTH"] = this.checked;
    });
    cercalia.jQuery("<span />").addClass("ui-icon cercalia-logistics-icon cercalia-logistics-icon-width").appendTo(elementAnchoMaximo);
    cercalia.jQuery('<span />').html(cercalia.i18n._('Maximum width')).addClass('cercalia-logistics-text').appendTo(elementAnchoMaximo);
    cercalia.jQuery('<input />').attr('title', cercalia.i18n._('meters')).attr('type', 'text').addClass('cercalia-logistics-value').appendTo(elementAnchoMaximo).change(function() {
        self.logisticsRouteValues_["WIDTH_VALUE"] = this.value;
        if (!chkAnchoMaximo[0].checked) { 
        	chkAnchoMaximo.click();
        }
        if (chkAnchoMaximo[0].checked && (this.value == null || this.value.length <= 0)) {
        	chkAnchoMaximo.click();
        }
    });
    cercalia.jQuery('<span />').html('m').addClass('cercalia-logistics-units').appendTo(elementAnchoMaximo);

	// Mercancías peligrosas 
    var elementMercanciasPeligrosas = cercalia.jQuery('<div />').addClass("cercalia-widget-routing-logistics-optionRoute").appendTo(divContent);
    var chkAnchoMaximo = cercalia.jQuery('<input />').attr('type', 'checkbox').addClass('cercalia-logistics-check').appendTo(elementMercanciasPeligrosas).click(function() {
    	self.logisticsRouteValues_["RIMP"] = this.checked;
    });
    cercalia.jQuery("<span />").addClass("ui-icon cercalia-logistics-icon cercalia-logistics-icon-dangerous-goods").appendTo(elementMercanciasPeligrosas);
    cercalia.jQuery('<span />').html(cercalia.i18n._('Dangerous goods')).addClass('cercalia-logistics-text').appendTo(elementMercanciasPeligrosas);

	
    // Velocidad máxima
    var elementVelocidadMaxima = cercalia.jQuery('<div />').addClass("cercalia-widget-routing-logistics-optionRoute").appendTo(divContent);
    var chkVelocidadMaxima = cercalia.jQuery('<input />').attr('type', 'checkbox').addClass('cercalia-logistics-check').appendTo(elementVelocidadMaxima).click(function() {
    	self.logisticsRouteValues_["MAXVEL"] = this.checked;
    });
    
    cercalia.jQuery('<span />')
    	.html(cercalia.i18n._('Maximum speed'))
    	.addClass('cercalia-logistics-text cercalia-logistics-text-noblank')
    .appendTo(elementVelocidadMaxima);
    
    cercalia.jQuery('<input />')
    	.attr('title', 'km/h')
    	.attr('type', 'text')
    	.addClass('cercalia-logistics-value')
    .appendTo(elementVelocidadMaxima).change(function() {
        self.logisticsRouteValues_["MAXVEL_VALUE"] = this.value;
        if (!chkVelocidadMaxima[0].checked) {
        	chkVelocidadMaxima.click();
        }
        if (chkVelocidadMaxima[0].checked && (this.value == null || this.value.length <= 0)) {
        	chkVelocidadMaxima.click();
        }
    });
	
    cercalia.jQuery('<span />')
    	.html('km/h')
    	.addClass('cercalia-logistics-units')
    .appendTo(elementVelocidadMaxima);



};

/**
 * Recalcula el tamaño del widget
 * @param {number} height: Altura del widget. Si no se define y se ha definido una funcion de height se recalculara utilizando esta.
 */
cercalia.widget.Routing.prototype.resize = function(height) {

    var new_height;

    if (typeof (height) === "undefined" || height === null) {
        if (typeof (this.height_) === "function") {
            new_height = this.height_();
        } else {
            new_height = this.height_;
        }
    } else {
        new_height = height;
    }

    var element = cercalia.jQuery("#" + this.divId_).css("height", new_height);
};

/**
 * Modifica el mapa con el que interactua el widget.
 * @param {cercalia.Map} map Mapa con el que interactuará el Widget.
 */
cercalia.widget.Routing.prototype.setMap = function(map) {
    this.map_ = map;
    if (this.lateralRoutingReport_ != null) {
    	this.lateralRoutingReport_.setMap(map);
    }
};

/**
 * Reordena los contenidos de las cajas segun se haya modificado. Tambien las imagenes de cada caja....
 * @param {boolean} recenter Centra el mapa con los marcadores de ruta.
 * @param {boolean} override
 */
cercalia.widget.Routing.prototype.refresh = function(recenter, override) {

	    var sortList = this.sortList_.find("li");
	    var markersToCenter = [];
	    
	    for (var newPos = 0; newPos < sortList.length; newPos++) {
	        var sort = cercalia.jQuery(sortList[newPos]);
	        var imageNum = "A";
	        
	        if (newPos == 0){
	            imageNum = "A";
	        } else if (newPos == sortList.length - 1){
	        	imageNum = "B";
	        } else {
	            imageNum = newPos;
	        }
	
	        sort.attr("data-position", newPos);
	        sort.find(".cercalia-widget-routing-icon .ui-icon").removeClass().addClass("ui-icon cercalia-icon cercalia-marker-icon-" + imageNum);
	    }
	
	    cercalia.jQuery("#" + this.divId_ + " .cercalia-widget-routing-revert").hide();
	    cercalia.jQuery("#" + this.divId_ + " .cercalia-widget-routing-icon-close").hide();
	
	    if (sortList.length <= 2) {
	        cercalia.jQuery(sortList[0]).find(".cercalia-widget-routing-revert").show();
	    } else {
	        cercalia.jQuery("#" + this.divId_ + " .cercalia-widget-routing-icon-close").show();
	    }
	    
	if(override) {
        if(this.routing_ !== undefined && this.routing_ != null){
        	this.routing_.sincronize(this);
        }
    }
};

/**
 * @return {Array} list of geocodings
 */
cercalia.widget.Routing.prototype.getStops = function() {
	
	var stops = [ ];
	var sortList = this.sortList_.find("li");
    
    for (var i = 0; i < sortList.length; i++) {
    	stops.push( sortList[i].geocoding );
    }
    
    return stops;
};

/**
 * Guarda el resultado de la busqueda (Autocomplete)
 * @private
 * @param {number|string} stop Indice de la caja
 * @param {Object} result Resultado del routing
 * @param {cercalia.LonLat} realCoord
 */
cercalia.widget.Routing.prototype.autocompleteCallback_ = function(stop, result, realCoord, stopId) {
	var self = this;
    var sortList = this.sortList_.find("li");
    
    if (sortList[stop]) {
        sortList[stop].geocoding = result;
        if(realCoord) {
			realCoord["geocoding"] = result;
		}

        // Modifiquem la pos del marker o el creem si no existeix.
        if (sortList[stop].marker) {
            sortList[stop].marker.setPosition(new cercalia.LonLat(result.coord.x, result.coord.y));
        } else {

        	var p;
        	if(realCoord){
        		p = realCoord;
        		result.coord.x = p.getLon();
        		result.coord.y = p.getLat();
        	} else {
            	var x = result.coord.x;
            	var y = result.coord.y;
        		p = new cercalia.LonLat(x, y);
        	}
        	
        	var stop = parseInt(stop);
        	switch(stop) {
	            case 0:
	            	this.routing_.setOrigin(p, false, result.label);
	                break;
	            case sortList.length -1:
	            	this.routing_.setDestination(p, false, result.label);
	                break;
	            default:
	            	this.routing_.setStep(p, false, result.label, stop -1, true);
        	}
        }

    } else {
    	console.warn("No box at index: " + stop);
    }

    this.refresh(true, false);
};

/**
 * Modifica la ruta segun donde se haya dragado el marker.
 * @private
 * @param {cercalia.Marker} marker Marker draggado.
 * @param {cercalia.LonLat} newPosition
 */
cercalia.widget.Routing.prototype.dragEndCallback_ = function(marker, newPosition) {

    if (marker.stopId == 'o') {
    	 this.routing_.setOrigin(newPosition);
    } else if (marker.stopId == 'd') {
    	 this.routing_.setDestination(newPosition);
    } else {
    	 this.routing_.setStep(newPosition);
    }
};


/**
 * Añade una caja al final de la lista de puntos de parada.
 * @private
 */
cercalia.widget.Routing.prototype.addBox_ = function() {
    var imageNum = "A";

    // Creamos li que será dragable (contenedor)
    var divContainer = cercalia.jQuery("<li />").addClass("cercalia-widget-routing-stop").attr("data-position", 0)/*.attr("id", this.divId_ + "_" + this.stopCounter_)**/.appendTo(this.sortList_);

    // Separador superior
    cercalia.jQuery("<div />").addClass("cercalia-widget-routing-hr cercalia-widget-routing-hr-top").appendTo(divContainer);

    // Icono marker
    var divIcon = cercalia.jQuery("<div />").addClass("cercalia-widget-routing-icon").appendTo(divContainer);
    cercalia.jQuery("<span />").addClass("ui-icon cercalia-icon cercalia-marker-icon-" + imageNum).appendTo(divIcon);

    // Creamos el autocomplete
    var divAutocomplete = cercalia.jQuery("<div />").addClass("cercalia-widget-routing-autocomplete").attr("id", this.divId_ + "Autocomplete_" + (new Date()).getTime()).appendTo(divContainer);
    var self = this;
    var stop = this.stopCounter_;
    var autocomplete = new cercalia.widget.GeocodingSuggest({
        div: divAutocomplete.attr("id"),
        map: this.map_,
        defaultCountry: this.defaultCountry_,
        complete: function(result) {
            result.label = result.name.value;
            var stop = divContainer.attr("data-position");
            self.autocompleteCallback_(stop, result);
        }
    });
    autocomplete.routingBox = divContainer;
    this.autocompleteList_.push(autocomplete);

    // Icono para eliminar caja
    var divIconClose = cercalia.jQuery("<div />").addClass("cercalia-widget-routing-icon-close").appendTo(divContainer);
    var closeIcon = cercalia.jQuery("<span />").addClass("ui-icon cercalia-icon cercalia-icon-close").appendTo(divIconClose).click({
        targetContainer: divContainer
    }, function(ev) {
        var sortList = self.sortList_.find("li");
        if (sortList.length > 2) {
            var index = ev.data.targetContainer.attr("data-position");
            self.autocompleteList_.splice(index, 1);
            self.stopCounter_--;
            divContainer.detach().remove();
            self.refresh(false,true);
        }
    });

    // Eventos para mostrar la cruz de eliminar
    divContainer.mouseenter(function() {
        closeIcon.css("display", "block");
    }).mouseleave(function() {
        closeIcon.css("display", "none");
    });

    // Separador inferior
    cercalia.jQuery("<div />")
    	.addClass("cercalia-widget-routing-hr cercalia-widget-routing-hr-bottom")
    .appendTo(divContainer);

    // Añadimos boton para invertir la ruta (solo se muestra el del primer div!)
    var revert = cercalia.jQuery("<div />").addClass("cercalia-widget-routing-revert").appendTo(divContainer).click(function() {
        var sortList = self.sortList_.find("li");

        if (sortList.length == 2) {
            var box0 = cercalia.jQuery(sortList[0]).detach();
            self.sortList_.append(box0);
            self.refresh();
        }
    });
    
    cercalia.jQuery("<span />")
    	.addClass("ui-icon cercalia-icon cercalia-icon-revert")
    .appendTo(revert);
    
    this.stopCounter_++;
};

/**
 * Añade una caja al final de la lista de puntos.
 */
cercalia.widget.Routing.prototype.addStop = function() {
    if (this.autocompleteList_.length + 1 <= this.maxBoxes_) {
        this.addBox_();
        this.refresh(false,true);
    }
};

/**
 * Añade una caja al fina de la lista de puntos de parada.
 */
cercalia.widget.Routing.prototype.addStepStop = function() {

    if (this.autocompleteList_.length + 1 <= this.maxBoxes_) {

        this.addBox_();
        var last = this.autocompleteList_.length;

        if (last >= 2) {
            var aux = this.autocompleteList_[last - 2];
            this.autocompleteList_[last - 2] = this.autocompleteList_[last - 1];
            this.autocompleteList_[last - 1] = aux;

            var lastStepBox = cercalia.jQuery(this.sortList_.find("li")[last - 1]).detach();
            var destBox = cercalia.jQuery(this.sortList_.find("li")[last - 2]).detach();

            this.sortList_.append(lastStepBox).append(destBox)/* .sortable( "refresh" ).sortable( "refreshPositions" ) */;
        }

        this.refresh();
    }

};

/**
 * Fills service with the rute options that the users indicated
 * @param service {cercalia.service.Routing|cercalia.service.LogisticsRouting}
 * @return {cercalia.service.Routing|cercalia.service.LogisticsRouting}
 */
cercalia.widget.Routing.prototype.addOptionsRouteInService = function(service) {
	// Set de las opciones
	if (this.optionsRoute_) {
	    if (this.optionsRoute_.weight != null ) {
	    	service.setWeight(this.optionsRoute_.weight);
	    }
	    if (this.optionsRoute_.reorder != null ) {
	    	service.setReorder(this.optionsRoute_.reorder);
	    }
	}
	return service;
}

/**
 * @return {boolean} true if it's a logistics route, otherwise false.
 */
cercalia.widget.Routing.prototype.isLogistics = function() {
	return this.logisticsRoute_;
};

/**
 * Fills service with the logistics options that the users indicated
 * @param service {cercalia.service.Routing|cercalia.service.LogisticsRouting}
 * @returns {cercalia.service.Routing|cercalia.service.LogisticsRouting}
 */
cercalia.widget.Routing.prototype.addLogisticsInService = function(service) {
	
	if (this.logisticsRoute_) {
	
		if(service.getClass() == "cercalia.service.Routing"){
            service.setOptionsToLogisticsService(this.routingLogistics_);
            service = this.routingLogistics_;
		}
		
	    if (this.logisticsRouteValues_['WEIGHT']) {
	        var lweight = parseInt(this.logisticsRouteValues_['WEIGHT_VALUE'] ? this.logisticsRouteValues_['WEIGHT_VALUE'] : 0);
	        lweight = isNaN(lweight) ? 0 : lweight;
	        service.setVWeight(lweight);
	    }
	
	    if (this.logisticsRouteValues_['WEIGHTAXL']) {
	        var vaxleweight = parseInt(this.logisticsRouteValues_['WEIGHTAXL_VALUE'] ? this.logisticsRouteValues_['WEIGHTAXL_VALUE'] : 0);
	        vaxleweight = isNaN(vaxleweight) ? 0 : vaxleweight;
	        service.setVAxleWeight(vaxleweight);
	    }
	
	    if (this.logisticsRouteValues_['HEIGHT']) {
	        var vheight = parseInt(this.logisticsRouteValues_['HEIGHT_VALUE'] ? this.logisticsRouteValues_['HEIGHT_VALUE'] : 0);
	        vheight = isNaN(vheight) ? 0 : vheight;
	        service.setVHeight(vheight);
	    }
	
	    if (this.logisticsRouteValues_['LENGTH']) {
	        var vlength = parseInt(this.logisticsRouteValues_['LENGTH_VALUE'] ? this.logisticsRouteValues_['LENGTH_VALUE'] : 0);
	        vlength = isNaN(vlength) ? 0 : vlength;
	        service.setVLength(vlength);
	    }
	
	    if (this.logisticsRouteValues_['WIDTH']) {
	        var vwidth = parseInt(this.logisticsRouteValues_['WIDTH_VALUE'] ? this.logisticsRouteValues_['WIDTH_VALUE'] : 0);
	        vwidth = isNaN(vwidth) ? 0 : vwidth;
	        service.setVWidth(vwidth);
	    }
	
	    if (this.logisticsRouteValues_['MAXVEL']) {
	        var vmaxvel = parseInt(this.logisticsRouteValues_['MAXVEL_VALUE'] ? this.logisticsRouteValues_['MAXVEL_VALUE'] : 0);
	        vmaxvel = isNaN(vmaxvel) ? 0 : vmaxvel;
	        service.setVMaxVel(vmaxvel);
	    }
		
	    if (this.logisticsRouteValues_['RIMP']) {
			var serviceWeight = service.getWeight();
			var weight = serviceWeight.indexOf("rimp")==-1 ? serviceWeight + "rimp" : serviceWeight;
			service.setWeight(weight);
	    }
	}
	
	return service;
}

/**
 * Create report
 * @param {Object} data Cercalia object JSON
 */
cercalia.widget.Routing.prototype.createReport = function(data) {
	if(data){
		var sortListnotSorted = this.sortList_.find("li");
        var sortList = this.stepsSortList_;
        var info = [];

        //posem l'origen
        var stop = sortListnotSorted[0].geocoding;
        info.push( stop );

        //posem els steps
        for (var index = 0; index < sortList.length; index++) {
        	
        	var geStep = sortList[ index ].geocoding;
        	if(sortList[ index ].isDragPoint !== undefined 
        			&& sortList[ index ].isDragPoint){
        		
        		geStep.isDragPoint = true;
           	}else geStep.isDragPoint = false;
        	
        	info.push( geStep );
        }
        
        //posem el desti
        stop = sortListnotSorted[ sortListnotSorted.length - 1 ].geocoding;
        info.push( stop );
        
	    data.cercalia.info = info;
	    
	    this.routingPane_.hide();
        this.reportPane_.show();
		this.lateralRoutingReport_.createReport(data);
	} else {
		console.error("error in cercalia.widget.Routing.createReport: data is empty");
	}
}

/**
 * Limpia las cajas no utilizadas para el calculo de ruta (minimo deja dos)
 */
cercalia.widget.Routing.prototype.cleanBoxes = function() {
    var sortList = this.sortList_.find("li");
    var maxList = sortList.length;

    // Miramos si se ha obtenido una coordenada para cada una de las cajas, si no la borramos
    for (var index = 0; index < maxList; index++) {
        if (typeof (sortList[index].geocoding) === "undefined" || sortList[index].geocoding === null) {

            // Solo borramos cajas si hay mas de dos
            if (this.sortList_.find("li").length > 2) {
            	
            	//Borrem els autompletes que no utilitzem.
            	var li = sortList[index];
            	var trobat = -1;
            	for(it = 0 ; it < this.autocompleteList_.length; it++){
            		if(li == this.autocompleteList_[it].routingBox[0]){
            			trobat = it;
            		}
            	}
            	if(trobat >=0){
            		this.autocompleteList_.splice(trobat,1);
            	}
            	
                cercalia.jQuery(li).detach().remove();
                this.stopCounter_--;
            }
        }
    }
    this.refresh();
};

/**
 * Limpia las cajas y la ruta dibujada en el mapa
 */
cercalia.widget.Routing.prototype.clean = function() {

    var sortList = this.sortList_.find("li");
    for (var index = 0; index < sortList.length; index++) {
        sortList[index].geocoding = null;
        if(sortList[index].marker)sortList[index].marker.destroy();
        sortList[index].marker = null;
    }

    for ( var index = 0; index < this.autocompleteList_.length; index++) {
        this.autocompleteList_[index].clean();
    }

    this.cleanBoxes();
    if (this.lateralRoutingReport_) {
        this.lateralRoutingReport_.clean();
    }
    this.reportPane_.hide();
    this.routingPane_.show();
    
};

/**
 * Set del origen de la ruta.
 * @param {string|cercalia.LonLat} origin Nombre a buscar o latitud y longitud del origen
 */
cercalia.widget.Routing.prototype.setOrigin = function(origin) {

    var self = this;
    if (typeof (origin) === "string") {
        // Accedemos al suggest del origen
        //var autocomplete = this.autocompleteList_[0]; // Si no hay suggest lo creamos if(autocomplete == null) { this.addStop(); autocomplete = this.autocompleteList_[0]; }
        cercalia.Exception(cercalia.i18n._("WIDGET_ERR_NO_IMPLEMENTED", this.CLASS_NAME_ + ".setOrigin"));

    } else if ( origin instanceof cercalia.LonLat ) {

    	var liOrigin = this.sortList_.find("li")[0];
    	if( liOrigin && ( (liOrigin.geocoding == null) || (liOrigin.geocoding.coord && liOrigin.geocoding.coord.x != origin.getLon() && liOrigin.geocoding.coord.y != origin.getLat())) ){
    	
	        var autocomplete = this.autocompleteList_[0];
	
	        // Si no hay suggest lo creamos
	        if (autocomplete == null) {
	            this.addStop();
	            autocomplete = this.autocompleteList_[0];
	        }
	
	        // Lanzamos peticion de reversegeocoding para obtener el nombre y datos del punto
	        this.reverseGeocoding_.getDirection(origin, function(response) {
	            self.setStop_(0, response.cercalia.proximity, autocomplete, origin, 'o');
	            self.reInitStepList_();
	            //if (self.canCalculate_()) self.calculate();
	        });
    	}
    } else {
        cercalia.Exception(cercalia.i18n._("WIDGET_ERR_NO_SUPPORTED", this.CLASS_NAME_ + ".setOrigin"));
    }

    if (this.showUICallback_ !== null){
    	this.showUICallback_();
    }
};


/**
 * Set del origen de la ruta.
 * @param {string|cercalia.LonLat} destination Nombre a buscar o latitud y longitud del destino
 */
cercalia.widget.Routing.prototype.setDestination = function(destination) {

    var self = this;
    if (typeof (destination) === "string") {
        // Accedemos al suggest del origen
        //var autocomplete = this.autocompleteList_[0]; // Si no hay suggest lo creamos if(autocomplete == null) { this.addStop(); autocomplete = this.autocompleteList_[0]; }
        cercalia.Exception(cercalia.i18n._("WIDGET_ERR_NO_IMPLEMENTED", this.CLASS_NAME_ + ".setDestination"));

    } else if ( destination instanceof cercalia.LonLat ) {

    	var sortList = this.sortList_.find("li");
    	var liDestination = sortList[sortList.length -1];
    	if( liDestination  && ( (liDestination.geocoding == null) || (liDestination.geocoding.coord && liDestination.geocoding.coord.x != destination.getLon() && liDestination.geocoding.coord.y != destination.getLat())) ){
    		
	        if (this.stopCounter_ <= 1) {
	            this.addStop();
	        }
	
	        var pos = this.stopCounter_ - 1;
	        var autocomplete = this.autocompleteList_[pos];
	
	        // Lanzamos peticion de reversegeocoding para obtener el nombre y datos del punto
	        this.reverseGeocoding_.getDirection(destination, function(response) {
	            self.setStop_(pos, response.cercalia.proximity, autocomplete, destination, 'f');
	            self.reInitStepList_();
	            //if (self.canCalculate_()) self.calculate();
	        });
    	}
    } else {
        cercalia.Exception(cercalia.i18n._("WIDGET_ERR_NO_SUPPORTED", this.CLASS_NAME_ + ".setDestination"));
    }

    if (this.showUICallback_ !== null){
    	this.showUICallback_();
    }
};


/**
 * Set del punto de paso de la ruta.
 * @param {string|cercalia.LonLat} waypoint Nombre a buscar o latitud y longitud del destino.
 * @param {number} position Posición del punto de paso.
 */
cercalia.widget.Routing.prototype.setStep = function(waypoint, position) {

    var self = this;
    if (typeof (waypoint) === "string") {
        // Accedemos al suggest del origen
        //var autocomplete = this.autocompleteList_[0]; // Si no hay suggest lo creamos if(autocomplete == null) { this.addStop(); autocomplete = this.autocompleteList_[0]; }
        cercalia.Exception(cercalia.i18n._("WIDGET_ERR_NO_IMPLEMENTED", this.CLASS_NAME_ + ".setStep"));
        
    } else if (waypoint instanceof cercalia.LonLat) {
        if (position >= this.autocompleteList_.length) {
            cercalia.Exception(cercalia.i18n._("WIDGET_ERR_POS_GREATER", this.CLASS_NAME_ + ".setStep"));
        } else {
        	var sortList = this.sortList_.find("li");
        	var liStep = sortList[position];
        	if( liStep && ((liStep.geocoding == null) || (liStep.geocoding.coord && liStep.geocoding.coord.x != waypoint.getLon() && liStep.geocoding.coord.y != waypoint.getLat())) ) {
	            var autocomplete = this.autocompleteList_[position];
	            // Lanzamos peticion de reversegeocoding para obtener el nombre y datos del punto
	            this.reverseGeocoding_.getDirection(waypoint, function(response) {
	                self.setStop_(position, response.cercalia.proximity, autocomplete, waypoint, 'p');
	                self.reInitStepList_();
	                //if (self.canCalculate_()) self.calculate();
	            });
        	}
        }
    } else {
        cercalia.Exception(cercalia.i18n._("WIDGET_ERR_NO_SUPPORTED", this.CLASS_NAME_ + ".setStep"));
    }

    if (this.showUICallback_ !== null){
    	this.showUICallback_();
    }
};




/**
 * Reiniciem la llista de steps
 * @private
 */
cercalia.widget.Routing.prototype.reInitStepList_ = function() {
	
	// re-iniciem la llista. pq s'ha posat un punt de forma "normal".
	this.stepsSortList_ = [ ];
	var sortList = this.sortList_.find("li");
	
	for (var index = 0; index < sortList.length; index++) {
	    if ( ! ( index == 0 || index == sortList.length - 1 ) ) {
	        var stop = sortList[index].geocoding;
	    	
	        if(stop){
		    	var coord = new cercalia.LonLat(stop.coord.x, stop.coord.y)
		    	coord["geocoding"] = sortList[index].geocoding
		    	this.stepsSortList_.push( coord );
	        }
	    }
	}
};

/**
 * posa el el punt, en la posició indicada movent els altres punts a la cua.
 * @param  {cercalia.LonLat} lonLat
 * @param  {number} position
 * @param  {boolean} override 
 */
cercalia.widget.Routing.prototype.setStepDrag = function( lonLat, position, override){
	
	var self = this;
	lonLat.isDragPoint = true;
	
	if(override){
		this.stepsSortList_[position] = lonLat;
	}else{
		this.stepsSortList_ = cercalia.Util.addObjectInArray( this.stepsSortList_ , lonLat, position );
	}
	
    // Lanzamos peticion de reversegeocoding para obtener el nombre y datos del punto   
    this.reverseGeocoding_.getDirection(lonLat, function(response) {
    	lonLat["geocoding"] = response.cercalia.proximity.gelist.ge;
    });
};

/**
 * treu el punt dragable, en la posició indicada movent els altres punts a la cua.
 * @param  {cercalia.LonLat} lonLat
 * @param  {number} position
 * @return {cercalia.widget.routing} this
 */
cercalia.widget.Routing.prototype.removeStepDrag = function(lonLat, position){
	
	if(lonLat){
		var index = this.stepsSortList_.indexOf(lonLat);
		if (index > -1) {
			this.stepsSortList_.splice(index, 1);
			return this;
		}
	}
	
	if(position !== undefined && position != null){
		if (position > -1) {
			this.stepsSortList_.splice(position, 1);
			return this;
		}
	}
	return this;

};

/**
 * Remove step in the position indicated in the parameter `position` moving the other points.
 * @param {number} position
 * @return {cercalia.widget.routing} this
 */
cercalia.widget.Routing.prototype.removeStep = function(position) {
	var self = this;
	var sortList = this.sortList_.find("li");
	
	if(position !== undefined && position != null){
       
		position = parseInt(position);
		if (position > -1) {
			
			//this.stopCounter_--;
			//this.reInitStepList_();
			
			self.autocompleteList_.splice(position, 1);
            self.stopCounter_--;
            sortList[position].remove();//(position, 1); //divContainer.detach().remove();
            self.refresh(false,true);
            
			return this;
		}
	}
	return this;
}

/**
 * Return number of boxs.
 * @return {Number}
 */
cercalia.widget.Routing.prototype.getCounterBox = function() {
    return this.stopCounter_;
};

/**
 * Set del origen de la ruta.
 * @private
 * @param {number} pos Posicion de la parada a modificar.
 * @param {Object} proximity Respuesta proximity de cercalia.
 * @param {cercalia.widget.GeocodingSuggest} autocomplete Autocomplete a modificar el texto.
 * @param {cercalia.LonLat} realCoord
 * @param {string} stopId
 */
cercalia.widget.Routing.prototype.setStop_ = function(pos, proximity, autocomplete, realCoord, stopId) {
    var ge = proximity.gelist.ge;

    if (proximity.type == "adr") {
        if (ge.housenumber != null) {
            ge.label = ge.name + " " + ge.housenumber.value + ", " + ge.municipality.value;
            autocomplete.setInputText(ge.label);
        } else {
            ge.label = ge.name + ", " + ge.municipality.value;
            autocomplete.setInputText(ge.label);
        }
    } else if (proximity.type == "ct") {
        ge.label = ge.name + ", " + ge.subregion.value;
        autocomplete.setInputText(ge.label);
    } else {
        ge.label = ge.name;
        autocomplete.setInputText(ge.label);
    }

    autocomplete.blur();
    this.autocompleteCallback_(pos, ge, realCoord, stopId);
};

/**
 * @param routeMap {cercalia.RouteMap}
 */
cercalia.widget.Routing.prototype.setRouteMap = function(routeMap) {
    this.routing_ = routeMap;
    this.routingUsed_ = this.routing_.getService();
    this.lateralRoutingReport_.setRoutingService(this.routingUsed_);
};

/**
 * @return {cercalia.RouteMap}
 */
cercalia.widget.Routing.prototype.getRouteMap = function() {
    return this.routing_;
};


/**
 * Get Options Route
 * @return {Object}
 */
cercalia.widget.Routing.prototype.getOptionsRoute = function() {
	return this.optionsRoute_;
}


/**
 * Return object type.
 * @return {string}
 */
cercalia.widget.Routing.prototype.getClass = function() {
    return this.CLASS_NAME_;
};

/**
 * Print route
 */
cercalia.widget.Routing.prototype.printReport = function() {
	
	var self = this;
	var idDivPrint = 'divPrint' + this.map_.getId();
	
	
	//Creating dialog HTML
	var jqDialogContent = cercalia.jQuery(
		'<div id="' + idDivPrint + '" title="Report de la ruta" style="display:none" class="printWindow ui-widget cercalia-widget cercalia-widget-routingreport">' +
		'<button class="btn-print ui-button ui-widget ui-state-default ui-corner-all" type="submit">'+ cercalia.i18n._('ROUTING_PRINT') +'</button>' +
			'<div class="inner">' +
				'<div id="divMapReport"></div>' +
				'<div id="containerPrintReport">' +
				'</div>' +
			'</div>' +
		'</div>');
		


	var btnPrint = jqDialogContent.find('.btn-print');
	
	btnPrint.button().click(function() {
		btnPrint.remove();
		self.sendToPrinter_(mapPrint, idDivPrint);
	});
	
	cercalia.jQuery('body').append(jqDialogContent);	

	if(this.dialogPrint_) {
		this.dialogPrint_.remove();
	}	
	
	this.dialogPrint_ = cercalia.jQuery('#' + idDivPrint).dialog({
		width: 700,
		height: 600,
		close: function(event, ui) {
			cercalia.jQuery('#containerPrintReport').empty();
			self.dialogPrint_.remove();
		},
		modal: true
	});
	this.dialogPrint_.dialog('open');

	
	
	//Clone report
	var divReportPrint = this.reportPane_.clone();


	divReportPrint.find('button').remove();
	divReportPrint.find('.cercalia-widget-routingreport-directions-stepDesc-options').remove();
	divReportPrint.find('.cercalia-widget-routingreport-step-zoom').remove();
	

	cercalia.jQuery('#' + idDivPrint).show();
	
	var mapPrint = new cercalia.Map({
		target: 'divMapReport',
		center: this.map_.getCenter(),
		zoom: this.map_.getZoom(),
		controls: [cercalia.MapControls.LayerSwitcher]
	});
	
	
	var service = this.routing_.getService();
	var wkt = service.getWKT();
	
	var arrMarkers = [];
	/*
	arrMarkers.push(new cercalia.Marker({
		position: service.getOrigin(),
		icon: new cercalia.Icon({src: cercaliaGlobals.img + '/cercalia-marker-icon-A.png', anchor:[12,34]})
	}));
	arrMarkers.push(new cercalia.Marker({
		position: service.getDestination(),
		icon: new cercalia.Icon({src: cercaliaGlobals.img + '/cercalia-marker-icon-B.png', anchor:[12,34]})
	}));
	
	var steps = service.getSteps();
	for(var i = 0 ; i < steps.length; i++) {
		arrMarkers.push(new cercalia.Marker({
			position: steps[i],
			icon: new cercalia.Icon({src:cercaliaGlobals.img + '/cercalia-marker-icon-' + (parseInt(i)+1) + '.png', anchor:[12,34]})
		}));
	}
	mapPrint.addMarkers(arrMarkers);
	*/
	//pintar feature WKT
	var features = this.routing_.getFeatures();
	var newFeatures = [];
	for(var i = 0 ; i < features.length; i++) {
		//No podemos usar las mismas porque ya estan pintadas en el mapa de fondo.
		//tenemos que crear de nuevas o clonarlas
		var olFeature = features[i].getFeature();
		var geom = olFeature.getGeometry();
		var newFeature = new cercalia.Feature({
			geometry: geom
		});
		newFeatures.push(newFeature);
	}
	
	mapPrint.addFeatures(newFeatures);
	mapPrint.centerToFeatures(newFeatures);
	
	cercalia.jQuery('#divMapReport .cercalia-bar-top').hide(); //Hide top bar
	cercalia.jQuery('#divMapReport .cercalia-control-zoom').hide(); //Hide zoom control
	cercalia.jQuery('#containerPrintReport').html( divReportPrint.html() ); //Clone HTML report
	
};


/**
 * @private
 * @param {Element} mapPrint
 * @param {string} idDivPrint
 */
cercalia.widget.Routing.prototype.sendToPrinter_ = function(mapPrint, idDivPrint) {
	var self = this;
	//Eliminem la part que ens sobra
	cercalia.jQuery('#' + idDivPrint).find('#divMapReport').remove();
	
	var divImpresora = cercalia.jQuery('#' + idDivPrint).clone().attr('id', idDivPrint + 'Clone');
	var popupWin = window.open('', '_blank', 'width=600,height=600');
	popupWin.document.open();
	
	
	popupWin.document.write('<!DOCTYPE html>');
	popupWin.document.write('<html>');
	popupWin.document.write('<head>');
	popupWin.document.write('<script type="text/javascript" src="http://api.cercalia.com/api/cercalia.js?key=07de1b67aa00baf5f1284298f88132e3914e4fb380fce9d91c815aa372fe67c4&theme=blue&lang=es"></script>');
	popupWin.document.write('</head>');
	popupWin.document.write('<body>');
	popupWin.document.write('<div style="margin:0 auto;width:600px;height:600px" id="printDivMapImpresora"></div>');
	popupWin.document.write('<div class="ui-widget cercalia-widget cercalia-widget-routingreport">');
	popupWin.document.write( divImpresora.html()  );
	popupWin.document.write('</div>');
	popupWin.document.write('</body>');
	popupWin.document.write('</html>');
	popupWin.document.close();

		
	popupWin.onload = function(){
		mapPrint.getMap().setTarget(popupWin.document.getElementById('printDivMapImpresora'));
		mapPrint.getMap().updateSize();
	
		//Creem el que s'ha eliminat dintre el dialog print

		var divMapReport = cercalia.jQuery('<div />').attr('id','divMapReport');
		cercalia.jQuery( cercalia.jQuery('#divPrint .inner') ).prepend( divMapReport );
		divMapReport.find('button').remove();
		//Li donem un petit timeout per a que s'acabi de fer 'updateSize()'
		setTimeout(function(){
			self.dialogPrint_.dialog('close');
			popupWin.print();
			mapPrint.getMap().setTarget( divMapReport[0] );
			mapPrint.getMap().updateSize();
			popupWin.close();
		}, 250);
	};
};


/**
 *	Save route as KML.
 */
cercalia.widget.Routing.prototype.saveKml = function() {
	var filename = "cercalia_route" + Date.now() + ".kml";
	var routingService = this.routing_.getService();
	var wkt = routingService.getWKT();
	var kml = cercalia.Util.transformWktToKML(wkt);
	cercalia.Util.downloadXmlToFile(kml, filename);
};

/**
 * Get autocomplete widgets
 * @return {Array.<cercalia.widget.GeocodingSuggest>} List autocompletes widgets.
 */
cercalia.widget.Routing.prototype.getAutocompletesWidgets = function() {
    return this.autocompleteList_;
};