﻿/// <reference name="MicrosoftAjax.debug.js" />
/// <reference name="MicrosoftAjaxTimer.debug.js" />
/// <reference name="MicrosoftAjaxWebForms.debug.js" />


Type.registerNamespace("SGis.MapToolkit");

SGis.MapToolkit.LayerMapBehavior = function(element) {
    SGis.MapToolkit.LayerMapBehavior.initializeBase(this, [element]);
    // Referencia a Controles y objetos
    this._mapControl = null;
    this._mapContainer = null;    // Referencia al contenedor de mapas
    this._parentControl = null;   // Referencia al control de mapas
    this._lyrMap = [];            // Elementos de layers imagenes 0 y 1
    // Propiedades    
    this._ServicePath = null;     // Ruta del servicio
    this._ServiceMethod = null;   // Método a llamar del servicio de mapas
    this._MarginBuffer = 0;     // Buffer del grafico para las 4 direcciones
    this._ZOrder = 20;            // orden del indice z
    this._LayerId = "lyrMap"      // Identificador interno
    this._Params = "";            // Parámetros para obtener los objetos
    this._LayerEnabled = true;    // Indica si la layer está activa o no
    this._AnimationsEnabled = true; // Indica si están activas las animaciones
    // Miembros Privados
    this._currentMap = 0;         // Una layer se usa de backup mientras la otra se muestra
    this._isLoaded = false;       // Bandera para indicar si el control ha sido cargado (inicializado)
    this._mapWidth = 0;           // Ancho del mapa incluyendo margenes buffer
    this._mapHeight = 0;          // Alto del mapa, incluyendo margenes buffer
    this._ctrWidth = 0;           // Ancho del control (parte visible del mapa)
    this._ctrHeight = 0;          // Alto del control (parte visible del mapa)
    this._serviceTimeOut = 20000; // Tiempo de espera máxio para time out
    this._requestNumber = 0;      // Bandera para determinar el numero de request al servidor para descartar respuestas asincronicas cuando hay una posterior
    this._isDirty = false;        // Bandera que indica si el mapa esta sucio
    this._deltaY = 0;             // desplazamiento temporal al hacer paneo
    this._deltaX = 0;             // desplazamiento temporal al hacer paneo
    // Animadores para Coordenadas y dimensiones 
    this._aniChangeDim = null;
    this._aniChangeX = null;
    this._aniChangeY = null;
    this._aniChangeW = null;
    this._aniChangeH = null;
    // Eventos
    this._mapControl$onPanningMove$delegate = Function.createDelegate(this, this._mapControl_onPanningMove);
    this._mapControl$onPanningEnd$delegate = Function.createDelegate(this, this._mapControl_onPanningEnd);
    this._mapControl$onMapExtentChanged$delegate = Function.createDelegate(this, this._mapControl_onMapExtentChanged);
    this._lyrMap0$delegates = {
        load: Function.createDelegate(this, this._lyrMap0_onLoadHandler)
    }
    this._lyrMap1$delegates = {
        load: Function.createDelegate(this, this._lyrMap1_onLoadHandler)
    }
}

