//
//	TerraServer Functionality for Google Maps API V2
//      Philip Gladstone
//      http://pond.gladstonefamily.net
//      May 2006
//      Heavily based on code by
//	Nick Jacobsen
//	http://www.lokkju.com
//	July, 2005
//
//	Some UTM functions taken from taken from http://www.mccormick.uk.com/html/distancecalculator.html
//	Some coding concepts based on David Schuetz's Terraserver Functionality
// 		for Google Maps Standalone Mode (http://www.dasnet.org/node/101)
//
//	Use of this file is governed by the 3 clause BSD style license
//

function _makeWMSUTMMap(layers, epsg, label, copyright) {

var zone_width = Math.floor(1000000/102400) * 102400;

var theTileSize = 512


//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 
// UTM conversion functions, etc.
// taken from http://www.mccormick.uk.com/html/distancecalculator.html
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 

var deg2rad = Math.PI / 180;
var rad2deg = 180.0 / Math.PI;
var pi = Math.PI;


function geo_constants(ellipsoid)
{
// return values as an object
var ellipsoid = { axis: 6378137, 
                  eccentricity: 0.00669438 };
return ellipsoid;
}

function calc_utm(lat, lon)
{
// DJS - hardcode ellipsoid to 21, and get the appropriate access and eccent
var ellipsoid = geo_constants(21);  
var axis = ellipsoid.axis;
var eccent = ellipsoid.eccentricity;

var k0 = 0.9996;
var latrad = lat * deg2rad;
var longrad = lon * deg2rad;
var zonenum = floor((lon + 180) / 6) + 1;
if (lat >= 56.0 && lat < 64.0 && lon >= 3.0 && lon < 12.0 )
  zonenum = 32;
// Special zones for Svalbard
if( lat >= 72.0 && lat < 84.0 ) 
  {
  if (lon >= 0.0  && lon <  9.0 ) zonenum = 31;
  else if ( lon >= 9.0  && lon < 21.0 ) zonenum = 33;
  else if ( lon >= 21.0 && lon < 33.0 ) zonenum = 35;
  else if ( lon >= 33.0 && lon < 42.0 ) zonenum = 37;
 }

var lonorig = (zonenum - 1) * 6 - 180 + 3;  //+3 puts origin in middle of zone
var lonorigrad = lonorig * deg2rad;

var eccPrimeSquared = (eccent) / (1 - eccent);

//calculate
var N = axis / sqrt(1 - eccent * sin(latrad) * sin(latrad));
var T = tan(latrad) * tan(latrad);
var C = eccPrimeSquared * cos(latrad) * cos(latrad);
var A = cos(latrad) * (longrad - lonorigrad);
var M = axis * ((1 - eccent / 4 - 3 * eccent * eccent / 64 - 5 * eccent * eccent * eccent / 256) * latrad - (3 * eccent / 8 + 3 * eccent * eccent / 32 + 45 * eccent * eccent *eccent / 1024) * sin(2 * latrad) + (15 * eccent * eccent / 256 + 45 * eccent * eccent * eccent / 1024) * sin(4 * latrad) - (35 * eccent * eccent * eccent / 3072) * sin(6 * latrad));

var easting = (k0 * N * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120) + 500000.0);
var northing = (k0 * (M + N * tan(latrad) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 + (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A * A * A / 720)));

//if (lat < 0)
  //northing += 10000000.0; // 100000 meter offset for southern hemisphere

ret = { x:easting, y:northing, z:zonenum }

return ret;
}

//===================================================================
function val_utm(zone, northing, easting)
{
// DJS - hardcode to 21 (WGS-84)
ellipsoid = geo_constants(21);

var axis = ellipsoid.axis;
var eccent = ellipsoid.eccentricity;
var k0 = 0.9996;

var e1 = (1 - sqrt(1 - eccent)) / (1 + sqrt(1 - eccent));
var x = easting - 500000.0; //remove 500,000 meter offset for longitude
var y = northing;

var nhemisphere = 1;

var longorig = (zone - 1) * 6 - 180 + 3;  //+3 puts origin in middle of zone

var eccPrimeSquared = (eccent) / (1-eccent);
var M = y / k0;
var mu = M / (axis * (1 - eccent / 4 - 3 * eccent * eccent / 64 - 5 * eccent * eccent * eccent / 256));
var phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * sin(4 * mu) + (151 * e1 * e1 * e1 / 96) * sin(6 * mu);
var phi1 = phi1Rad * rad2deg;
var N1 = axis / sqrt(1 - eccent * sin(phi1Rad) * sin(phi1Rad));


var T1 = tan(phi1Rad) * tan(phi1Rad);
var C1 = eccPrimeSquared * cos(phi1Rad) * cos(phi1Rad);
var R1 = axis * (1 - eccent) / pow(1-eccent * sin(phi1Rad) * sin(phi1Rad), 1.5);
var D = x / (N1 * k0);
var lat = phi1Rad - (N1 * tan(phi1Rad) / R1) * (D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D * D * D * D / 24 + (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C1 * C1) * D * D * D * D * D * D / 720);
lat = lat * rad2deg;
var lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1) * D * D * D * D * D / 120) / cos(phi1Rad);
lon = longorig + lon * rad2deg;

