﻿/* Copyright (c) 2006 MetaCarta, Inc., published under the BSD licence.
 * See http://svn.openlayers.org/trunk/openlayers/release-license.txt 
 * for the full text of the license. */

var debugCnt = 0;

/**
 * @class
 * 
 * @requires OpenLayers/Layer/Grid.js
 */
OpenLayers.Layer.EnvinsaTileServer = OpenLayers.Class.create();
OpenLayers.Layer.EnvinsaTileServer.prototype = 
  OpenLayers.Class.inherit( OpenLayers.Layer.Grid, {
  
    /** Hashtable of default parameter key/value pairs 
     * @final @type Object */
    DEFAULT_PARAMS: {   reproject: false,
                        isBaseLayer: true,
                        tileOrigin: null,
                        output: 'image/png',
                        minZoomLevel: -1,   // minZoomLevel, maxZoomLevel
                        maxZoomLevel: -1    // to setup custom zoom levels
    },
    
    /**
    * @constructor
    *
    * @param {String} name
    * @param {String} url
    * @param {Object} params
    * @param {Object} options Hashtable of extra options to tag onto the layer
    */
    initialize: function(name, url, params, options) {
        var newArguments = new Array();
        //uppercase params
        params = OpenLayers.Util.upperCaseObject(params);
        newArguments.push(name, url, params, options);
        OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
        OpenLayers.Util.applyDefaults(
                       this.params, 
                       OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS)
                       );

        // unless explicitly set in options, if the layer is transparent, 
        // it will be an overlay
        if (options == null || options.isBaseLayer == null) {
            this.isBaseLayer = ((this.params.TRANSPARENT != "true") && 
                                (this.params.TRANSPARENT != true));
        }
        this.setTileSize(new OpenLayers.Size(256, 128));  
        
        if (options.minZoomLevel != null && options.maxZoomLevel != null) {
            minZoomLevel = options.minZoomLevel;
            maxZoomLevel = options.maxZoomLevel;
        }
    },    

    /**
     * 
     */
    destroy: function() {
        // for now, nothing special to do here. 
        OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);  
    },

    
    /**
     * @param {Object} obj
     * 
     * @returns An exact clone of this OpenLayers.Layer.EnvinsaTileServer
     * @type OpenLayers.Layer.EnvinsaTileServer
     */
    clone: function (obj) {
        
        if (obj == null) {
            obj = new OpenLayers.Layer.EnvinsaTileServer(this.name,
                                           this.url,
                                           this.params,
                                           this.options);
        }

        //get all additions from superclasses
        obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);

        // copy/set any non-init, non-simple values here

        return obj;
    },    
    
    /**
     * @param {OpenLayers.Bounds} bounds
     * 
     * @returns A string with the layer's url and parameters and also the 
     *           passed-in bounds and appropriate tile size specified as 
     *           parameters
     * @type String
     *   To Get a Tile:
     *   http://www.mapinfo.net/MapTiling/RESTService/getTile?name=<map name>&level=<int>&row=<int>&col=<int>&output=png
     *   The row is 1 based.
     *   The col is 1 based.
     */
    getURL: function (bounds) {
        var mapBounds = map.getMaxExtent();
        var res = this.map.getResolution();
        var x = ((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w)) + 1;
        var y = (((mapBounds.top - mapBounds.bottom) / (res * this.tileSize.h)) - ((bounds.bottom - this.tileOrigin.lat) / (res * this.tileSize.h)));
        var z = this.map.getZoom()+1;
        x = parseInt(x);
        y = parseInt(y);
        
        // Custom zoom levels
        if (minZoomLevel != -1) {
            if (this.numZoomLevels == 2) {
                if (this.map.getZoom()==0)
                   z=minZoomLevel;
                else 
                    z=maxZoomLevel;
            }
            else if (this.numZoomLevels == maxZoomLevel-minZoomLevel+1) {
                z = this.map.getZoom()+minZoomLevel;
            }
            else if ( (maxZoomLevel-minZoomLevel+2)%this.numZoomLevels==0){
                z = this.map.getZoom()*((maxZoomLevel-minZoomLevel+2)/this.numZoomLevels)+minZoomLevel;                
            }
        }
        ///////////////
        
        var mapname = this.params.MAPNAME;
        var outputfmt = this.params.OUTPUT;
        var retUrl = this.url + "?name=" + mapname + "&level=" + z + "&row=" + y + "&col=" + x + "&output=" + outputfmt.substring(6);
//        this.alert(retUrl);
        if (this.params.USERNAME != null)
        {
            retUrl = retUrl + "&username="+this.params.USERNAME+"&password="+this.params.PASSWORD;
        }
                
        // Debug stuff
        var debugOut = $('DebugOut');
        //if (this.debugCnt == null) var debugCnt = 0;
        if (debugOut != null) {
            debugOut.value = debugOut.value+debugCnt+" row: "+y+" col: "+x+" \tz: "+z+" \tBBOX: ("+bounds.left+","+bounds.top+","+bounds.right+","+bounds.bottom+")\n";
            debugCnt += 1;
        }
        
        return retUrl; 
    },

    /**
    * addTile creates a tile, initializes it, and 
    * adds it to the layer div. 
    *
    * @param {OpenLayers.Bounds} bounds
    *
    * @returns The added OpenLayers.Tile.Image
    * @type OpenLayers.Tile.Image
    */
    addTile:function(bounds,position) {
        var url = this.getURL(bounds);
        return new OpenLayers.Tile.Image(this, position, bounds, 
                                             url, this.tileSize);
    },

    /** When the layer is added to a map, then we can fetch our origin 
     *  (if we don't have one.) 
     * 
     * @param {OpenLayers.Map} map
     */
    setMap: function(map) {
        OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments);
        if (!this.tileOrigin) { 
            this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left,
                                                this.map.maxExtent.bottom);
        }                                       
    },

     /**
     * Catch changeParams and uppercase the new params to be merged in
     *  before calling changeParams on the super class.
     * 
     * Once params have been changed, we will need to re-init our tiles
     * 
     * @param {Object} newParams Hashtable of new params to use
     */
    mergeNewParams:function(newParams) {
        var upperParams = OpenLayers.Util.upperCaseObject(newParams);
        var newArguments = [upperParams];
        OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this, 
                                                             newArguments);
    },

    /** combine the layer's url with its params and these newParams. 
    *   
    *    Add the SRS parameter from projection -- this is probably
    *     more eloquently done via a setProjection() method, but this 
    *     works for now and always.
    * 
    * @param {Object} newParams
    * 
    * @type String
    */
    getFullRequestString:function(newParams) {
        var projection = this.map.getProjection();
        this.params.SRS = (projection == "none") ? null : projection;

        return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
                                                    this, arguments);
    },
       
    /** @final @type String */
    CLASS_NAME: "OpenLayers.Layer.EnvinsaTileServer"
});