SGis.MapToolkit.LayerMapBehavior.prototype = {
    initialize: function() {
        SGis.MapToolkit.LayerMapBehavior.callBaseMethod(this, 'initialize');
        //
        this.buildAllControls();
        this.add_propertyChanged(Function.createDelegate(this, this._onPropertyChanged));
        //
        this._mapContainer = this.get_element().control._mapContainer;
        this._mapControl = this.get_element();
        this._parentControl = this.get_element().control;
        // Crea Controles
        this.buildAllControls();
        // Attach event handlers
        this._parentControl.add_panningMove(this._mapControl$onPanningMove$delegate);
        this._parentControl.add_panningEnd(this._mapControl$onPanningEnd$delegate);
        this._parentControl.add_mapExtentChanged(this._mapControl$onMapExtentChanged$delegate);
        // Animations
        this._aniChangeX = new AjaxControlToolkit.Animation.LengthAnimation(null, null, null, "style", null, 0, 0, "px");
        this._aniChangeY = new AjaxControlToolkit.Animation.LengthAnimation(null, null, null, "style", null, 0, 0, "px");
        this._aniChangeW = new AjaxControlToolkit.Animation.LengthAnimation(null, null, null, "style", null, 0, 0, "px");
        this._aniChangeH = new AjaxControlToolkit.Animation.LengthAnimation(null, null, null, "style", null, 0, 0, "px");
        this._aniChangeDim = new AjaxControlToolkit.Animation.ParallelAnimation(null, .10, null, [this._aniChangeX, this._aniChangeY, this._aniChangeW, this._aniChangeH]);
    },
    dispose: function() {
        //Add custom dispose actions here
        SGis.MapToolkit.LayerMapBehavior.callBaseMethod(this, 'dispose');
    },
    get_PlugInId: function() {
        /// <value type="string" mayBeNull="false">
        /// Gets de plugIn unique id
        /// </value>
        return 'sgis.layermap';
    },
    /// <summary>
    // loads the current plugin into the main map container, creates menu, toolbar, atach events, etc
    /// </summary>
    /// <param name="container" type="SGis.MapToolkit.MapControl">
    /// The map control container
    /// </param>
    load: function(container) {
        if (this._isLoaded) return;
        this._isLoaded = true;
        this.resetLayers();
    },
    unload: function() {
        Sys.Debug.trace('Unloading layrMap');
    },
    // Construye todos los controles hijo
    buildAllControls: function() {
        for (i = 0; i < 2; i++) {
            this._lyrMap[i] = $common.createElementFromTemplate({
                nodeName: "IMG",
                properties: {
                    id: this._LayerId + "lyrImg" + i,
                    style: {
                        position: "absolute",
                        visibility: "hidden",
                        backgroundColor: "transparent",
                        zIndex: this._ZOrder - i
                    }
                },
                cssClasses: ["sgmap_lyr_img"]
            }, this._mapContainer);
        }
        $addHandlers(this._lyrMap[0], this._lyrMap0$delegates);
        $addHandlers(this._lyrMap[1], this._lyrMap1$delegates);
    },
    // Resetea posición y tamaño de layers
    resetLayers: function() {
        var size = WebForm_GetElementPosition(this._mapContainer);
        this._mapWidth = size.width + this._MarginBuffer * 2;
        this._mapHeight = size.height + this._MarginBuffer * 2;
        this._ctrWidth = size.width;
        this._ctrHeight = size.height;
        var l0 = this._lyrMap[0];
        var l1 = this._lyrMap[1];
        // Hace capas invisibles para evitar distorsión en resize
        l0.style.visibility = "hidden";
        l1.style.visibility = "hidden";
        l0.startPos = null;
        l1.startPos = null;
        // Cambia tamaños 
        WebForm_SetElementHeight(l0, this._mapHeight);
        WebForm_SetElementHeight(l1, this._mapHeight);
        WebForm_SetElementWidth(l0, this._mapWidth);
        WebForm_SetElementWidth(l1, this._mapWidth);
        // Cambia posición
        WebForm_SetElementX(l0, this._MarginBuffer * (-1));
        WebForm_SetElementX(l1, this._MarginBuffer * (-1));
        WebForm_SetElementY(l0, this._MarginBuffer * (-1));
        WebForm_SetElementY(l1, this._MarginBuffer * (-1));
        // Carga contenido
        this.loadData();
    },
    loadData: function() {
        if (this._LayerEnabled) {
            this.invokeGetMapWebService();
        }
    },
    // Invoca al servicio web para obtener mapa en forma asincrónica
    invokeGetMapWebService: function() {
        this._requestNumber++;
        Sys.Net.WebServiceProxy.invoke(this._ServicePath, this._ServiceMethod, false,
                { centerX: this._mapControl.control._CenterX, centerY: this._mapControl.control._CenterY, zoom: this._mapControl.control._Zoom, imgWidth: this._mapWidth, imgHeight: this._mapHeight, mapParams: this._Params },
                Function.createDelegate(this, this.onGetMapMethodComplete),
                Function.createDelegate(this, this.onGetMapMethodError), { requestNumber: this._requestNumber }, this._serviceTimeOut);
        this.showStatusProcess('Solicitando mapa...');
    },
    // Muestra mensaje cargando y throbber
    showStatusProcess: function(message) {
        if (this._parentControl._stsBar) {
            this._parentControl._stsBar.addMessage(this._LayerId, { Text: message, Icon: SGis.MapToolkit.StatusBarIcon.Throbber });
        }
    },
    // Muestra mensaje cargando y throbber
    showStatusDownload: function(message) {
        if (this._parentControl._stsBar) {
            this._parentControl._stsBar.addMessage(this._LayerId, { Text: message, Icon: SGis.MapToolkit.StatusBarIcon.Download });
        }
    },
    showStatusError: function(message) {
        if (this._parentControl._stsBar) {
            this._parentControl._stsBar.addMessage(this._LayerId, { Text: message, Icon: SGis.MapToolkit.StatusBarIcon.Error });
        }
    },
    removeStatus: function() {
        if (this._parentControl._stsBar) {
            this._parentControl._stsBar.removeMessage(this._LayerId);
        }
    },
    // Se completo invocación al web service - GetMap
    onGetMapMethodComplete: function(result, userContext, methodName) {
        // Verifica que sea el ultimo request, ignora resultado si no
        if (this._requestNumber != userContext.requestNumber) return;
        // Si el resultado es invalido debe mostrar el error y no procesar mas
        if (!result.IsValid) {
            this.removeStatus();
            return;
        }
        this._isDirty = false;
        // Aplica cambios al mapa invisible para mostrarlo una vez cargado
        var map = this.invisibleMap();
        map.resultGetMap = result; // Se guarda el resultado del mapa dentro de la layer para porder dibujarla en base a valores actuales de centro y zoom
        var showStatus = (map.nameProp === result.Url ? false : true);
        //
        if (result.Url !== '') {
            map.src = result.Url;
            if (showStatus) {
                this.showStatusDownload('Cargando mapa...');
            } else {
                this.removeStatus();
            }
            //
            map.startPos = this.getRelativeMapPosition(map);
            WebForm_SetElementHeight(map, map.startPos.height);
            WebForm_SetElementWidth(map, map.startPos.width);
            WebForm_SetElementX(map, map.startPos.x + this._deltaX);
            WebForm_SetElementY(map, map.startPos.y + this._deltaY);

        }
        else {
            map.src = result.Url;
            this.removeStatus();
            $common.setVisible(this.invisibleMap(), false)
            $common.setVisible(this.visibleMap(), false)
        }

        //
        //map.style.backgroundImage = "url(" + result.Url + ") !important";
        //map.style.filter = "progid: DXImageTransform.Microsoft.AlphaImageLoader(" +
        /*
        debugger;
        map.style.backgroundImage = result.Url;
        map.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + result.Url + "', sizingMethod='scale')";
        */
    },
    // Obtiene la posición, tamaño y zoom relativos entre un mapa y el control principal
    getRelativeMapPosition: function(element) {
        var c = this._mapControl.control;
        // Crea objeto para retornar
        var res = element.resultGetMap;
        var dx = res.CenterX - c._CenterX;
        var dy = res.CenterY - c._CenterY;
        //debugger;
        var result = new Object();
        // Relación entre el zoom actual y el zoom del mapa
        result.r = res.Zoom / c._Zoom;
        // como el valor de c._Zoom esta truncado, se lleva a 1 cuando el error es > 0.0001
        if (result.r < 1.0001 && result.r > 0.9999) {
            result.r = 1;
        }
        // Ancho del mapa
        result.width = res.Width * result.r;
        // Alto
        result.height = res.Height * result.r;
        // Nuevo centro en funcion de los tamaños, zoom y escala
        var newCenter = $sgutils.worldToMap(
            { x: res.CenterX, y: res.CenterY },
            c._CenterX,
            c._CenterY,
            c._Zoom,
            this._ctrWidth,
            this._ctrHeight);
        result.x = Math.round(newCenter.x - (result.width) / 2);
        result.y = Math.round(newCenter.y - (result.height) / 2);
        return result;
    },
    // Error al invocar web service
    onGetMapMethodError: function(webServiceError, userContext, methodName) {
        // Verifica que sea el ultimo request, ignora resultado si no
        if (this._requestNumber != userContext.requestNumber) return;
        // Call failed
        //this._removeStatusLabel();
        var strError;
        if (webServiceError.get_timedOut()) {
            strError = "Tiempo de espera excedido.";
        } else {
            strError = "Error al llamar Servicio Web: " + webServiceError.get_statusCode() + " " + webServiceError.get_message();
        }
        this.showStatusError(strError);
    },
    // Obtiene el mapa visible
    visibleMap: function() {
        return this._lyrMap[this._currentMap];
    },
    // Obtiene el mapa invisible
    invisibleMap: function() {
        return this._lyrMap[this._currentMap == 0 ? 1 : 0];
    },
    // Determina si es necesario redibujar el mapa, cuando se encuentra fuera de la ventana donde se ve
    reloadIfNeeded: function() {
        var map = this.visibleMap();
        var reload = true;
        if (map.startPos) {
            var pos = map.startPos;
            if (this._isDirty || pos.x > 0 || pos.y > 0 || pos.r != 1 || pos.width + pos.x < this._ctrWidth || pos.height + pos.y < this._ctrHeight) {
                reload = true;
            } else {
                reload = false;
            }
        }
        if (reload) {
            if (!this._AnimationsEnabled) {
                $common.setVisible(this.visibleMap(), false);
            }
            this.loadData();
        }
    },
    // Intercambia imagenes de mapas
    swapImgMaps: function() {
        this.removeStatus(); // Remueve el mensaje en la barra de estados
        this._currentMap = this._currentMap == 0 ? 1 : 0;
        var v = this.visibleMap();
        var i = this.invisibleMap();
        // Prepara efecto Fade
        i.style.zIndex = this._ZOrder;
        v.style.zIndex = this._ZOrder + 1;
        $common.setVisible(v, true);
        $common.setVisible(i, false);

        /*
        Efecto fade deshabilitado - manejarlo con una bandera
        
        
        $common.setElementOpacity(i, 0);
        $common.setElementOpacity(i, 1);
        $common.setVisible(v, true);
        $common.setVisible(i, true);
        //
        var aniFadeIn = new AjaxControlToolkit.Animation.FadeAnimation(v, .3, 20, 'FadeIn', 1, 0, true);
        aniFadeIn.play();
        //
        var aniFadeOut = new AjaxControlToolkit.Animation.FadeAnimation(i, .3, 20, 'FadeOut', 0, 1, true);
        aniFadeOut.play();
        */

    },
    // Realiza el paneo y zoom animado de el mapa principal y el overview
    animateZoomPan: function() {
        var map = this.visibleMap();
        if (map.startPos) {
            var endPos = this.getRelativeMapPosition(map);
            // Si no cambio nada, no se realiza paneo ni se recarga
            if (endPos.x === map.startPos.x &&
                endPos.y === map.startPos.y &&
                endPos.width === map.startPos.width &&
                endPos.height === map.startPos.height) {
                //debugger;
                this.reloadIfNeeded();
                return;
            }
            //
            if (this._AnimationsEnabled) {
                this._aniChangeX.set_propertyKey("left");
                this._aniChangeX.set_target(map);
                this._aniChangeX.set_startValue(map.startPos.x);
                this._aniChangeX.set_endValue(endPos.x);
                this._aniChangeY.set_propertyKey("top");
                this._aniChangeY.set_target(map);
                this._aniChangeY.set_startValue(map.startPos.y);
                this._aniChangeY.set_endValue(endPos.y);
                this._aniChangeW.set_propertyKey("width");
                this._aniChangeW.set_target(map);
                this._aniChangeW.set_startValue(map.startPos.width);
                this._aniChangeW.set_endValue(endPos.width);
                this._aniChangeH.set_propertyKey("height");
                this._aniChangeH.set_target(map);
                this._aniChangeH.set_startValue(map.startPos.height);
                this._aniChangeH.set_endValue(endPos.height);
                var endHandler = Function.createDelegate(this, function() {
                    this._aniChangeDim.remove_ended(endHandler);
                    this.reloadIfNeeded();
                });
                map.startPos = endPos;  // La posición final pasa a ser la pos. inicial
                this._aniChangeDim.add_ended(endHandler);
                this._aniChangeDim.play();
            } else {

                map.startPos = endPos;  // La posición final pasa a ser la pos. inicial
                this.reloadIfNeeded();
            }
        } else {
            this.loadData();
        }

    },

    //--------------------------------------------------------------------------
    // Acceso a Propiedades
    //--------------------------------------------------------------------------
    get_Params: function() {
        return this._Params;
    },
    set_Params: function(value) {
        if (this._Params != value) {
            this._Params = value;
            this.raisePropertyChanged('Params');
        }
    },

    get_ServicePath: function() {
        return this._ServicePath;
    },
    set_ServicePath: function(value) {
        if (this._ServicePath != value) {
            this._ServicePath = value;
            this.raisePropertyChanged('ServicePath');
        }
    },
    get_ServiceMethod: function() {
        return this._ServiceMethod;
    },
    set_ServiceMethod: function(value) {
        if (this._ServiceMethod != value) {
            this._ServiceMethod = value;
            this.raisePropertyChanged('ServiceMethod');
        }
    },
    get_MarginBuffer: function() {
        return this._MarginBuffer;
    },
    set_MarginBuffer: function(value) {
        if (this._MarginBuffer != value) {
            this._MarginBuffer = value;
            this.raisePropertyChanged('MarginBuffer');
        }
    },
    get_ZOrder: function() {
        return this._ZOrder;
    },
    set_ZOrder: function(value) {
        if (this._ZOrder != value) {
            this._ZOrder = value;
            this.raisePropertyChanged('ZOrder');
        }
    },
    get_LayerId: function() {
        return this._LayerId;
    },
    set_LayerId: function(value) {
        if (this._LayerId != value) {
            this._LayerId = value;
            this.raisePropertyChanged('LayerId');
        }
    },
    get_LayerEnabled: function() {
        return this._LayerEnabled;
    },
    set_LayerEnabled: function(value) {
        if (this._LayerEnabled != value) {
            this._LayerEnabled = value;
            if (this._isLoaded) {
                if (value) {
                    this.reloadIfNeeded();
                } else {
                    $common.setVisible(this.visibleMap(), false);
                }
            }
            this.raisePropertyChanged('LayerEnabled');
        }
    },
    get_AnimationsEnabled: function() {
        return this._AnimationsEnabled;
    },
    set_AnimationsEnabled: function(value) {
        if (this._AnimationsEnabled != value) {
            this._AnimationsEnabled = value;
            this.raisePropertyChanged('AnimationsEnabled');
        }
    },
    //--------------------------------------------------------------------------
    // Manejadores de Eventos
    //--------------------------------------------------------------------------
    // Mueve el mose sobre el Mapa

    // Al realizar paneo en el control mapa
    _mapControl_onPanningMove: function(sender, args) {
        var map = this.visibleMap();
        if (map.startPos) {
            this._deltaY = args.dy;
            this._deltaX = args.dx;
            WebForm_SetElementX(map, map.startPos.x + args.dx);
            WebForm_SetElementY(map, map.startPos.y + args.dy);
        }

    },
    // Al finalizar paneo de mapa
    _mapControl_onPanningEnd: function(sender, args) {
        var map = this.visibleMap();
        if (map.startPos) {
            // Aplica los delta en forma definitiva
            map.startPos.x = map.startPos.x + args.dx;
            map.startPos.y = map.startPos.y + args.dy;
            WebForm_SetElementX(map, map.startPos.x);
            WebForm_SetElementY(map, map.startPos.y);
            this._deltaY = 0;
            this._deltaX = 0;
        }
        //this.reloadIfNeeded();
    },
    // Al cambiar la extensión del mapa
    _mapControl_onMapExtentChanged: function(sender, args) {
        var map = this.visibleMap();
        this.animateZoomPan();
    },
    // Termina carga de imagen para mapa 1
    _lyrMap0_onLoadHandler: function(evt) {
        this.swapImgMaps();
    },
    // Termina carga de imagen para mapa 2
    _lyrMap1_onLoadHandler: function(evt) {
        this.swapImgMaps();
    },
    // Al cambiar propiedades 
    _onPropertyChanged: function(sender, args) {
        var propname = args.get_propertyName();
    }

}
SGis.MapToolkit.LayerMapBehavior.registerClass('SGis.MapToolkit.LayerMapBehavior', AjaxControlToolkit.BehaviorBase, SGis.MapToolkit.IPlugIn);


if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();