ret = new GLatLng(lat,lon);
return ret;
}


//===================================================================

    function mod(y, x)
    {
        if (y >= 0)
            return y - x * floor(y / x);
        else
            return y + x * (floor(-y / x) + 1.0);
    }

    function sqrt(x) { return Math.sqrt(x); }

    function tan(x) { return Math.tan(x); }

    function sin(x) { return Math.sin(x); }

    function cos(x) { return Math.cos(x); }

    function floor(x) { return Math.floor(x); }

    function pow(x, y) { return Math.pow(x, y); }

    function UTMProjection() {
    }

    UTMProjection.prototype = new GProjection();

    UTMProjection.prototype.fromLatLngToPixel=function(a,b) {
        var d = new GPoint;
        var ut = calc_utm(a.y, a.x);

        d.x = Math.round((ut.x + (ut.z - 1) * zone_width) / pow(2, 17 - b));
        d.y = -Math.round(ut.y / pow(2, 17 - b));
        return d;
    }

    UTMProjection.prototype.fromPixelToLatLng=function(a,s,c) {
        var x = a.x
        var k = a.y
        x = x * pow(2, 17 - s);
        var n = -k * pow(2, 17 - s);
        var e = x - floor(x/zone_width)*zone_width;
        var z = floor(x/zone_width)+1;

        var ll=val_utm(z,n,e);
        return new GLatLng(ll.lat(), ll.lng(), c)
    }

    UTMProjection.prototype.tileCheckRange=function(a,b,c) {
        return true
    }

    UTMProjection.prototype.getWrapWidth=function(zoom) {
        return 60 * zone_width / pow(2, 17 - zoom);
    }

    var copycoll = new GCopyrightCollection(copyright + " &copy; ");

    copycoll.addCopyright(new GCopyright(1, new GLatLngBounds(new GLatLng(-90, -180), new GLatLng(90, 180)), 0, "zzzz"));

    var minZ = 20
    var maxZ = 0

    for (x in layers) {
        if (maxZ < layers[x].maxZ) {
            maxZ = layers[x].maxZ
        }
        if (minZ > layers[x].minZ) {
            minZ = layers[x].minZ
        }
    }

    function getEPSG (z, y) {
        var epsgtabN = new Array();
        var epsgtabS = new Array();

        epsgtabN.push({l:25828, h:25838});

        var epsgtab = (y >= 0) ? epsgtabN : epsgtabS;

        for (i in epsgtab) {
            if (epsg >= epsgtab[i].l && epsg <= epsgtab[i].h) {
                var r = z + epsgtab[i].l - epsgtab[i].l % 100;
                if (r >= epsgtab[i].l && r <= epsgtab[i].h) {
                    return r;
                }
            }
        }

        return (y >= 0 ? 32600 : 32700) + z;
    }

    var tilelayer = new GTileLayer(copycoll, minZ, maxZ);

    tilelayer.layers = layers

    tilelayer.getTileUrl = function (a,zoom) {
        var s = 17 - zoom;
        var factor = pow(2, s)
        var x = a.x * factor * theTileSize;
        var y = -a.y * factor * theTileSize;


        var z = floor(x/zone_width)+1;
        x = floor(x - floor(x/zone_width)*zone_width);

        var srs = "EPSG:" + getEPSG(z, y);

        if (y < 0) {
            y += 10000000;
        }

        var bbox = x + "," + (y - (theTileSize ) * factor) + "," + (x + (theTileSize ) * factor) + "," + y;

        var baseURL = "";

        for (i in this.layers) {
            if (zoom >= this.layers[i].minZ && zoom <= this.layers[i].maxZ) {
                baseURL = this.layers[i].url + "REQUEST=getMap&SERVICE=WMS&VERSION=1.1.0&LAYERS=" + this.layers[i].layer + "&STYLES=&FORMAT=image/png&BGCOLOR=0xffffff&TRANSPARENT=true&WIDTH=" + theTileSize + "&HEIGHT=" + theTileSize;
            }
        }

        var servernum = 0;

        if (a.x & 1) servernum += 2;
        if (a.y & 1) servernum += 1;

        baseURL = baseURL.replace(/server\.gladstonefamily/, "server" + servernum + ".gladstonefamily");

        return baseURL + "&BBOX=" + bbox + "&SRS=" + srs;
    } ;


    return new GMapType([tilelayer], new UTMProjection(), label, {errorMessage:"No Data Available", tileSize:theTileSize});

}

function WMSLayer(url, layer, minZ, maxZ) {
    this.url = url;
    this.layer = layer;
    this.minZ = minZ;
    this.maxZ = maxZ;
}


