﻿function WVZoomPowerTwo()
{
    var oThis=this;
    var viewer = null;
    var factorScale = 0.9; //factor de escalado
    var isScaling = false; //indica si está escalando el visor
    var enabled  = false; //indica si este behavior está operativo para afectar al visor
    
    var currentScale = 0;
    var widthDiv2 = 0;
    var heightDiv2 = 0;
    
    var queryScaleOut=false;
    var queryBeginScale=false;
    var zoomOp = WVZoomOp.NONE;
    var lastDir = WVZoomOp.NONE; //última dirección para zoom NO continuo
    var minScale = 0;
    var maxScale = 0;
    var nextScale= 0; //siguiente escala de visualización
    var isContinuousZoom = true;
    
    var limitZoom=true; //indica si se limita el zoom contínuo a un máximo
    var zoomSteps = 0; //pasos de zoom dados en la animación
    var zoomStepsLimit = 30; //límite máximo de pasos de zoom permitido
    
    this.getEnabled=function()
    {
        return enabled;
    }
    
    this.setEnabled=function(enable)
    {
        enabled = enable;
    }
    
    //retorna si el comportamiento debe estar siempre activo
    this.alwaysKeepEnabled=function()
    {
        return false;
    }
    
    this.init=function (visor)
    {
        viewer = visor;
        widthDiv2 = viewer.getWidth() / 2;
        heightDiv2 = viewer.getHeight() / 2;
        minScale = viewer.getScaleMin();
        maxScale= viewer.getScaleMax();
        setup();
    }
    
    this.getBehaviorType=function()
    {
        return WVBehaviorType.ZOOM_POWER_TWO;
    }
    
    //setup inicial de valores para el comportamiento
    function setup()
    {
        factorScale = 0.9;
        isContinuousZoom = true;
        isScaling = false;
        queryScaleOut  = false;
        queryBeginScale= false;
        zoomOp = WVZoomOp.NONE;
        lastDir = WVZoomOp.NONE;
        currentScale = 0;
        limitZoom=true;
        zoomSteps = 0;
    }
    
    this.onUpdate = function ()
    {
        if (queryBeginScale)
        {
            queryBeginScale=false;
            beginScale();
        }
        
        if (isScaling)
        {
            if (!queryScaleOut)
            {
                if (limitZoom)
                {
                    zoomSteps++;
                    if (zoomSteps >= zoomStepsLimit) //límite para no saturar el navegador con el tamaño de los Tiles
                    {
                        this.endScale();
                    }
                }
            
                if (!queryScaleOut)
                {
                    if (zoomOp == WVZoomOp.IN)
                    {
                        if ((currentScale * factorScale) <= viewer.getScaleMin()) //puede seguir escalado normal
                        {
                            this.endScale();
                            nextScale = viewer.getScaleMin();
                        }
                    }
                    else if (zoomOp == WVZoomOp.OUT)
                    {
                        if ((currentScale / factorScale) >= viewer.getScaleMax()) //puede seguir escalado normal
                        {
                            this.endScale();
                            nextScale = viewer.getScaleMax();
                        }
                    }
                }
            }
            
            if (queryScaleOut)
            {
                var exit=true;
                if (viewer.usePower2Scale())
                {
                    if (zoomOp == WVZoomOp.IN)
                    {
                        if ((currentScale * factorScale) > nextScale) //puede seguir escalado normal
                        {
                            exit=false;
                        }
                        else //ajusta a la siguiente escala y termina
                        {
                            factorScale = nextScale/currentScale;
                            doScaling();
                            exit=true;
                        }
                    }
                    else if (zoomOp == WVZoomOp.OUT)
                    {
                        if ((currentScale / factorScale) < nextScale) //puede seguir escalado normal
                        {
                            exit=false;
                        }
                        else //ajusta a la siguiente escala y termina
                        {
                            factorScale = currentScale/nextScale;
                            doScaling();
                            exit=true;
                        }
                    }
                }
                if (exit)
                {
                    
                    endScale();
                    queryScaleOut=false;
                    return;
                }
            }
            
            doScaling();
        }
    }
    
    //Retorna la escala actual a la que está el zoom animado
    this.getCurrentScale=function()
    {
        return currentScale;
    }
    
    this.isFinishing=function()
    {
        return queryScaleOut;
    }
    
    this.finalize=function()
    {
        if (nextScale !=viewer.getScale())
        {
            viewer.setScale(nextScale);
            viewer.redockLayers();
        }
        else
        {
            showSpecialLayers(true);
        }
        
        setup();
    }
    
    this.setZoomLimit=function(doLimit)
    {
        limitZoom = doLimit;
    }
    
    this.setContinuousZoom=function(continuo)
    {
        if (!queryScaleOut)
        {
            isContinuousZoom = continuo;
        }
    }
    
    //Establece un factor de escalado (cuanto menor sea, mayor la rapidez de Zoom)
    this.setScaleFactor=function(factor)
    {
        if (!queryScaleOut)
        {
            factorScale = factor;
        }
    }
    
    //Establece dirección de zooming
    this.setDirection=function(dir)
    {
        if (!queryScaleOut)
        {
            zoomOp = dir;
            lastDir = dir;
        }
    }
    
    //Provoca la inicialización del scaling
    this.beginScale=function()
    {
        if (!isScaling && !queryBeginScale) queryBeginScale=true;
    }
    
    function beginScale()
    {
        if (!isScaling && !queryScaleOut && enabled)
        {
            showSpecialLayers(false);
            
            //metadatos de escalado para tiles
            var layers = viewer.getSystemLayers();
            var n1=layers.length;
            for(var i=0;i<n1;i++)
            {
                if (layers[i].purge) layers[i].purge(); //fuerza purga de Tiles obsoletos de vistas anteriores
                
                if (layers[i].getVisible())
                {
                    var tiles = layers[i].getTiles();
                    var n2=tiles.length;
                    for(var j=0;j<n2;j++)
                    {
                        var x,y,w,h;
                        
                        w = parseFloat(tiles[j].style.width);
                        h = parseFloat(tiles[j].style.height);
                        x = parseFloat(tiles[j].style.left);
                        y = parseFloat(tiles[j].style.top);
                        
                        tiles[j].setAttribute("params_scale",x+","+y+","+w+","+h);
                    }
                }
            }
            
            queryScaleOut = false;
            isScaling=true;
            currentScale = viewer.getScale();
            zoomSteps = 0;
        }
    }
    
    //Provoca la finalización del scaling
    this.endScale=function()
    {
        if (isScaling && !queryScaleOut && enabled)
        {
            queryScaleOut=true;
            
            if (viewer.usePower2Scale() && !isContinuousZoom) //activa modo animación si aún está lejos de la escala definitiva
            {
                isContinuousZoom = true;
                zoomOp = lastDir;
                //factorScale = 0.95;
            }
            
            nextScale = calcNextScale(currentScale);
            nextScale = nextScale < viewer.getScaleMin() ? viewer.getScaleMin() : nextScale;
            nextScale = nextScale > viewer.getScaleMax() ? viewer.getScaleMax() : nextScale;
        }
    }
    
    function endScale()
    {
        isScaling=false;
        viewer.releaseBehavior();
    }
    
    //animación de scaling
    function doScaling()
    {
        if (zoomOp == WVZoomOp.IN)
        {
            if (currentScale<=minScale) //si llega a escala mínima, terminamos zoom
            {
                currentScale = minScale;
                nextScale = currentScale;
                oThis.endScale();
                return;
            }
            currentScale *= factorScale;
        }
        else if (zoomOp == WVZoomOp.OUT)
        {
            if (currentScale>=maxScale) //si llega a escala máxima, terminamos zoom
            {
                currentScale = maxScale;
                nextScale = currentScale;
                oThis.endScale();
                return;
            }
            currentScale /= factorScale;
        }
        
        if (zoomOp != WVZoomOp.NONE)
        {
            var layers = viewer.getSystemLayers();
            var n1=layers.length;
            for(var i=0;i<n1;i++)
            {
                if (layers[i].getVisible())
                {
                    var tiles = layers[i].getTiles();
                    var n2=tiles.length;
                    for(var j=0;j<n2;j++)
                    {
                        var x,y,w,h;
                        var params = tiles[j].getAttribute("params_scale");
                        params = params.split(',');
                        x=parseFloat(params[0]);
                        y=parseFloat(params[1]);
                        w=parseFloat(params[2]);
                        h=parseFloat(params[3]);
                        
                        //x = x - (x - parseFloat(tiles[j].style.left)); //sincroniza con scrolling
                        //y = y - (y - parseFloat(tiles[j].style.top));

                        x -=widthDiv2; //llevamos al origen de coordenadas para escalar
                        y -=heightDiv2;
                        if (zoomOp == WVZoomOp.IN)
                        {
                            x /= factorScale;
                            y /= factorScale;
                        }
                        else if (zoomOp == WVZoomOp.OUT)
                        {
                            x *=factorScale;
                            y *=factorScale;
                        }
                        x +=widthDiv2; //restauramos a coordenadas iniciales de escalado
                        y +=heightDiv2;
                        
                        var xx = Math.round(x);
                        var yy = Math.round(y);
                        tiles[j].style.left = xx;
                        tiles[j].style.top  = yy;
                       
                        if (zoomOp == WVZoomOp.IN)
                        {
                            w /= factorScale;
                            h /= factorScale;
                        }
                        else if (zoomOp == WVZoomOp.OUT)
                        {
                            w *=factorScale;
                            h *=factorScale;
                        }
                            
                        tiles[j].style.width = Math.ceil(w);
                        tiles[j].style.height= Math.ceil(h);
                        
                        tiles[j].setAttribute("params_scale",x+","+y+","+w+","+h);
                    }
                }
            }
        }
        
        if (!isContinuousZoom) zoomOp = WVZoomOp.NONE;
    }
    
    //Muestra u oculta capas que pueden ocasionar Glitches gráficos al escalar (Iconos, Tacks, etc.)
    function showSpecialLayers(ver)
    {
        var layerIcons = viewer.getSystemLayer(WVLayerType.ICON);
        if (layerIcons!=null)
        {
            layerIcons.setVisible(ver);
        }
        
        var cLayers = viewer.getCustomLayers();
        var n = cLayers.length;
        for (var i=0;i<n;i++)
        {
            cLayers[i].setVisible(ver);
        }
    }
    
    //retorna la siguiente escala a partir de la actual
    function calcNextScale()
    {
        if (viewer.usePower2Scale())
        {
            if (currentScale<=256) 
            {
                var s = 1;
                do
                {
                    s<<=1;
                }
                while (s<currentScale);
                
                if (zoomOp == WVZoomOp.IN)
                {
                    s>>=1;
                }
                else if (zoomOp == WVZoomOp.OUT && s==currentScale)
                {
                    s<<=1;
                }
                
                return s; 
            }
            
            var s = 0;
            do
            {
                s+=256;
            }
            while (s<currentScale);
            
            if (zoomOp == WVZoomOp.IN)
            {
                s-=256;
            }
            else if (zoomOp == WVZoomOp.OUT && s==currentScale)
            {
                s+=256;
            }
            
            return s;
        }
        else
        {
            return currentScale;
        }
    }
}

//Enumerado de opciones de zoom
function WVZoomOp(valor) 
{
    this.value = valor;
}
WVZoomOp.prototype.toString = function () 
{
    return this.value;
};
WVZoomOp.IN = new WVLayerType('IN');
WVZoomOp.OUT = new WVLayerType('OUT');
WVZoomOp.NONE = new WVLayerType('NONE');