﻿//Gestiona Tiles de la capa de Raster
function WVRasterLayer()
{
    var oThis = this;
    var panel = null;
    var viewer = null;
    var layerType = WVLayerType.RASTER;
    var visible = true;
    
    var rows = 0;
    var cols = 0;
    var widthGrid   = 0;
    var heightGrid  = 0;
    var widthTileUtmX  = 0;
    var heightTileUtmY = 0;
    
    var queryRefresh;
    this.tilesRemaining = 0; 
    var seedCache=0; //semilla para forzar la actualización de la capa con datos nuevos
    var numLayersBehind = 0; // número de capas que existen debajo de ésta
    
    var lstCurrentTiles; // lista de tiles que se visualizan de inmediato
    var lstPrevTiles; //lista de tiles visualizados en una vista anterior (debido a un zoom, principalmente)
    var queryPurge=false; //indica que es necesario eliminar Tiles de vistas anteriores
    var deltaPurge=0; //tiempo que ha pasado desde el inicio de una notificación de purgue
    var timeoutPurge=7000; //tiempo que debe pasar antes de purgar Tiles obsoletos
    var imgTranspURL = "";
            
    this.init = function(webviewer)
    {
        viewer = webviewer;
        imgTranspURL = document.getElementById(viewer.getBaseID() + viewer.getGUID() + "_imgTranspSrc").value;
                
        numLayersBehind = viewer.getSystemLayers().length - 1;
        setupReferences()
        setupPanel();
        calcRowsAndCols();
        
        //Setup inicial del grid
        lstCurrentTiles = createGrid();
        resolveTiles(sortTiles(viewer, lstCurrentTiles));
        
        for(var i=0;i<lstCurrentTiles.length;i++)
        {
            panel.appendChild(lstCurrentTiles[i]);
        }              
        viewer.subscribeEvent(WVEventType.CHANGE_SCALE, this.onChangeScale);
        queryRefresh=false;  
    }
    
    //Retorna si se ha completado la carga de esta capa
    this.isLoaded=function()
    {
        return this.tilesRemaining > 0 ? false : true;
    }
    
    this.setVisible=function(ver)
    {
        visible = ver;
        
        if (!visible)
        {
            panel.style.visibility= "hidden";
        }
        else
        {
            if (window.opera || window.addEventListener) this.renoveCache();
            queryRefresh=true;
        }
    }
    
    this.getVisible=function()
    {
        return visible;
    }
    
    this.getLayerType=function()
    {
        return layerType;
    }
    
    this.getContainer=function()
    {
        return panel;
    }
    
    this.getTiles = function ()
    {
        return lstCurrentTiles;
    }
    
    //Libera recursos
    this.dispose = function ()
    {
        disposeAll();
    }
    
    //Refresca la vista
    this.refresh=function()
    {
        queryRefresh=true;
    }
    
    //Scrolling de Tiles en base a un vector de desplazamiento
    this.onUpdate = function (offset, deltaTime)
    {
        if (queryPurge)
        {
            deltaPurge+=deltaTime;
            if (deltaPurge>=timeoutPurge)
            {
                deltaPurge=0;
                purgePrevTiles();
                queryPurge=false;
            }
        }
            
        if (visible)
        {
            if (queryRefresh)
            {
                refreshAll();
                queryRefresh=false;                
                return;
            }
            
            if (viewer.getRasterOpacity())
            {
                if (lstCurrentTiles!=null)
                {
                    for(var i=lstCurrentTiles.length-1;i>=0;i--) //Opacity
                    {
                        setOpacity(lstCurrentTiles[i]);
                    }
                }
            }
            
            if ( (offset.x!=0 || offset.y!=0)) //Scrolling
            {
                if (lstCurrentTiles!=null && lstCurrentTiles.length>0) doScroll(offset, lstCurrentTiles, true);
                if (lstPrevTiles!=null && lstPrevTiles.length>0) doScroll(offset, lstPrevTiles, false);
            }
        }
    }
    
    function doScroll(offset, lstScrollingTiles, refresh)
    {
        var powerOfTwo = viewer.usePower2Scale();
        var vw = viewer.getWidth();
        var vh = viewer.getHeight();
        var tw = viewer.getTileWidth();
        var th = viewer.getTileHeight();
        
        var lstTiles=new Array();
        
        var i=rows-1;
        do
        {
            var j = cols-1;
            do
            {
                var tile = lstScrollingTiles[i * cols + j];
                
                if (tile!=null)
                {
                    var tileX = parseInt(tile.style.left) + offset.x;
                    var tileY = parseInt(tile.style.top) + offset.y;
                    
                    if (!refresh) //sólo hace scrolling del Tile, sin recargar imagen ni cambiarla de posición
                    {
                        tile.style.left=tileX;
                        tile.style.top =tileY;
                    }
                    else
                    {
                        var widthChanged=0;
                        var heightChanged=0;
                        var swapped = false;
                        if (offset.x > 0 && tileX >= vw) //Scroll por la derecha
                        {
                            widthChanged = -widthGrid;
                            tileX -= widthGrid;
                            swapped = true;
                        }
                        else if (offset.x < 0 && tileX < - tw) //Scroll por la izquierda
                        {
                            widthChanged = widthGrid;
                            tileX += widthGrid;
                            swapped = true;
                        }
                        
                        if (offset.y < 0 && tileY < - th) //Scroll por arriba
                        {
                            heightChanged = heightGrid;
                            tileY += heightGrid;
                            swapped = true;
                        }
                        else if (offset.y > 0 && tileY >= vh) //Scroll por abajo
                        {
                            heightChanged = -heightGrid;
                            tileY -= heightGrid;
                            swapped = true;
                        }
                        
                        if (swapped)
                        {
                            hideTile(tile);
                            
                            if (powerOfTwo)
                            {
                                var utmX = parseInt(tile.getAttribute("utmX")) + (widthChanged * viewer.getScale());
                                var utmY = parseInt(tile.getAttribute("utmY")) - (heightChanged * viewer.getScale());
                                tile.setAttribute("utmX",utmX);
                                tile.setAttribute("utmY",utmY);
                            }
                            lstTiles.push(tile);
                        }
                        
                        tile.style.left=tileX;
                        tile.style.top =tileY;
                        
                        if (tile.getAttribute("NeedRefresh")=="true") //comprueba si algún tile dentro de la vista necesita recargarse
                        {
                            if ( (tileX<=viewer.getWidth() && tileX+256>=0) && (tileY<=viewer.getHeight() && tileY+256>=0) )
                            {
                                lstTiles.push(tile);
                            }
                        }
                    }
                }
            }
            while(j--);
        }
        while(i--);
        
        if (lstTiles.length>0) resolveTiles(sortTiles(viewer, lstTiles));
    }
        
    this.onChangeScale = function()
    {
        purgePrevTiles();
        oThis.refresh();
    }
    
    this.onRedock=function()
    {
        deltaPurge = 0;
        queryPurge = true;
        purgePrevTiles();
        
        lstPrevTiles = lstCurrentTiles;
        lstCurrentTiles = createGrid();
        for(var i=0;i<lstCurrentTiles.length;i++)
        {
            panel.appendChild(lstCurrentTiles[i]);
        }
        
        oThis.refresh();
    }
    
    this.purge = function()
    {
        purgePrevTiles();
    }
    
    function purgePrevTiles()
    {
        if (lstPrevTiles!=null && lstPrevTiles.length>0)
        {
            for(var i=0;i<lstPrevTiles.length;i++) //elimina Tiles del panel
            {
                lstPrevTiles[i].onload=null;
                lstPrevTiles[i].src=imgTranspURL;
                hideTile(lstPrevTiles[i]);
                panel.removeChild(lstPrevTiles[i]);
            }
            
            var j=lstPrevTiles.length-1; //elimina Tiles de la lista
            do
            {
                lstPrevTiles.splice(j,1);
            }
            while(j--);
            
            oThis.tilesRemaining = 0;
        }
    }
    
    //Renueva la semilla caché para no obtener los mismos datos gráficos en el próximo refresco
    this.renoveCache=function()
    {
        seedCache++;
    }
    
    function refreshAll()
    {
        setupReferences();
        
        var xIni = 0;
        var yIni = 0;
        
        var powerOfTwo = viewer.usePower2Scale();
        
        if (powerOfTwo)
        {
            var p = getFirstTileCorner(); //UTMs
            xIni = p.x;
            yIni = p.y;
        }
        else
        {
            xIni = (viewer.getWidth()  >> 1) - (widthGrid  >> 1); //Pixels
            yIni = (viewer.getHeight() >> 1) - (heightGrid >> 1);
        }
        
        var lstTiles=new Array();
        
        var tw = viewer.getTileWidth();
        var th = viewer.getTileHeight();
        var i=rows-1;
        do
        {
            var row = i * tw;
            var j=cols-1;
            do
            {
                var col = j * th;
                var tile = lstCurrentTiles[i * cols + j];
                if (tile!=null)
                {
                    hideTile(tile);
                    tile.onload=null;
                    tile.src=imgTranspURL;
                    
                    tile.style.width=tw;
                    tile.style.height=th; 
                    
                    if (powerOfTwo)
                    {
                        var utmX = xIni +(j * widthTileUtmX);
                        var utmY = yIni +(i * heightTileUtmY);
                        tile.setAttribute("utmX",utmX);
                        tile.setAttribute("utmY",utmY);
                        var px = viewer.transformWorldToLocal(utmX,utmY);
                        tile.style.top = Math.round(px.y) - th;
                        tile.style.left= Math.round(px.x);
                    }    
                    else
                    {
                        var x=xIni + col;
                        var y=yIni + row;
                        tile.style.top = y;
                        tile.style.left= x;  
                    }      
                    lstTiles.push(tile);       
                }
            }
            while(j--);
        }
        while(i--);
        
        oThis.tilesRemaining = 0;
        resolveTiles(sortTiles(viewer, lstTiles));
        
        if (visible)
        {
            panel.style.visibility = "visible";
        }
    }
    
    function disposeAll()
    {
        viewer.unsubscribeEvent(WVEventType.CHANGE_SCALE, oThis.onChangeScale);
        var j=panel.childNodes.length-1;
        do
        {
            var tile = panel.childNodes[j];
            panel.removeChild(tile);
        }
        while(j--);
        panel.innerHTML="";
    }
    
    //Crea panel contenedor de Tiles
    function setupPanel()
    {
        //configura panel contenedor
        panel = document.createElement('DIV');
        panel.style.width=viewer.getWidth();
        panel.style.height=viewer.getHeight();
        panel.style.top=-viewer.getHeight()*numLayersBehind;
        panel.style.left=0;
        panel.style.position="relative";
        panel.style.display="block";
        panel.style.backgroundColor="transparent";
        panel.style.zIndex = viewer.getZIndexBase()+10;
    }
    
    //Calcula filas y columnas de tiles que se necesitan para rellenar la capa
    function calcRowsAndCols()
    {
        rows = Math.ceil(viewer.getHeight()/viewer.getTileHeight()) + 2;
        cols = Math.ceil(viewer.getWidth()/viewer.getTileWidth()) + 2;
        
        widthGrid = viewer.getTileWidth() * cols;
        heightGrid = viewer.getTileHeight() * rows;
    }
    
    function setupReferences()
    {
        widthTileUtmX  = viewer.getTileWidth() *viewer.getScale();
        heightTileUtmY = viewer.getTileHeight()*viewer.getScale();
    }
    
    //Retorna la UTM inferior izquierda que corresponde al tile más cercano al visor ajustándose a la caché de disco
    function getFirstTileCorner()
    {
        var superBounds = viewer.getSuperBounds();
        
        var lengthToBoundsUTM = viewer.transformLocalToWorld((viewer.getWidth() >> 1), (viewer.getHeight() >> 1));
        lengthToBoundsUTM.x -= superBounds.x;
        lengthToBoundsUTM.y -= superBounds.y;
        var numTilesLeft = Math.floor(lengthToBoundsUTM.x/widthTileUtmX) - (cols>>1);
        var numTilesBottom = Math.floor(lengthToBoundsUTM.y/heightTileUtmY) - (rows>>1);
        numTilesLeft = numTilesLeft < 0 ? 0 : numTilesLeft;
        numTilesBottom = numTilesBottom < 0 ? 0 : numTilesBottom;
        
        var scale = viewer.getScale();
        var xIni = superBounds.x + ((numTilesLeft   * 256) * scale);
        var yIni = superBounds.y + ((numTilesBottom * 256) * scale);
        
        xIni = xIni - (xIni % 256);
        yIni = yIni - (yIni % 256);
        
        //reajusta corner si alguna coordenada en x,y sigue dentro del visor
        //Nota: es obligado cubrir todo el visor
        var px = viewer.transformWorldToLocal(xIni,yIni);
        if (px.x>0)
        {
            numTilesLeft = Math.ceil(px.x/256);
            xIni = xIni - ((numTilesLeft * 256) * scale);
        }
        
        if (px.y<viewer.getHeight())
        {
            numTilesBottom = Math.ceil((viewer.getHeight() - px.y)/256);
            yIni = yIni - ((numTilesBottom * 256) * scale);
        }
        
        return {x:xIni,y:yIni};
    }
    
    //Crea Tiles necesarios para visualización
    function createGrid()
    {
        var xIni = 0;
        var yIni = 0;
        
        var powerOfTwo = viewer.usePower2Scale();
        
        if (powerOfTwo)
        {
            var p = getFirstTileCorner(); //UTMs
            xIni = p.x;
            yIni = p.y;
        }
        else
        {
            xIni = (viewer.getWidth()  >> 1) - (widthGrid  >> 1); //Pixels
            yIni = (viewer.getHeight() >> 1) - (heightGrid >> 1);
        }
        
        var lstTiles=new Array();
        
        var tw = viewer.getTileWidth();
        var th = viewer.getTileHeight();
        
        var indexDomain=0;
        var domains = viewer.getDomains();
        var domainStep =0;
        
        var i=rows-1;
        do
        {
            var row = i * tw;
            var j=cols-1;
            do
            {
                if (domains.length>0)
                {
                    domainStep++;
                    if (domainStep>2)
                    {
                        domainStep=0;
                        indexDomain++;
                        indexDomain= indexDomain>=domains.length ? 0 : indexDomain;
                    }
                }
                
                var col = j * th;
                var tile = document.createElement('IMG');
                hideTile(tile);
                tile.setAttribute("indexDomain", indexDomain);
                tile.setAttribute("isMap", "true");
                tile.setAttribute("loading", "false");
                tile.style.position  = "absolute";
                tile.style.width=tw;
                tile.style.height=th;
                
                if (powerOfTwo)
                {
                    var utmX = xIni +(j * widthTileUtmX);
                    var utmY = yIni +(i * heightTileUtmY);
                    var px = viewer.transformWorldToLocal(utmX,utmY);
                    tile.style.top = Math.round(px.y) - th;
                    tile.style.left= Math.round(px.x);
                    tile.setAttribute("utmX",utmX);
                    tile.setAttribute("utmY",utmY);
                }
                else
                {
                    var x = xIni + col;
                    var y = yIni + row;
                    tile.style.top = y;
                    tile.style.left= x;
                }
                
                lstTiles.push(tile);
            }
            while(j--);
        }
        while(i--);
        
        return lstTiles;
    }
    
    //notifica la carga de un Tile
    function tileLoaded(e)
    {
        oThis.tilesRemaining--; //contador de tiles pendientes de carga
        oThis.tilesRemaining = oThis.tilesRemaining < 0 ? 0 : oThis.tilesRemaining;
        this.style.display="block";
        this.setAttribute("loading", "false");
    }
    
    //resuelve peticiones de tiles
    function resolveTiles(lstTiles)
    {
        var powerOfTwo = viewer.usePower2Scale();
        var n = lstTiles.length;
        for(var i=0;i<n;i++)
        {
            var tile = lstTiles[i];
            if (powerOfTwo) 
            {
                resolveDirectUTM(tile, tile.getAttribute("utmX"), tile.getAttribute("utmY"));
            }
            else
            {
                resolveDirectPX(tile, parseInt(tile.style.left), parseInt(tile.style.top));
            }

            hideTile(tile);
            tile.onload=null;
            tile.src=imgTranspURL;
            if (tile.getAttribute("loading")=="true")
            {
                if (tile.getAttribute("NeedRefresh")=="false")
                {
                    tile.onload = tileLoaded;
                    tile.src = tile.getAttribute("NextURL");
                }
                else if (tile.getAttribute("NeedRefresh")=="true")
                {
                    tile.setAttribute("loading", "false");
                    oThis.tilesRemaining--; //contador de tiles pendientes de carga
                    oThis.tilesRemaining = oThis.tilesRemaining < 0 ? 0 : oThis.tilesRemaining;
                }
            }
        }
    }
    
    //Determina si un tile está fuera de la vista para actualizar su contenido.
    //Retorna true si está dentro de la vista o false en caso contrario
    function processTileForView(tile, px, py)
    {
        var result = true;
        
        if ( (px>viewer.getWidth() || px+256<0) || (py>viewer.getHeight() || py+256<0) )
        {
            result = false;
        }
        
        return result;
    }
    
    //resuelve tile con coordenadas UTM
    function resolveDirectUTM(tile, utmX, utmY)
    {
        //si el tile está fuera de la vista, no lo carga
        var x = parseInt(tile.style.left);
        var y = parseInt(tile.style.top);
        if (!processTileForView(tile, x, y)) 
        {
            tile.setAttribute("NeedRefresh","true");
            return;
        }
        
        var url = resolveUTM(tile, utmX, utmY);
        tile.setAttribute("NeedRefresh","false");
        tile.setAttribute("NextURL", url);
        if (tile.getAttribute("loading")=="true") oThis.tilesRemaining--;
        tile.setAttribute("loading", "true");
        oThis.tilesRemaining++;
    }
    
    //resuelve tile con coordenadas pantalla (pixel)
    function resolveDirectPX(tile, px, py)
    {
        if (!processTileForView(tile, px, py)) 
        {
            tile.setAttribute("NeedRefresh","true");
            return;
        }
        
        var url = resolve(tile, px, py);
        tile.setAttribute("NeedRefresh","false");
        tile.setAttribute("NextURL", url);
        if (tile.getAttribute("loading")=="true") oThis.tilesRemaining--;
        tile.setAttribute("loading", "true");
        oThis.tilesRemaining++;
    }
    
    //Retorna la URL que corresponde a un Tile con las coordenadas pantalla como parámetros
    function resolve (tile, xLocal, yLocal)
    {
        var domain = getDomain(parseInt(tile.getAttribute("indexDomain")));
        
        var host = domain + viewer.getUrlBase()+"op=0&";
        var visor = "VisorID=" + viewer.getGUID() + "&";
        var v = viewer.transformLocalToWorld(xLocal, yLocal + viewer.getTileHeight());
        var coords = "Args="+v.x+","+v.y+","+widthTileUtmX+","+heightTileUtmY+","+viewer.getTileWidth()+","+viewer.getTileHeight()+"&";
        var basura = "cacheSeed="+seedCache+"&scale="+viewer.getScale();
        return host + visor + coords + basura;
    } 
    
    function resolveUTM (tile, xUtm, yUtm)
    {
        var domain = getDomain(parseInt(tile.getAttribute("indexDomain")));
        
        var host = domain + viewer.getUrlBase()+"op=0&";
        var visor = "VisorID=" + viewer.getGUID() + "&";
        var coords = "Args="+xUtm+","+yUtm+","+widthTileUtmX+","+heightTileUtmY+","+viewer.getTileWidth()+","+viewer.getTileHeight()+"&";
        var basura = "cacheSeed="+seedCache+"&scale="+viewer.getScale();
        return host + visor + coords + basura;
    }
    
    //retorna un nombre de dominio en base a un indice
    function getDomain(index)
    {
        var domains = viewer.getDomains();
        var domain ="";
        if (domains.length>0 && index>=0 && index<domains.length)
        {
            domain = domains[index];
        }
        return domain;
    }
    
    function hideTile(tile)
    {
        if (tile!=null)
        {
            tile.style.display="none";
            if (viewer.getRasterOpacity())
            {
                tile.style.filter="alpha(opacity=0)"; //0-100
                tile.style.opacity="0"; //0-1
            }
        }
    }
    
    //asigna nivel de opacidad a tile
    function setOpacity(tile)
    {
        try
        {
            if (tile!=null)
            {
                var isLoading = tile.getAttribute("loading");
                if (isLoading!=null && isLoading=="false")
                {
                    var opacity = parseFloat(tile.style.opacity);
                    if (opacity<1)
                    {
                        opacity+=0.35;
                        opacity= (opacity>=1) ? 1 : opacity;
                        tile.style.filter="alpha(opacity="+(opacity*100)+")"; //0-100
                        tile.style.opacity=opacity; //0-1
                        
                        if (opacity==1) tile.style.filter="";
                    }
                }
            }
        }catch(e){}
    }
}


