/* #region TISolution */
TISolution = {
    VERSION_NUMBER: "1.0.0",
    apikey: null,
    CURSOR_PAN: "url('http://sistemas.tisolution.com/timap/script/theme/default/img/pan.cur') 9 9, url('http://sistemas.tisolution.com/timap/script/theme/default/img/pan.cur'), auto",
    CURSOR_PAN_DOWN: "url('http://sistemas.tisolution.com/timap/script/theme/default/img/pandown.cur') 9 9, url('http://sistemas.tisolution.com/timap/script/theme/default/img/pandown.cur'), auto",
    getServerBase: function()
    {
        return "http://sistemas.tisolution.com:8085/mapsolution/gwc/service";
    },
    getTileServerPath: function()
    {
        return "/wms";
    },
    getGazetteerServerPath: function()
    {
        return "/gazetteer";
    },
    getSupportServerPath: function()
    {
        return "/jsapi";
    },
    getApiKey: function()
    {
        return this.apikey || this._getApiKey();
    },
    getURL: function()
    {
        return document.URL;
    },
    _getApiKey: function()
    {
        var apikey = null;
        var scripts = document.getElementsByTagName('script');
        for (var i = 0; i < scripts.length; i++)
        {
            var src = scripts[i].getAttribute('src');
            if (src)
            {
                var index = src.lastIndexOf(OpenLayers._scriptName);
                if (index > -1)
                {
                    var strQueryString = src.substr(src.indexOf("?"));
                    var aQueryString = strQueryString.split("&");
                    for (var iParam = 0; iParam < aQueryString.length; iParam++)
                    {
                        if (aQueryString[iParam].indexOf("key=") > -1)
                        {
                            var aParam = aQueryString[iParam].split("=");
                            apikey = aParam[1];
                            break;
                        }
                    }
                }
            }
        }
        this.apikey = apikey;
        return apikey;
    },
    CLASS_NAME: "TISolution"
};
TISolution.SRS = {
    EPSG4326: 4326,
    EPSG27700: 27700,
    CLASS_NAME: "TISolution.SRS"
};
TISolution.MapPoint = OpenLayers.Class(OpenLayers.LonLat, {
    srs: null,
    initialize: function(eastings, northings, srs)
    {
        this.lon = parseFloat(eastings);
        this.lat = parseFloat(northings);
        this.srs = srs || TISolution.SRS.EPSG27700;
    },
    getEasting: function()
    {
        return this.lon;
    },
    getNorthing: function()
    {
        return this.lat;
    },
    toString: function()
    {
        return ("eastings=" + this.lon + ",northings=" + this.lat);
    },
    toCoordString: function()
    {
        return ("(" + this.lon + "," + this.lat + ")");
    },
    clone: function()
    {
        return new TISolution.MapPoint(this.lon, this.lat, this.srs);
    },
    add: function(eastings, northings)
    {
        if ((eastings == null) || (northings == null))
        {
            var msg = "You must pass both eastings and northings values " + "to the add function.";
            OpenLayers.Console.error(msg);
            return null;
        }
        return new TISolution.MapPoint(this.lon + eastings, this.lat + northings);
    },
    equals: function(ll)
    {
        var equals = false;
        if (ll != null)
        {
            equals = ((this.lon == ll.lon && this.lat == ll.lat && this.srs == ll.srs) || (isNaN(this.lon) && isNaN(this.lat) && isNaN(ll.lon) && isNaN(ll.lat)));
        }
        return equals;
    },
    CLASS_NAME: "TISolution.MapPoint"
});
TISolution.MapPoint.fromString = function(str)
{
    var pair = str.split(",");
    return new TISolution.MapPoint(parseFloat(pair[0]), parseFloat(pair[1]));
};
TISolution.MapSize = OpenLayers.Class(OpenLayers.Size, {
    srs: null,
    initialize: function(w, h)
    {
        this.w = parseFloat(w);
        this.h = parseFloat(h);
        this.srs = TISolution.SRS.EPSG27700;
    },
    toString: function()
    {
        return ("w=" + this.w + ",h=" + this.h);
    },
    clone: function()
    {
        return new TISolution.MapSize(this.w, this.h);
    },
    equals: function(sz)
    {
        var equals = false;
        if (sz != null)
        {
            equals = ((this.w == sz.w && this.h == sz.h && this.srs == sz.srs) || (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
        }
        return equals;
    },
    CLASS_NAME: "TISolution.MapSize"
});
TISolution.MapBounds = OpenLayers.Class(OpenLayers.Bounds, {
    srs: null,
    initialize: function(left, bottom, right, top)
    {
        if (left != null)
        {
            this.left = parseFloat(left);
        }
        if (bottom != null)
        {
            this.bottom = parseFloat(bottom);
        }
        if (right != null)
        {
            this.right = parseFloat(right);
        }
        if (top != null)
        {
            this.top = parseFloat(top);
        }
        this.srs = TISolution.SRS.EPSG27700;
    },
    clone: function()
    {
        return new TISolution.MapBounds(this.left, this.bottom, this.right, this.top);
    },
    equals: function(bounds)
    {
        var equals = false;
        if (bounds != null)
        {
            equals = ((this.left == bounds.left) && (this.right == bounds.right) && (this.top == bounds.top) && (this.bottom == bounds.bottom) && (this.srs == bounds.srs));
        }
        return equals;
    },
    toString: function()
    {
        return ("left-bottom=(" + this.left + "," + this.bottom + ")" + " right-top=(" + this.right + "," + this.top + ")");
    },
    toArray: function()
    {
        return [this.left, this.bottom, this.right, this.top];
    },
    toBBOX: function(decimal)
    {
        if (decimal == null)
        {
            decimal = 6;
        }
        var mult = Math.pow(10, decimal);
        var bbox = Math.round(this.left * mult) / mult + "," + Math.round(this.bottom * mult) / mult + "," + Math.round(this.right * mult) / mult + "," + Math.round(this.top * mult) / mult;
        return bbox;
    },
    getWidth: function()
    {
        return (this.right - this.left);
    },
    getHeight: function()
    {
        return (this.top - this.bottom);
    },
    getSize: function()
    {
        return new TISolution.MapSize(this.getWidth(), this.getHeight());
    },
    getCenter: function()
    {
        return new TISolution.MapPoint((this.left + this.right) / 2, (this.bottom + this.top) / 2);
    },
    add: function(x, y)
    {
        if ((x == null) || (y == null))
        {
            var msg = "You must pass both x and y values to the add function.";
            OpenLayers.Console.error(msg);
            return null;
        }
        return new TISolution.MapBounds(this.left + x, this.bottom + y, this.right + x, this.top + y);
    },
    extend: function(object)
    {
        var bounds = null;
        if (object)
        {
            switch (object.CLASS_NAME)
            {
                case "TISolution.MapPoint":
                    bounds = new TISolution.MapBounds(object.lon, object.lat, object.lon, object.lat);
                    break;
                case "OpenLayers.Geometry.Point":
                    bounds = new TISolution.MapBounds(object.x, object.y, object.x, object.y);
                    break;
                case "TISolution.MapBounds":
                    bounds = object;
                    break;
            }
            if (bounds)
            {
                if ((this.left == null) || (bounds.left < this.left))
                {
                    this.left = bounds.left;
                }
                if ((this.bottom == null) || (bounds.bottom < this.bottom))
                {
                    this.bottom = bounds.bottom;
                }
                if ((this.right == null) || (bounds.right > this.right))
                {
                    this.right = bounds.right;
                }
                if ((this.top == null) || (bounds.top > this.top))
                {
                    this.top = bounds.top;
                }
            }
        }
    },
    containsLonLat: function(ll, inclusive)
    {
        return this.contains(ll.lon, ll.lat, inclusive);
    },
    contains: function(x, y, inclusive)
    {
        if (inclusive == null)
        {
            inclusive = true;
        }
        var contains = false;
        if (inclusive)
        {
            contains = ((x >= this.left) && (x <= this.right) && (y >= this.bottom) && (y <= this.top));
        } else
        {
            contains = ((x > this.left) && (x < this.right) && (y > this.bottom) && (y < this.top));
        }
        return contains;
    },
    intersectsBounds: function(bounds, inclusive)
    {
        if (inclusive == null)
        {
            inclusive = true;
        }
        var inBottom = (bounds.bottom == this.bottom && bounds.top == this.top) ? true : (((bounds.bottom > this.bottom) && (bounds.bottom < this.top)) || ((this.bottom > bounds.bottom) && (this.bottom < bounds.top)));
        var inTop = (bounds.bottom == this.bottom && bounds.top == this.top) ? true : (((bounds.top > this.bottom) && (bounds.top < this.top)) || ((this.top > bounds.bottom) && (this.top < bounds.top)));
        var inRight = (bounds.right == this.right && bounds.left == this.left) ? true : (((bounds.right > this.left) && (bounds.right < this.right)) || ((this.right > bounds.left) && (this.right < bounds.right)));
        var inLeft = (bounds.right == this.right && bounds.left == this.left) ? true : (((bounds.left > this.left) && (bounds.left < this.right)) || ((this.left > bounds.left) && (this.left < bounds.right)));
        return (this.containsBounds(bounds, true, inclusive) || bounds.containsBounds(this, true, inclusive) || ((inTop || inBottom) && (inLeft || inRight)));
    },
    containsBounds: function(bounds, partial, inclusive)
    {
        if (partial == null)
        {
            partial = false;
        }
        if (inclusive == null)
        {
            inclusive = true;
        }
        var inLeft;
        var inTop;
        var inRight;
        var inBottom;
        if (inclusive)
        {
            inLeft = (bounds.left >= this.left) && (bounds.left <= this.right);
            inTop = (bounds.top >= this.bottom) && (bounds.top <= this.top);
            inRight = (bounds.right >= this.left) && (bounds.right <= this.right);
            inBottom = (bounds.bottom >= this.bottom) && (bounds.bottom <= this.top);
        } else
        {
            inLeft = (bounds.left > this.left) && (bounds.left < this.right);
            inTop = (bounds.top > this.bottom) && (bounds.top < this.top);
            inRight = (bounds.right > this.left) && (bounds.right < this.right);
            inBottom = (bounds.bottom > this.bottom) && (bounds.bottom < this.top);
        }
        return (partial) ? (inTop || inBottom) && (inLeft || inRight) : (inTop && inLeft && inBottom && inRight);
    },
    determineQuadrant: function(lonlat)
    {
        var quadrant = "";
        var center = this.getCenterLonLat();
        quadrant += (lonlat.lat < center.lat) ? "b" : "t";
        quadrant += (lonlat.lon < center.lon) ? "l" : "r";
        return quadrant;
    },
    CLASS_NAME: "TISolution.MapBounds"
});
TISolution.MapBounds.fromString = function(str)
{
    var bounds = str.split(",");
    return TISolution.MapBounds.fromArray(bounds);
};
TISolution.MapBounds.fromArray = function(bbox)
{
    return new TISolution.MapBounds(parseFloat(bbox[0]), parseFloat(bbox[1]), parseFloat(bbox[2]), parseFloat(bbox[3]));
};
TISolution.MapBounds.fromSize = function(size)
{
    return new TISolution.MapBounds(0, size.h, size.w, 0);
};
TISolution.MapBounds.oppositeQuadrant = function(quadrant)
{
    var opp = "";
    opp += (quadrant.charAt(0) == 't') ? 'b' : 't';
    opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l';
    return opp;
};
TISolution.ScreenPoint = OpenLayers.Class(OpenLayers.Pixel, {
    initialize: function(x, y)
    {
        this.x = parseFloat(x);
        this.y = parseFloat(y);
    },
    toString: function()
    {
        return ("x=" + this.x + ",y=" + this.y);
    },
    clone: function()
    {
        return new TISolution.ScreenPoint(this.x, this.y);
    },
    equals: function(px)
    {
        var equals = false;
        if (px != null)
        {
            equals = ((this.x == px.x && this.y == px.y) || (isNaN(this.x) && isNaN(this.y) && isNaN(px.x) && isNaN(px.y)));
        }
        return equals;
    },
    add: function(x, y)
    {
        if ((x == null) || (y == null))
        {
            var msg = "You must pass both x and y values to the add function.";
            OpenLayers.Console.error(msg);
            return null;
        }
        return new TISolution.ScreenPoint(this.x + x, this.y + y);
    },
    offset: function(px)
    {
        var newPx = this.clone();
        if (px)
        {
            newPx = this.add(px.x, px.y);
        }
        return newPx;
    },
    CLASS_NAME: "TISolution.ScreenPoint"
});
TISolution.ScreenSize = OpenLayers.Class(OpenLayers.Size, {
    w: 0.0,
    h: 0.0,
    initialize: function(w, h)
    {
        this.w = parseFloat(w);
        this.h = parseFloat(h);
    },
    toString: function()
    {
        return ("w=" + this.w + ",h=" + this.h);
    },
    clone: function()
    {
        return new TISolution.ScreenSize(this.w, this.h);
    },
    equals: function(sz)
    {
        var equals = false;
        if (sz != null)
        {
            equals = ((this.w == sz.w && this.h == sz.h) || (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
        }
        return equals;
    },
    CLASS_NAME: "TISolution.ScreenSize"
});
TISolution.ScreenBounds = OpenLayers.Class(OpenLayers.Bounds, {
    srs: null,
    initialize: function(left, top, right, bottom)
    {
        if (left != null)
        {
            this.left = parseFloat(left);
        }
        if (bottom != null)
        {
            this.bottom = parseFloat(bottom);
        }
        if (right != null)
        {
            this.right = parseFloat(right);
        }
        if (top != null)
        {
            this.top = parseFloat(top);
        }
        this.srs = TISolution.SRS.EPSG27700;
    },
    clone: function()
    {
        return new TISolution.ScreenBounds(this.left, this.top, this.right, this.bottom);
    },
    equals: function(bounds)
    {
        var equals = false;
        if (bounds != null)
        {
            equals = ((this.left == bounds.left) && (this.right == bounds.right) && (this.top == bounds.top) && (this.bottom == bounds.bottom) && (this.srs == bounds.srs));
        }
        return equals;
    },
    toString: function()
    {
        return ("left-top=(" + this.left + "," + this.top + ")" + " right-bottom=(" + this.right + "," + this.bottom + ")");
    },
    toArray: function()
    {
        return [this.left, this.top, this.right, this.bottom];
    },
    getWidth: function()
    {
        return (this.right - this.left);
    },
    getHeight: function()
    {
        return (this.bottom - this.top);
    },
    getSize: function()
    {
        return new TISolution.ScreenSize(this.getWidth(), this.getHeight());
    },
    getCenterPixel: function()
    {
        return new TISolution.ScreenPoint((this.left + this.right) / 2, (this.bottom + this.top) / 2);
    },
    add: function(x, y)
    {
        if ((x == null) || (y == null))
        {
            var msg = "You must pass both x and y values to the add function.";
            OpenLayers.Console.error(msg);
            return null;
        }
        return new TISolution.ScreenBounds(this.left + x, this.top + y, this.right + x, this.bottom + y);
    },
    extend: function(object)
    {
        var bounds = null;
        if (object)
        {
            switch (object.CLASS_NAME)
            {
                case "TISolution.ScreenPoint":
                    bounds = new TISolution.ScreenBounds(object.x, object.y, object.x, object.y);
                    break;
                case "TISolution.ScreenBounds":
                    bounds = object;
                    break;
            }
            if (bounds)
            {
                if ((this.left == null) || (bounds.left < this.left))
                {
                    this.left = bounds.left;
                }
                if ((this.bottom == null) || (bounds.bottom > this.bottom))
                {
                    this.bottom = bounds.bottom;
                }
                if ((this.right == null) || (bounds.right > this.right))
                {
                    this.right = bounds.right;
                }
                if ((this.top == null) || (bounds.top < this.top))
                {
                    this.top = bounds.top;
                }
            }
        }
    },
    containsPixel: function(px, inclusive)
    {
        return this.contains(px.x, px.y, inclusive);
    },
    contains: function(x, y, inclusive)
    {
        if (inclusive == null)
        {
            inclusive = true;
        }
        var contains = false;
        if (inclusive)
        {
            contains = ((x >= this.left) && (x <= this.right) && (y <= this.bottom) && (y >= this.top));
        } else
        {
            contains = ((x > this.left) && (x < this.right) && (y < this.bottom) && (y > this.top));
        }
        return contains;
    },
    intersectsBounds: function(bounds, inclusive)
    {
        if (inclusive == null)
        {
            inclusive = true;
        }
        var inBottom = (bounds.bottom == this.bottom && bounds.top == this.top) ? true : (((bounds.bottom < this.bottom) && (bounds.bottom > this.top)) || ((this.bottom < bounds.bottom) && (this.bottom > bounds.top)));
        var inTop = (bounds.bottom == this.bottom && bounds.top == this.top) ? true : (((bounds.top < this.bottom) && (bounds.top > this.top)) || ((this.top < bounds.bottom) && (this.top > bounds.top)));
        var inRight = (bounds.right == this.right && bounds.left == this.left) ? true : (((bounds.right > this.left) && (bounds.right < this.right)) || ((this.right > bounds.left) && (this.right < bounds.right)));
        var inLeft = (bounds.right == this.right && bounds.left == this.left) ? true : (((bounds.left > this.left) && (bounds.left < this.right)) || ((this.left > bounds.left) && (this.left < bounds.right)));
        return (this.containsBounds(bounds, true, inclusive) || bounds.containsBounds(this, true, inclusive) || ((inTop || inBottom) && (inLeft || inRight)));
    },
    containsBounds: function(bounds, partial, inclusive)
    {
        if (partial == null)
        {
            partial = false;
        }
        if (inclusive == null)
        {
            inclusive = true;
        }
        var inLeft;
        var inTop;
        var inRight;
        var inBottom;
        if (inclusive)
        {
            inLeft = (bounds.left >= this.left) && (bounds.left <= this.right);
            inTop = (bounds.top <= this.bottom) && (bounds.top >= this.top);
            inRight = (bounds.right >= this.left) && (bounds.right <= this.right);
            inBottom = (bounds.bottom <= this.bottom) && (bounds.bottom >= this.top);
        } else
        {
            inLeft = (bounds.left > this.left) && (bounds.left < this.right);
            inTop = (bounds.top < this.bottom) && (bounds.top > this.top);
            inRight = (bounds.right > this.left) && (bounds.right < this.right);
            inBottom = (bounds.bottom < this.bottom) && (bounds.bottom > this.top);
        }
        return (partial) ? (inTop || inBottom) && (inLeft || inRight) : (inTop && inLeft && inBottom && inRight);
    },
    determineQuadrant: function(px)
    {
        var quadrant = "";
        var center = this.getCenterPixel();
        quadrant += (px.y > center.y) ? "b" : "t";
        quadrant += (px.x < center.x) ? "l" : "r";
        return quadrant;
    },
    CLASS_NAME: "TISolution.ScreenBounds"
});
TISolution.ScreenBounds.fromString = function(str)
{
    var bounds = str.split(",");
    return TISolution.ScreenBounds.fromArray(bounds);
};
TISolution.ScreenBounds.fromArray = function(bbox)
{
    return new TISolution.ScreenBounds(parseFloat(bbox[0]), parseFloat(bbox[1]), parseFloat(bbox[2]), parseFloat(bbox[3]));
};
TISolution.ScreenBounds.fromSize = function(size)
{
    return new TISolution.ScreenBounds(0, 0, size.w, size.h);
};
TISolution.ScreenBounds.oppositeQuadrant = function(quadrant)
{
    var opp = "";
    opp += (quadrant.charAt(0) == 't') ? 'b' : 't';
    opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l';
    return opp;
};
//TISolution.GridProjection = OpenLayers.Class({
//    initialize: function()
//    {
//        this.DEG_TO_RAD = Math.PI / 180.0;
//        this.a = 6378137.0;
//        this.b = 6356752.3141;
//        this.f = 1.0 - this.b / this.a;
//        this.e2 = 1.0 - (this.b * this.b) / (this.a * this.a);
//        this.lat0 = 49.0 * this.DEG_TO_RAD;
//        this.lon0 = -2.0 * this.DEG_TO_RAD;
//        this.falseE = 400000.0;
//        this.falseN = -100000.0;
//        this.scl = 0.9996012717;
//        this.ety = (this.a - this.b) / (this.a + this.b);
//        this.aS = this.a * this.scl;
//        this.bS = this.b * this.scl;
//        this.low_res_east_shift = new Array(3);
//        var i;
//        for (i = 0; i < 3; i++)
//        {
//            this.low_res_east_shift[i] = new Array(5);
//        }
//        this.low_res_north_shift = new Array(3);
//        for (i = 0; i < 3; i++)
//        {
//            this.low_res_north_shift[i] = new Array(5);
//        }
//        this.init_low_res_data();
//    },
//    init_low_res_data: function()
//    {
//        this.low_res_east_shift[0][0] = 92;
//        this.low_res_east_shift[0][1] = 89;
//        this.low_res_east_shift[0][2] = 85;
//        this.low_res_east_shift[0][3] = 93;
//        this.low_res_east_shift[0][4] = 99;
//        this.low_res_east_shift[1][0] = 96;
//        this.low_res_east_shift[1][1] = 96;
//        this.low_res_east_shift[1][2] = 97;
//        this.low_res_east_shift[1][3] = 99;
//        this.low_res_east_shift[1][4] = 104;
//        this.low_res_east_shift[2][0] = 102;
//        this.low_res_east_shift[2][1] = 105;
//        this.low_res_east_shift[2][2] = 108;
//        this.low_res_east_shift[2][3] = 106;
//        this.low_res_east_shift[2][4] = 107;
//        this.low_res_north_shift[0][0] = -82;
//        this.low_res_north_shift[0][1] = -75;
//        this.low_res_north_shift[0][2] = -58;
//        this.low_res_north_shift[0][3] = -47;
//        this.low_res_north_shift[0][4] = -44;
//        this.low_res_north_shift[1][0] = -80;
//        this.low_res_north_shift[1][1] = -75;
//        this.low_res_north_shift[1][2] = -62;
//        this.low_res_north_shift[1][3] = -52;
//        this.low_res_north_shift[1][4] = -49;
//        this.low_res_north_shift[2][0] = -82;
//        this.low_res_north_shift[2][1] = -78;
//        this.low_res_north_shift[2][2] = -62;
//        this.low_res_north_shift[2][3] = -54;
//        this.low_res_north_shift[2][4] = -52;
//    },
//    getMapPointFromLonLat: function(pt_LonLat)
//    {
//        var pt_ETRS89 = this.geog2Grid(pt_LonLat);
//        var pt_OSGB36 = this.convert_89_36(pt_ETRS89);
//        return pt_OSGB36;
//    },
//    getLonLatFromMapPoint: function(pt_OSGB36)
//    {
//        var pt_ETRS89 = this.convert_36_89(pt_OSGB36);
//        var pt_LonLat = this.E_N_to_LonLat(pt_ETRS89);
//        return pt_LonLat;
//    },
//    os_arc: function(k3, k4)
//    {
//        var j3 = (((this.ety + 1.0) * this.ety * 5.0 / 4.0 + 1.0) * this.ety + 1.0) * k3;
//        var j4 = ((21.0 * this.ety / 8.0 + 3.0) * this.ety + 3.0) * this.ety * Math.sin(k3) * Math.cos(k4);
//        var j5 = this.ety * (this.ety + this.ety * this.ety) * Math.sin(2.0 * k3) * Math.cos(2.0 * k4) * 15.0 / 8.0;
//        var j6 = this.ety * this.ety * this.ety * Math.sin(3.0 * k3) * Math.cos(3.0 * k4) * 35.0 / 24.0;
//        return (this.bS * (j3 - j4 + j5 - j6));
//    },
//    geog2Grid: function(pt_LonLat)
//    {
//        var gridPoint = new OpenLayers.LonLat();
//        var lat_rad = pt_LonLat.lat * this.DEG_TO_RAD;
//        var lon_rad = pt_LonLat.lon * this.DEG_TO_RAD;
//        var k3 = lat_rad - this.lat0;
//        var k4 = lat_rad + this.lat0;
//        var tan_k = Math.tan(lat_rad);
//        var tan_k_2 = tan_k * tan_k;
//        var sin_k = Math.sin(lat_rad);
//        var cos_k = Math.cos(lat_rad);
//        var cos_k_3 = cos_k * cos_k * cos_k;
//        var cos_k_5 = cos_k * cos_k * cos_k_3;
//        var m = this.os_arc(k3, k4);
//        var v = this.aS / Math.sqrt(1.0 - this.e2 * sin_k * sin_k);
//        var v_3 = v * v * v;
//        var v_5 = v_3 * v * v;
//        var v_7 = v_5 * v * v;
//        var r = v * (1.0 - this.e2) / (1.0 - this.e2 * sin_k * sin_k);
//        var h2 = v / r - 1.0;
//        var p = lon_rad - this.lon0;
//        var j3 = m + this.falseN;
//        var j4 = v * sin_k * cos_k / 2.0;
//        var j5 = v * sin_k * cos_k_3 * (5.0 - tan_k_2 + 9.0 * h2) / 24.0;
//        var j6 = v * sin_k * cos_k_5 * ((tan_k_2 - 58.0) * tan_k_2 + 61.0) / 720.0;
//        gridPoint.lat = ((j6 * p * p + j5) * p * p + j4) * p * p + j3;
//        var j7 = v * cos_k;
//        var j8 = v * cos_k_3 * (v / r - tan_k_2) / 6.0;
//        var j9 = v * cos_k_5 / 120.0;
//        j9 = j9 * ((tan_k_2 - 58.0 * h2 - 18.0) * tan_k_2 + 5.0 + 14.0 * h2);
//        gridPoint.lon = ((j9 * p * p + j8) * p * p + j7) * p + this.falseE;
//        return gridPoint;
//    },
//    convert_89_36: function(pt_ETRS89)
//    {
//        var e = new Array(4);
//        var n = new Array(4);
//        var dxs = new Array(4);
//        var dys = new Array(4);
//        var spacing = 350000.0;
//        var east_index = Math.floor(pt_ETRS89.lon / spacing);
//        var north_index = Math.floor(pt_ETRS89.lat / spacing);
//        e[0] = e[3] = east_index;
//        e[1] = e[2] = east_index + 1;
//        n[0] = n[1] = north_index;
//        n[2] = n[3] = north_index + 1;
//        var i;
//        for (i = 0; i < 4; i++)
//        {
//            if (e[i] < 0) e[i] = 0;
//            if (e[i] > 2) e[i] = 2;
//            if (n[i] < 0) n[i] = 0;
//            if (n[i] > 4) n[i] = 4;
//            dxs[i] = this.low_res_east_shift[e[i]][n[i]];
//            dys[i] = this.low_res_north_shift[e[i]][n[i]];
//        }
//        var shiftX = this.bilinear(dxs, east_index * spacing, east_index * spacing + spacing, north_index * spacing, north_index * spacing + spacing, pt_ETRS89.lon, pt_ETRS89.lat);
//        var shiftY = this.bilinear(dys, east_index * spacing, east_index * spacing + spacing, north_index * spacing, north_index * spacing + spacing, pt_ETRS89.lon, pt_ETRS89.lat);
//        var output = new TISolution.MapPoint(pt_ETRS89.lon + shiftX, pt_ETRS89.lat + shiftY);
//        return output;
//    },
//    E_N_to_LonLat: function(pt_ETRS89)
//    {
//        var RadPHI0 = this.lat0;
//        var RadLAM0 = this.lon0;
//        var af0 = this.a * this.scl;
//        var bf0 = this.b * this.scl;
//        var e2 = ((af0 * af0) - (bf0 * bf0)) / (af0 * af0);
//        var n = (af0 - bf0) / (af0 + bf0);
//        var Et = pt_ETRS89.lon - this.falseE;
//        var PHId = this.initialLat(pt_ETRS89.lat, this.falseN, af0, RadPHI0, n, bf0);
//        var sinPHId = Math.sin(PHId);
//        var sinPHId2 = sinPHId * sinPHId;
//        var nu = af0 / (Math.sqrt(1.0 - (e2 * sinPHId2)));
//        var rho = (nu * (1.0 - e2)) / (1.0 - (e2 * sinPHId2));
//        var eta2 = (nu / rho) - 1.0;
//        var tanPHId = Math.tan(PHId);
//        var tanPHId2 = tanPHId * tanPHId;
//        var tanPHId4 = tanPHId2 * tanPHId2;
//        var tanPHId6 = tanPHId4 * tanPHId2;
//        var VII = (tanPHId) / (2 * rho * nu);
//        var VIII = (tanPHId / (24 * rho * (nu * nu * nu))) * (5 + (3 * tanPHId2) + eta2 - (9 * eta2 * tanPHId2));
//        var IX = (tanPHId / (720 * rho * (nu * nu * nu * nu * nu))) * (61 + (90 * tanPHId2) + (45 * tanPHId4));
//        var E_N_to_Lat = (180 / Math.PI) * (PHId - ((Et * Et) * VII) + ((Et * Et * Et * Et) * VIII) - ((Et * Et * Et * Et * Et * Et) * IX));
//        var cosPHId = Math.cos(PHId);
//        var cosPHId_1 = 1.0 / cosPHId;
//        var X = cosPHId_1 / nu;
//        var XI = (cosPHId_1 / (6 * (nu * nu * nu))) * ((nu / rho) + (2 * tanPHId2));
//        var XII = (cosPHId_1 / (120 * (nu * nu * nu * nu * nu))) * (5 + (28 * tanPHId2 + (24 * tanPHId4)));
//        var XIIA = (cosPHId_1 / (5040 * (nu * nu * nu * nu * nu * nu * nu))) * (61 + (662 * tanPHId2 + (1320 * tanPHId4 + (720 * tanPHId6))));
//        var E_N_to_Lng = (180 / Math.PI) * (RadLAM0 + (Et * X) - ((Et * Et * Et) * XI) + ((Et * Et * Et * Et * Et) * XII) - ((Et * Et * Et * Et * Et * Et * Et) * XIIA));
//        var pt_LonLat = new OpenLayers.LonLat(E_N_to_Lng, E_N_to_Lat);
//        return pt_LonLat;
//    },
//    initialLat: function(North, n0, afo, PHI0, n, bfo)
//    {
//        var PHI1 = ((North - n0) / afo) + PHI0;
//        var M = this.marc(bfo, n, PHI0, PHI1);
//        var PHI2 = ((North - n0 - M) / afo) + PHI1;
//        while (Math.abs(North - n0 - M) > 0.000001)
//        {
//            PHI2 = ((North - n0 - M) / afo) + PHI1;
//            M = this.marc(bfo, n, PHI0, PHI2);
//            PHI1 = PHI2;
//        }
//        return PHI2;
//    },
//    marc: function(bf0, n, PHI0, PHI)
//    {
//        var marc = bf0 * (((1.0 + n + ((5.0 / 4.0) * (n * n)) + ((5.0 / 4.0) * (n * n * n))) * (PHI - PHI0)) - (((3.0 * n) + (3.0 * (n * n)) + ((21.0 / 8.0) * (n * n * n))) * Math.sin(PHI - PHI0) * Math.cos(PHI + PHI0)) + ((((15.0 / 8.0) * (n * n)) + ((15.0 / 8.0) * (n * n * n))) * Math.sin(2.0 * (PHI - PHI0)) * Math.cos(2.0 * (PHI + PHI0))) - (((35.0 / 24.0) * (n * n * n)) * Math.sin(3.0 * (PHI - PHI0)) * Math.cos(3.0 * (PHI + PHI0))));
//        return marc;
//    },
//    convert_36_89: function(pt_OSGB36)
//    {
//        var dxs = new Array(4);
//        var dys = new Array(4);
//        var v1x;
//        var v1y;
//        var v2x;
//        var v2y;
//        var local_pt = new OpenLayers.LonLat();
//        var i;
//        var out_of_range = false;
//        var a;
//        var b;
//        var AA;
//        var BB;
//        var CC;
//        var old_a;
//        var f_x;
//        var f_dx;
//        var s;
//        var dn;
//        var de;
//        var t1;
//        var t2;
//        var t3;
//        var t5;
//        var l = new Array(7);
//        var spacing = 350000.0;
//        var gride = Math.floor(pt_OSGB36.lon / spacing);
//        var gridn = Math.floor(pt_OSGB36.lat / spacing);
//        var indexX;
//        var indexY;
//        i = 0;
//        while (i != 4)
//        {
//            for (i = 0; i < 4; i++)
//            {
//                indexX = gride + Math.floor(i / 2);
//                indexY = gridn + Math.floor(((i + 1) % 4) / 2);
//                if (indexX < 0) indexX = 0;
//                if (indexX > 2) indexX = 2;
//                if (indexY < 0) indexY = 0;
//                if (indexY > 4) indexY = 4;
//                if (indexX >= 0 && indexX <= 2 && indexY >= 0 && indexY <= 4)
//                {
//                    dxs[i] = this.low_res_east_shift[indexX][indexY];
//                    dys[i] = this.low_res_north_shift[indexX][indexY];
//                } else
//                {
//                    OpenLayers.Console.log("index out of range: indexX: " + indexX + " indexY: " + indexY);
//                }
//            }
//            for (i = 0; i < 4; i++)
//            {
//                indexX = gride + Math.floor(i / 2);
//                indexY = gridn + Math.floor(((i + 1) % 4) / 2);
//                v1x = dxs[i] + spacing * indexX - pt_OSGB36.lon;
//                v1y = dys[i] + spacing * indexY - pt_OSGB36.lat;
//                indexX = gride + Math.floor(((i + 1) % 4) / 2);
//                indexY = gridn + 1 - Math.floor(i / 2);
//                v2x = dxs[(i + 1) % 4] + spacing * indexX - pt_OSGB36.lon;
//                v2y = dys[(i + 1) % 4] + spacing * indexY - pt_OSGB36.lat;
//                if ((v1x * v2y - v2x * v1y) > 0.0) break;
//            }
//            switch (i)
//            {
//                case 0:
//                    gride--;
//                    break;
//                case 1:
//                    gridn++;
//                    break;
//                case 2:
//                    gride++;
//                    break;
//                case 3:
//                    gridn--;
//                    break;
//                case 4:
//                    break;
//            }
//        }
//        local_pt.lon = pt_OSGB36.lon - gride * spacing;
//        local_pt.lat = pt_OSGB36.lat - gridn * spacing;
//        l[1] = dxs[0] - dxs[3];
//        l[2] = dxs[1] - dxs[2];
//        l[3] = dys[0] - dys[3];
//        l[4] = dys[1] - dys[2];
//        l[5] = dys[0] - dys[1];
//        l[6] = dxs[0] - dxs[1];
//        s = spacing;
//        dn = local_pt.lat - dys[0];
//        de = local_pt.lon - dxs[0];
//        t1 = s - l[1];
//        t2 = l[3] - l[4];
//        t3 = l[1] - l[2];
//        t5 = s - l[5];
//        AA = (t1 * t2 + l[3] * t3) / s;
//        BB = t3 * dn - l[3] * l[6] + t1 * t5 - t2 * de;
//        CC = -s * dn * l[6] - s * de * (s - l[5]);
//        if (AA < BB * 0.0000000001)
//        {
//            if (BB == 0)
//            {
//                alert("Indeterminable equations");
//                return null;
//            }
//            a = -CC / BB;
//        } else
//        {
//            a = (-BB + Math.sqrt(BB * BB - 4.0 * AA * CC)) / (2.0 * AA);
//        }
//        for (i = 0; i < 10; i++)
//        {
//            old_a = a;
//            f_x = AA * old_a * old_a + BB * old_a + CC;
//            f_dx = 2.0 * AA * old_a + BB;
//            if (f_dx == 0.0) break;
//            a = old_a - (f_x / f_dx);
//            if (Math.abs(old_a - a) < 0.00001) break;
//        }
//        b = ((s * s) * local_pt.lat - (s * (s * dys[0] - a * l[3]))) / ((s * s) - (s * l[5] - a * t2));
//        var pt_ETRS89 = new OpenLayers.LonLat(a + (gride * spacing), b + (gridn * spacing));
//        return pt_ETRS89;
//    },
//    bilinear: function(y, x1l, x1u, x2l, x2u, x1, x2)
//    {
//        var d1 = x1u - x1l;
//        var d2 = x2u - x2l;
//        var t = (x1 - x1l) / d1;
//        var u = (x2 - x2l) / d2;
//        return (1.0 - t) * (1.0 - u) * y[0] + t * (1.0 - u) * y[1] + t * u * y[2] + (1.0 - t) * u * y[3];
//    },
//    CLASS_NAME: "TISolution.GridProjection"
//});
TISolution.InfoWindow = OpenLayers.Class(OpenLayers.Popup.Anchored, {
    initialize: function(id, lonlat, size, contentHTML, anchor, closeBox)
    {
        closeBox = false;
        OpenLayers.Popup.Anchored.prototype.initialize.apply(this, arguments);
        this.setAnchor(anchor);
        this.contentDiv.style.zIndex = OpenLayers.Map.prototype.Z_INDEX_BASE.Popup + 2;
        this.imgLocation = OpenLayers.Util.getImagesLocation() + "OS/control/popup/";
        this.DEFAULT_INFO_WINDOW_SIZE = new OpenLayers.Size(250, 200);
        this.margin = 10;
        this.minX = 70;
        this.minY = 60;
        this.FADE_SPEED = 400;
        this.setSize(size);
        this.size = new OpenLayers.Size(this.minX, this.minY);
        this.tlPx = new OpenLayers.Pixel();
        this.tPx = new OpenLayers.Pixel();
        this.trPx = new OpenLayers.Pixel();
        this.lPx = new OpenLayers.Pixel();
        this.rPx = new OpenLayers.Pixel();
        this.blPx = new OpenLayers.Pixel();
        this.bPx = new OpenLayers.Pixel();
        this.brPx = new OpenLayers.Pixel();
        this.bgPx = new OpenLayers.Pixel();
        this.slPx = new OpenLayers.Pixel();
        this.sPx = new OpenLayers.Pixel();
        this.srPx = new OpenLayers.Pixel();
        this.tlSz = new OpenLayers.Size();
        this.tSz = new OpenLayers.Size();
        this.trSz = new OpenLayers.Size();
        this.lSz = new OpenLayers.Size();
        this.rSz = new OpenLayers.Size();
        this.blSz = new OpenLayers.Size();
        this.bSz = new OpenLayers.Size();
        this.brSz = new OpenLayers.Size();
        this.bgSz = new OpenLayers.Size();
        this.slSz = new OpenLayers.Size();
        this.sSz = new OpenLayers.Size();
        this.srSz = new OpenLayers.Size();
        this.calcBackgroundBounds();
        this.closePx = new OpenLayers.Pixel();
        this.closeSz = new OpenLayers.Size();
        this.calcCloseBounds();
    },
    setSize: function(size)
    {
        if (size != undefined)
        {
            this.fullSize = size.clone();
        } else
        {
            this.fullSize = this.DEFAULT_INFO_WINDOW_SIZE;
        }
    },
    draw: function(px)
    {
        if (px == null)
        {
            if ((this.lonlat != null) && (this.map != null))
            {
                px = this.map.getLayerPxFromLonLat(this.lonlat);
            }
        }
        this.moveTo(px);
        this.createBackground();
        this.createCloseButton();
        return this.div;
    },
    createBackground: function()
    {
        this.slDiv = OpenLayers.Util.createAlphaImageDiv('slDiv', this.slPx, this.slSz, this.imgLocation + "sl.png", null, null, 'size', this.opacity, false);
        this.groupDiv.appendChild(this.slDiv);
        this.sDiv = OpenLayers.Util.createAlphaImageDiv('sDiv', this.sPx, this.sSz, this.imgLocation + "s.png", null, null, 'scale', this.opacity, false);
        this.groupDiv.appendChild(this.sDiv);
        this.srDiv = OpenLayers.Util.createAlphaImageDiv('srDiv', this.srPx, this.srSz, this.imgLocation + "sr.png", null, null, 'size', this.opacity, false);
        this.groupDiv.appendChild(this.srDiv);
        this.tlDiv = OpenLayers.Util.createAlphaImageDiv('tlDiv', this.tlPx, this.tlSz, this.imgLocation + "tl.png", null, null, 'scale', this.opacity, false);
        this.groupDiv.appendChild(this.tlDiv);
        this.tDiv = OpenLayers.Util.createAlphaImageDiv('tDiv', this.tPx, this.tSz, this.imgLocation + "t.png", null, null, 'scale', this.opacity, false);
        this.groupDiv.appendChild(this.tDiv);
        this.trDiv = OpenLayers.Util.createAlphaImageDiv('trDiv', this.trPx, this.trSz, this.imgLocation + "tr.png", null, null, 'size', this.opacity, false);
        this.groupDiv.appendChild(this.trDiv);
        this.lDiv = OpenLayers.Util.createAlphaImageDiv('lDiv', this.lPx, this.lSz, this.imgLocation + "l.png", null, null, 'scale', this.opacity, false);
        this.groupDiv.appendChild(this.lDiv);
        this.rDiv = OpenLayers.Util.createAlphaImageDiv('rDiv', this.rPx, this.rSz, this.imgLocation + "r.png", null, null, 'scale', this.opacity, false);
        this.groupDiv.appendChild(this.rDiv);
        this.blDiv = OpenLayers.Util.createAlphaImageDiv('blDiv', this.blPx, this.blSz, this.imgLocation + "bl.png", null, null, 'size', this.opacity, false);
        this.groupDiv.appendChild(this.blDiv);
        this.bDiv = OpenLayers.Util.createAlphaImageDiv('bDiv', this.bPx, this.bSz, this.imgLocation + "b.png", null, null, 'scale', this.opacity, false);
        this.groupDiv.appendChild(this.bDiv);
        this.brDiv = OpenLayers.Util.createAlphaImageDiv('brDiv', this.brPx, this.brSz, this.imgLocation + "br.png", null, null, 'size', this.opacity, false);
        this.groupDiv.appendChild(this.brDiv);
        this.bgDiv = OpenLayers.Util.createDiv('bgDiv', this.bgPx, this.bgSz, null, null, null, 'hidden', this.opacity);
        this.bgDiv.style.backgroundColor = "white";
        this.groupDiv.appendChild(this.bgDiv);
    },
    destroy: function()
    {
        this.tlDiv = null;
        this.tDiv = null;
        this.trDiv = null;
        this.lDiv = null;
        this.rDiv = null;
        this.blDiv = null;
        this.bDiv = null;
        this.brDiv = null;
        this.bgDiv = null;
        this.slDiv = null;
        this.sDiv = null;
        this.srDiv = null;
        OpenLayers.Popup.prototype.destroy.apply(this, arguments);
    },
    createCloseButton: function()
    {
        this.closeDiv = OpenLayers.Util.createAlphaImageDiv('closeDiv', this.closePx, this.closeSz, this.imgLocation + "close.png", null, null, 'size', this.opacity, false);
        this.closeDiv.style.zIndex = OpenLayers.Map.prototype.Z_INDEX_BASE.Popup + 3;
        this.groupDiv.appendChild(this.closeDiv);
        OpenLayers.Event.observe(this.closeDiv, "click", OpenLayers.Function.bindAsEventListener(this.closeInfoWindow, this));
    },
    closeInfoWindow: function(e)
    {
        this.hide();
        OpenLayers.Event.stop(e);
    },
    setPosition: function(lonlat)
    {
        this.lonlat = lonlat;
        this.updatePosition();
    },
    setAnchor: function(anchor)
    {
        this.anchor = anchor || {
            size: new OpenLayers.Size(0, 0),
            offset: new OpenLayers.Pixel(0, 0),
            infoWindowAnchor: new OpenLayers.Pixel(0, 0)
        };
    },
    moveTo: function(px)
    {
        if ((px != null) && (this.div != null))
        {
            var px = this.calculateNewPx(px);
            this.div.style.left = px.x + "px";
            this.div.style.top = px.y + "px";
        }
    },
    hide: function()
    {
        var endFunc = OpenLayers.Function.bind(this._hide, this);
        var anim = new Animator({
            onComplete: endFunc,
            duration: this.FADE_SPEED
        });
        this.deltaX = (this.fullSize.w - this.minX);
        this.deltaY = (this.fullSize.h - this.minY);
        var func = OpenLayers.Function.bind(this._appear, this);
        anim.addSubject(func);
        anim.reverse();
    },
    _hide: function()
    {
        if (!OpenLayers.Util.alphaHack()) OpenLayers.Util.setOpacity(this.groupDiv, 0);
        OpenLayers.Element.hide(this.div);
    },
    show: function()
    {
        if (!OpenLayers.Util.alphaHack()) OpenLayers.Util.setOpacity(this.groupDiv, 0);
        this._show();
        var endFunc = OpenLayers.Function.bind(this._endShow, this);
        var anim = new Animator({
            onComplete: endFunc,
            duration: this.FADE_SPEED
        });
        this.deltaX = (this.fullSize.w - this.minX);
        this.deltaY = (this.fullSize.h - this.minY);
        var func = OpenLayers.Function.bind(this._appear, this);
        anim.addSubject(func);
        anim.play();
    },
    _show: function()
    {
        OpenLayers.Element.show(this.div);
    },
    _endShow: function()
    {
        this.groupDiv.style.opacity = "";
        this.groupDiv.style.filter = "";
        this.bgDiv.style.opacity = "";
        this.bgDiv.style.filter = "";
    },
    _appear: function(value)
    {
        var w = parseInt(this.minX + this.deltaX * value);
        var h = parseInt(this.minY + this.deltaY * value);
        var size = new OpenLayers.Size(w, h);
        this._changeSize(size);
        if (!OpenLayers.Util.alphaHack()) OpenLayers.Util.setOpacity(this.groupDiv, value);
    },
    calcBackgroundBounds: function()
    {
        this._calcTLBounds();
        this._calcTRBounds();
        this._calcTBounds();
        this._calcBRBounds();
        this._calcBLBounds();
        this._calcBBounds();
        this._calcBGBounds();
        this._calcLBounds();
        this._calcRBounds();
        this._calcSLBounds();
        this._calcSRBounds();
        this._calcSBounds();
    },
    _calcTLBounds: function()
    {
        this.tlSz.w = 15;
        this.tlSz.h = 15;
        this.tlPx.x = 0;
        this.tlPx.y = 0;
    },
    _calcTRBounds: function()
    {
        this.trSz.w = 37;
        this.trSz.h = 15;
        this.trPx.x = this.size.w - this.trSz.w;
        this.trPx.y = 0;
    },
    _calcTBounds: function()
    {
        this.tPx.x = this.tlSz.w;
        this.tPx.y = 0;
        this.tSz.w = this.size.w - this.tlSz.w - this.trSz.w;
        this.tSz.h = 15;
    },
    _calcBRBounds: function()
    {
        this.brSz.w = 37;
        this.brSz.h = 44;
        this.brPx.x = this.size.w - this.brSz.w;
        this.brPx.y = this.size.h - this.brSz.h;
    },
    _calcBLBounds: function()
    {
        this.blSz.w = 15;
        this.blSz.h = 15;
        this.blPx.x = 0;
        this.blPx.y = this.size.h - this.brSz.h;
    },
    _calcBBounds: function()
    {
        this.bPx.x = this.blSz.w;
        this.bPx.y = this.size.h - this.brSz.h;
        this.bSz.w = this.size.w - this.blSz.w - this.brSz.w;
        this.bSz.h = 15;
    },
    _calcBGBounds: function()
    {
        this.bgSz.w = this.bSz.w;
        this.bgSz.h = this.size.h - this.trSz.h - this.brSz.h;
        this.bgPx.x = this.tlSz.w;
        this.bgPx.y = this.tlSz.h;
    },
    _calcLBounds: function()
    {
        this.lPx.x = 0;
        this.lPx.y = this.tlSz.h;
        this.lSz.w = 15;
        this.lSz.h = this.bgSz.h;
    },
    _calcRBounds: function()
    {
        this.rPx.x = this.size.w - this.trSz.w;
        this.rPx.y = this.trSz.h;
        this.rSz.w = 37;
        this.rSz.h = this.bgSz.h;
    },
    _calcSRBounds: function()
    {
        this.srSz.w = 60;
        this.srSz.h = 101;
        this.srPx.x = this.size.w - 30;
        this.srPx.y = this.size.h - 101;
    },
    _calcSLBounds: function()
    {
        this.slSz.w = 31;
        this.slSz.h = 101;
        this.slPx.x = 0;
        this.slPx.y = this.size.h - 101;
    },
    _calcSBounds: function()
    {
        this.sPx.x = this.slSz.w;
        this.sPx.y = this.size.h - 101;
        this.sSz.w = this.size.w - this.slSz.w - this.srSz.w + 30;
        this.sSz.h = 101;
    },
    calcCloseBounds: function()
    {
        this.closePx.x = this.size.w - 12 - this.margin;
        this.closePx.y = this.margin;
        this.closeSz.w = 12;
        this.closeSz.h = 12;
    },
    _changeSize: function(size)
    {
        this.size = size.clone();
        var shadowSize = new OpenLayers.Size(size.w + 50, size.h);
        this.calcBackgroundBounds();
        OpenLayers.Util.modifyDOMElement(this.contentDiv, null, this.bgPx, this.bgSz);
        OpenLayers.Util.modifyDOMElement(this.groupDiv, null, null, shadowSize);
        OpenLayers.Util.modifyDOMElement(this.div, null, null, shadowSize);
        OpenLayers.Util.modifyAlphaImageDiv(this.tlDiv, null, this.tlPx, this.tlSz);
        OpenLayers.Util.modifyAlphaImageDiv(this.tDiv, null, this.tPx, this.tSz);
        OpenLayers.Util.modifyAlphaImageDiv(this.trDiv, null, this.trPx, this.trSz);
        OpenLayers.Util.modifyAlphaImageDiv(this.lDiv, null, this.lPx, this.lSz);
        OpenLayers.Util.modifyAlphaImageDiv(this.rDiv, null, this.rPx, this.rSz);
        OpenLayers.Util.modifyAlphaImageDiv(this.blDiv, null, this.blPx, this.blSz);
        OpenLayers.Util.modifyAlphaImageDiv(this.bDiv, null, this.bPx, this.bSz);
        OpenLayers.Util.modifyAlphaImageDiv(this.brDiv, null, this.brPx, this.brSz);
        OpenLayers.Util.modifyDOMElement(this.bgDiv, null, this.bgPx, this.bgSz);
        OpenLayers.Util.modifyAlphaImageDiv(this.slDiv, null, this.slPx, this.slSz);
        OpenLayers.Util.modifyAlphaImageDiv(this.sDiv, null, this.sPx, this.sSz);
        OpenLayers.Util.modifyAlphaImageDiv(this.srDiv, null, this.srPx, this.srSz);
        this.calcCloseBounds();
        OpenLayers.Util.modifyAlphaImageDiv(this.closeDiv, null, this.closePx, this.closeSz);
        this.updatePosition();
    },
    calculateNewPx: function(px)
    {
        var newPx = px.clone();
        newPx.x += this.anchor.offset.x;
        newPx.y += this.anchor.offset.y;
        newPx.x += this.anchor.infoWindowAnchor.x;
        newPx.y += this.anchor.infoWindowAnchor.y;
        newPx.x -= this.size.w;
        newPx.y -= this.size.h;
        newPx.x += 37 - 2;
        newPx.y += 0;
        return newPx;
    },
    CLASS_NAME: "TISolution.InfoWindow"
});
TISolution.Control = {};
TISolution.Control.LargeMapControl = OpenLayers.Class(OpenLayers.Control.PanZoomBar, {
    slideFactor: 100,
    sliderDiv: null,
    nsz: new OpenLayers.Size(29, 21),
    esz: new OpenLayers.Size(20, 27),
    ssz: new OpenLayers.Size(29, 20),
    wsz: new OpenLayers.Size(20, 27),
    zisz: new OpenLayers.Size(35, 34),
    zosz: new OpenLayers.Size(35, 34),
    Z_X: 17,
    Z_Y: 74,
    drawZoomBar: true,
    ZB_X: 6,
    ZB_Y: 30,
    SL_W: 44,
    SL_H: 17,
    zoomStopWidth: 22,
    zoomStopHeight: 11,
    zoomBarHeight: null,
    zoOffsetY: null,
    controlPosition: null,
    includeXY: true,
    initialize: function()
    {
        OpenLayers.Control.PanZoomBar.prototype.initialize.apply(this, arguments);
    },
    draw: function(px)
    {
        this.controlPosition = px;
        if (this.drawZoomBar)
        {
            this.zoomBarHeight = this.zoomStopHeight * (this.map.getNumZoomLevels() + 1);
            this.zoOffsetY = 0;
        } else
        {
            this.zoomBarHeight = 0;
            this.zoOffsetY = 10;
        }
        var npx = new OpenLayers.Pixel(this.esz.w, 0);
        var epx = new OpenLayers.Pixel(this.esz.w + this.nsz.w, this.nsz.h);
        var spx = new OpenLayers.Pixel(this.esz.w, this.nsz.h + this.esz.h);
        var wpx = new OpenLayers.Pixel(0, this.nsz.h);
        var pbsz = new OpenLayers.Size(this.nsz.w, this.wsz.h);
        var pbpx = new OpenLayers.Pixel(this.esz.w, this.nsz.h);
        var zipx = new OpenLayers.Pixel(this.Z_X, this.Z_Y);
        var zopx = new OpenLayers.Pixel(this.Z_X, this.Z_Y + this.zisz.h + this.zoomBarHeight - this.zoomStopHeight + this.zoOffsetY);
        var pos = this._calculateOffset();
        OpenLayers.Control.prototype.draw.call(this, pos);
        this.buttons = [];
        var imgLocation = OpenLayers.Util.getImagesLocation() + "OS/control/pan-o.png";
        var panbkg = OpenLayers.Util.createAlphaImageDiv("OS_Control_Pan_bkg", pbpx, pbsz, imgLocation, "absolute");
        this.div.appendChild(panbkg);
        this._addButton("panup", "OS/control/pan-n.png", npx, this.nsz);
        this._addButton("panright", "OS/control/pan-e.png", epx, this.esz);
        this._addButton("pandown", "OS/control/pan-s.png", spx, this.ssz);
        this._addButton("panleft", "OS/control/pan-w.png", wpx, this.wsz);
        if (this.drawZoomBar)
        {
            this._addButton("zoomin", "OS/control/zoom-in.png", zipx, this.zisz);
            var zbpx = new OpenLayers.Pixel(this.Z_X + this.ZB_X, this.Z_Y + this.ZB_Y);
            this._addZoomBar(zbpx);
            this._addButton("zoomout", "OS/control/zoom-out.png", zopx, this.zosz);
        } else
        {
            this._addButton("zoomin", "OS/control/zoom-in-small.png", zipx, this.zisz);
            this._addButton("zoomout", "OS/control/zoom-out-small.png", zopx, this.zosz);
        }
        return this.div;
    },
    _calculateOffset: function()
    {
        var pos;
        var px = this.controlPosition;
        if (px)
        {
            if (px instanceof TISolution.Control.ControlPosition)
            {
                var offsetx = 0;
                var offsety = 0;
                if (px.offset)
                {
                    offsetx = px.offset.w;
                    offsety = px.offset.h;
                }
                switch (px.anchor)
                {
                    case TISolution.Control.ControlAnchor.ANCHOR_TOP_LEFT:
                        pos = new OpenLayers.Pixel(offsetx, offsety);
                        break;
                    case TISolution.Control.ControlAnchor.ANCHOR_TOP_RIGHT:
                        pos = new OpenLayers.Pixel(this.map.size.w - this.wsz.w - this.nsz.w - this.esz.w - offsetx, offsety);
                        break;
                    case TISolution.Control.ControlAnchor.ANCHOR_BOTTOM_LEFT:
                        pos = new OpenLayers.Pixel(offsetx, this.map.size.h - this.Z_Y - this.zosz.h - this.zoomBarHeight - this.zisz.h - offsety);
                        break;
                    case TISolution.Control.ControlAnchor.ANCHOR_BOTTOM_RIGHT:
                        pos = new OpenLayers.Pixel(this.map.size.w - this.wsz.w - this.nsz.w - this.esz.w - offsetx, this.map.size.h - this.Z_Y - this.zosz.h - this.zoomBarHeight - this.zisz.h - offsety);
                        break;
                    default:
                        pos = new OpenLayers.Pixel(offsetx, offsety);
                        break;
                }
            } else if (this.position)
            {
                pos = px.clone();
            }
        } else
        {
            if (this.position)
            {
                pos = this.position.clone();
            }
        }
        return pos;
    },
    _addZoomBar: function(centered)
    {
        var imgLocation = OpenLayers.Util.getImagesLocation();
        var id = "OpenLayers_Control_PanZoomBar_Slider" + this.map.id;
        var zoomsToEnd = this.map.getNumZoomLevels() - this.map.getZoom();
        var slider = OpenLayers.Util.createAlphaImageDiv(id,
                       centered.add(-11, zoomsToEnd * this.zoomStopHeight), 
                       new OpenLayers.Size(this.SL_W, this.SL_H), imgLocation + "OS/control/zoom-pointer.png", "absolute");
//        var slider = OpenLayers.Util.createAlphaImageDiv(id,
//                       centered.add(-1, zoomsToEnd * this.zoomStopHeight),
//                       new OpenLayers.Size(20, 9),
//                       imgLocation + "slider.png",
//                       "absolute");
        this.slider = slider;
        this.sliderEvents = new OpenLayers.Events(this, slider, null, true);
        this.sliderEvents.register("mousedown", this, this.zoomBarDown);
        this.sliderEvents.register("mousemove", this, this.zoomBarDrag);
        this.sliderEvents.register("mouseup", this, this.zoomBarUp);
        this.sliderEvents.register("dblclick", this, this.doubleClick);
        this.sliderEvents.register("click", this, this.doubleClick);
        sz = new OpenLayers.Size();
        sz.h = this.zoomStopHeight * (this.map.getNumZoomLevels() + 1);
        sz.w = this.zoomStopWidth;
        var div = null
        if (OpenLayers.Util.alphaHack())
        {
            var id = "OpenLayers_Control_PanZoomBar" + this.map.id;
            div = OpenLayers.Util.createAlphaImageDiv(id, centered, new OpenLayers.Size(sz.w, sz.h), imgLocation + "OS/control/zoom-scale.png", "absolute", null, "crop");
            div.style.height = sz.h;
        } else
        {
            div = OpenLayers.Util.createDiv('OpenLayers_Control_PanZoomBar_Zoombar' + this.map.id, centered, sz, imgLocation + "OS/control/zoom-scale.png");
        }
        this.zoombarDiv = div;
        this.divEvents = new OpenLayers.Events(this, div, null, true);
        this.divEvents.register("mousedown", this, this.divClick);
        this.divEvents.register("mousemove", this, this.passEventToSlider);
        this.divEvents.register("dblclick", this, this.doubleClick);
        this.divEvents.register("click", this, this.doubleClick);
        this.div.appendChild(div);
        this.startTop = parseInt(div.style.top);
        this.div.appendChild(slider);
        this.map.events.register("zoomend", this, this.moveZoomBar);
        centered = centered.add(0, this.zoomStopHeight * this.map.getNumZoomLevels());
        return centered;
    },
    buttonDown: function(evt)
    {
        if (!OpenLayers.Event.isLeftClick(evt)) return;
        var slideFactor = this.map.size.w / 4;
        switch (this.action)
        {
            case "panup":
                if (this.map.animatePan)
                    this.map.animatePan(0, -slideFactor);
                else
                    this.map.pan(0, -slideFactor);
                break;
            case "pandown":
                if (this.map.animatePan)
                    this.map.animatePan(0, slideFactor);
                else
                    this.map.pan(0, slideFactor);
                break;
            case "panleft":
                if (this.map.animatePan)
                    this.map.animatePan(-slideFactor, 0);
                else
                    this.map.pan(-slideFactor, 0);
                break;
            case "panright":
                if (this.map.animatePan)
                    this.map.animatePan(slideFactor, 0);
                else
                    this.map.pan(slideFactor, 0);
                break;
            case "zoomin":
                this.map.zoomIn();
                break;
            case "zoomout":
                this.map.zoomOut();
                break;
            case "zoomworld":
                this.map.zoomToMaxExtent();
                break;
        }
        OpenLayers.Event.stop(evt);
    },
    onMapResize: function()
    {
        var pos = this._calculateOffset();
        this.moveTo(pos);
    },
    CLASS_NAME: "TISolution.Control.LargeMapControl"
});
TISolution.Control.SmallMapControl = OpenLayers.Class(TISolution.Control.LargeMapControl, {
    drawZoomBar: false,
    initialize: function()
    {
        TISolution.Control.LargeMapControl.prototype.initialize.apply(this, arguments);
    },
    CLASS_NAME: "TISolution.Control.SmallMapControl"
});
TISolution.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control.OverviewMap, {
    initialize: function(options)
    {
        var defaultOptions = {
            mapOptions: TISolution.DEFAULT_OVERVIEW_MAPOPTIONS
        };
        OpenLayers.Util.extend(defaultOptions, options);
        this.layers = [];
        this.handlers = {};
        OpenLayers.Control.prototype.initialize.apply(this, [defaultOptions]);
    },
    draw: function()
    {
        OpenLayers.Control.OverviewMap.prototype.draw.apply(this, arguments);
        var px = new OpenLayers.Pixel(0, 0);
        var sz = new OpenLayers.Size(this.size.w + 16 + 4, this.size.h + 8 + 4);
        this.bgDiv = OpenLayers.Util.createDiv(this.id, px, sz, null, null, null, 'hidden', 0.5);
        this.bgDiv.className = this.displayClass + "Background";
        this.div.appendChild(this.bgDiv);
        return this.div;
    },
    isSuitableOverview: function()
    {
        var mapExtent = this.map.getExtent();
        var maxExtent = this.map.maxExtent;
        var testExtent = new OpenLayers.Bounds(Math.max(mapExtent.left, maxExtent.left), Math.max(mapExtent.bottom, maxExtent.bottom), Math.min(mapExtent.right, maxExtent.right), Math.min(mapExtent.top, maxExtent.top));
        var resRatio = this.ovmap.getResolution() / this.map.getResolution();
        return ((resRatio > this.minRatio || this.ovmap.zoom == null) && (resRatio <= this.maxRatio) && (this.ovmap.getExtent().containsBounds(testExtent)));
    },
    CLASS_NAME: "TISolution.Control.OverviewMap"
});
TISolution.Control.ControlAnchor = {
    ANCHOR_TOP_RIGHT: 1,
    ANCHOR_TOP_LEFT: 2,
    ANCHOR_BOTTOM_RIGHT: 3,
    ANCHOR_BOTTOM_LEFT: 4,
    CLASS_NAME: "TISolution.Control.ControlAnchor"
};
TISolution.Control.ControlPosition = OpenLayers.Class({
    anchor: null,
    offset: null,
    initialize: function(anchor, offset)
    {
        this.anchor = anchor;
        this.offset = offset;
    },
    CLASS_NAME: "TISolution.Control.ControlPosition"
});
TISolution.Control.Copyright = OpenLayers.Class({
    text: null,
    bounds: null,
    initialize: function(text, bounds)
    {
        this.text = text;
        this.bounds = bounds;
    },
    CLASS_NAME: "TISolution.Control.Copyright"
});
TISolution.Control.Copyright.getDefaultCopyright = function()
{
    var text = "&copy;TISolution  solu&ccedil;&otilde;es em Geoprocessamento. Todos os direitos reservados. <a href=\"http://www.tisolution.com/\" target=\"_blank\">Acordo de licen&ccedil;a do usu&aacute;rio final</a>";
    var bounds = new TISolution.MapBounds(-180, -90, 180, 90);
    return new TISolution.Control.Copyright(text, bounds);
}
TISolution.Control.CopyrightCollection = OpenLayers.Class(OpenLayers.Control, {
    bgDiv: null,
    textDiv: null,
    copyrights: null,
    initialize: function(options)
    {
        OpenLayers.Control.prototype.initialize.apply(this, [options]);
        this.copyrights = [];
        this.addCopyright(TISolution.Control.Copyright.getDefaultCopyright());
    },
    addCopyright: function(copyright)
    {
        this.copyrights.push(copyright);
    },
    getCopyrightNotice: function(extent)
    {
        var str = "";
        for (var i = 0; i < this.copyrights.length; i++)
        {
            if (extent.intersectsBounds(this.copyrights[i].bounds)) str += this.copyrights[i].text + " ";
        }
        str = OpenLayers.String.trim(str);
        return str;
    },
    draw: function()
    {
        if (this.div == null)
        {
            var bounds = this.map.size;
            var sz = new OpenLayers.Size(bounds.w, 16);
            this.div = OpenLayers.Util.createDiv(this.id, null, sz, null, null, null, 'hidden', 1.0);
            this.div.className = this.displayClass;
            var px = new OpenLayers.Pixel(0, 0);
            this.bgDiv = OpenLayers.Util.createDiv(this.id, px, sz, null, null, null, 'hidden', 0.5);
            this.bgDiv.className = this.displayClass + "Background";
            this.div.appendChild(this.bgDiv);
            px = new OpenLayers.Pixel(4, 1);
            this.textDiv = OpenLayers.Util.createDiv(this.id, px, sz, null, null, null, 'hidden', 1.0);
            this.textDiv.className = this.displayClass + "Text";
            this.div.appendChild(this.textDiv);
        }
        this.map.events.register('moveend', this, this.updateScale);
        this.updateScale();
        return this.div;
    },
    updateScale: function()
    {
        var extent = this.map.getExtent();
        if (extent)
        {
            var str = this.getCopyrightNotice(extent);
            this.textDiv.innerHTML = str;
        }
    },
    onMapResize: function()
    {
        if (this.div != null)
        {
            var bounds = this.map.size;
            var sz = new OpenLayers.Size(bounds.w, 16);
            OpenLayers.Util.modifyDOMElement(this.div, null, null, sz);
            OpenLayers.Util.modifyDOMElement(this.bgDiv, null, null, sz);
            OpenLayers.Util.modifyDOMElement(this.textDiv, null, null, sz);
        }
    },
    CLASS_NAME: "TISolution.Control.CopyrightCollection"
});
TISolution.Icon = OpenLayers.Class(OpenLayers.Icon, {
    infoWindowAnchor: null,
    initialize: function(url, size, offset, calculateOffset, infoWindowAnchor)
    {
        OpenLayers.Icon.prototype.initialize.apply(this, arguments);
        this.infoWindowAnchor = infoWindowAnchor || TISolution.Icon.DEFAULT_INFO_WINDOW_ANCHOR;
    },
    clone: function()
    {
        return new TISolution.Icon(this.url, this.size, this.offset, this.calculateOffset, this.infoWindowAnchor);
    },
    CLASS_NAME: "TISolution.Icon"
});
TISolution.Icon.DEFAULT_ICON_URL = OpenLayers.Util.getImagesLocation() + "OS/images/markers/marker_red.png";
TISolution.Icon.DEFAULT_ICON_SIZE = new OpenLayers.Size(33, 45);
TISolution.Icon.DEFAULT_ICON_OFFSET = new OpenLayers.Pixel(-16, -37);
TISolution.Icon.DEFAULT_INFO_WINDOW_ANCHOR = new OpenLayers.Pixel(16, 16);
OpenLayers.Marker.defaultIcon = function()
{    
    var url = TISolution.Icon.DEFAULT_ICON_URL;
    var size = TISolution.Icon.DEFAULT_ICON_SIZE;
    var offset = TISolution.Icon.DEFAULT_ICON_OFFSET;
    var infoWindowAnchor = TISolution.Icon.DEFAULT_INFO_WINDOW_ANCHOR;
    var icon = new TISolution.Icon(url, size, offset, null, infoWindowAnchor);
    return icon;
};
TISolution.Layer = {};
TISolution.GazetteerEntry = OpenLayers.Class({
    name: null,
    county: null,
    type: null,
    location: null,
    initialize: function(name, county, type, location)
    {
        this.name = name;
        this.county = county;
        this.type = type;
        this.location = location;
    },
    CLASS_NAME: "TISolution.GazetteerEntry"
});
TISolution.Gazetteer = OpenLayers.Class({
    initialize: function() { },
    getLonLat: function(query, callback)
    {
        TISolution.Gazetteer.prototype.callback = callback;
        var callback = "TISolution.Gazetteer.prototype._getLonLatCallback";
        this._doGazetteerQuery(query, callback);
    },
    getLocations: function(query, callback)
    {
        TISolution.Gazetteer.prototype.callback = callback;
        var callback = "TISolution.Gazetteer.prototype._getLocationsCallback";
        this._doGazetteerQuery(query, callback);
    },
    _doGazetteerQuery: function(query, callback)
    {
        var request = TISolution.getServerBase() + TISolution.getGazetteerServerPath() + "?q=" + encodeURIComponent(query) + "&key=" + encodeURIComponent(TISolution.getApiKey()) + "&f=json" + "&callback=" + encodeURIComponent(callback) + "&url=" + encodeURIComponent(TISolution.getURL());
        var reqObj = new JSONscriptRequest(request);
        reqObj.buildScriptTag();
        reqObj.addScriptTag();
    },
    _getLonLatCallback: function(jsonData)
    {
        var mapPoint = null;
        if (jsonData != null)
        {
            var items = jsonData.GazetteerResult.items.Item;
            if (items != undefined)
            {
                if (items.length == undefined) items = [items];
                if (items.length > 0)
                {
                    var name = items[0].name;
                    var point = items[0].location["gml:Point"];
                    var pos = point["gml:pos"];
                    var pair = pos.split(" ");
                    mapPoint = new TISolution.MapPoint(parseFloat(pair[0]), parseFloat(pair[1]));
                }
            }
        }
        TISolution.Gazetteer.prototype.callback(mapPoint);
    },
    _getLocationsCallback: function(jsonData)
    {
        var locations = [];
        if (jsonData != null)
        {
            var items = jsonData.GazetteerResult.items.Item;
            if (items != undefined)
            {
                if (items.length == undefined) items = [items];
                for (var i = 0; i < items.length; i++)
                {
                    var name = items[i].name;
                    var county = items[i].county;
                    var type = items[i].type;
                    var point = items[i].location["gml:Point"];
                    var pos = point["gml:pos"];
                    var pair = pos.split(" ");
                    var location = new TISolution.MapPoint(parseFloat(pair[0]), parseFloat(pair[1]));
                    var gazetteerEntry = new TISolution.GazetteerEntry(name, county, type, location);
                    locations.push(gazetteerEntry);
                }
            }
        }
        TISolution.Gazetteer.prototype.callback(locations);
    },
    CLASS_NAME: "TISolution.Gazetteer"
});
TISolution.SupportService = OpenLayers.Class({
    initialize: function() { },
    getTileCount: function(callback)
    {
        TISolution.SupportService.prototype.callback = callback;
        var query = "tilecount";
        var callback = "TISolution.SupportService.prototype._getTileCountCallback";
        this._doServiceQuery(query, callback);
    },
    _doServiceQuery: function(query, callback)
    {
        var request = TISolution.getServerBase() + TISolution.getSupportServerPath() + "?q=" + encodeURIComponent(query) + "&key=" + encodeURIComponent(TISolution.getApiKey()) + "&f=json" + "&callback=" + encodeURIComponent(callback) + "&url=" + encodeURIComponent(TISolution.getURL());
        var reqObj = new JSONscriptRequest(request);
        reqObj.buildScriptTag();
        reqObj.addScriptTag();
    },
    _getTileCountCallback: function(jsonData)
    {
        var tilesUsed = -1;
        var maxTiles = -1;
        if (jsonData != null)
        {
            var apiTileCount = jsonData.APITileCountVO;
            if (apiTileCount != null)
            {
                tilesUsed = apiTileCount.tilesUsed;
                maxTiles = apiTileCount.maxTiles;
            }
        }
        TISolution.SupportService.prototype.callback(tilesUsed, maxTiles);
    },
    CLASS_NAME: "TISolution.SupportService"
});
TISolution.Marker = OpenLayers.Class(OpenLayers.Marker, {
    openInfoWindow: function()
    {
        this.map.closeInfoWindow();
        this.map.openInfoWindow(this.icon, this.lonlat, this.contentDisplay, this.size);
    },
    CLASS_NAME: "TISolution.Map"
});

TISolution.Map = OpenLayers.Class(OpenLayers.Map, {
    centreInfoWindow: true,
    initialize: function(div, options)
    {
        this.zoom = null;
        var mapOptions = OpenLayers.Util.extend({ mapversion: "street" }, TISolution.DEFAULT_MAPOPTIONS_WITHOUT_CONTROLS);
        mapOptions.controls =
        [
            new OpenLayers.Control.Navigation(), new OpenLayers.Control.KeyboardDefaults(),
            new TISolution.Control.CopyrightCollection(), new OpenLayers.Control.ArgParser()
        ];
        mapOptions = OpenLayers.Util.extend(mapOptions, options);
        OpenLayers.Map.prototype.initialize.call(this, div, mapOptions);
        var wmsLayer = new TISolution.Layer.WMS(mapOptions.mapversion);
        this.addLayer(wmsLayer);
        if (!(options && options.controls))
        {
            if (this.size.h >= 300) this.addControl(new TISolution.Control.LargeMapControl());
            else this.addControl(new TISolution.Control.SmallMapControl());
            this.addControl(new TISolution.Control.CopyrightCollection());
        }
        this.vectorLayer = new OpenLayers.Layer.Vector('Vector Layer', { displayInLayerSwitcher: false });
        this.addLayer(this.vectorLayer);
        this.markerLayer = new OpenLayers.Layer.Markers('Marker Layer', { displayInLayerSwitcher: false });
        this.addLayer(this.markerLayer);
    },
    getMarkerLayer: function()
    {
        return this.markerLayer;
    },
    getVectorLayer: function()
    {
        return this.vectorLayer;
    },
    getInfoWindow: function()
    {
        return this.infoWindow;
    },
    createMarker: function(pos, icon, html, size)
    {
        var marker = new TISolution.Marker(pos, icon);
        marker.contentDisplay = html;
        if (html)
        {
            marker.events.register("mousedown",
                {
                    marker: marker,
                    size: size
                },
                function(evt)
                {
                    this.marker.map.closeInfoWindow();
                    this.marker.map.openInfoWindow(this.marker.icon, this.marker.lonlat, this.marker.contentDisplay, this.size);
                    OpenLayers.Event.stop(evt);
                }
            );
        }
        this.markerLayer.addMarker(marker);
        return marker;
    },    
    removeMarker: function(marker)
    {
        this.markerLayer.removeMarker(marker);
    },
    clearMarkers: function()
    {
        this.markerLayer.clearMarkers();
    },
    addFeatures: function(features)
    {
        this.vectorLayer.addFeatures(features);
    },
    removeFeatures: function(features)
    {
        this.vectorLayer.removeFeatures(features);
    },
    destroyFeatures: function()
    {
        this.vectorLayer.destroyFeatures();
    },
    openInfoWindow: function(icon, pos, html, size)
    {
        if (!this.infoWindow)
        {
            this.infoWindow = new TISolution.InfoWindow("infoWindow", new OpenLayers.LonLat(0, 0), new OpenLayers.Size(240, 280), "", null, true);
            this.addPopup(this.infoWindow);
            this.infoWindow._hide();
        }
        this.infoWindow.setSize(size);
        if (icon)
            this.infoWindow.setAnchor(icon);
        this.infoWindow.setPosition(pos);
        this.infoWindow.setContentHTML(html);
        if (this.centreInfoWindow)
        {
            var windowSize = this.infoWindow.fullSize;
            var resolution = this.getResolution();
            var x = (pos.lon - this.center.lon) / resolution;
            var y = (this.center.lat - pos.lat) / resolution;
            var dx = x - windowSize.w / 2;
            var dy = y - windowSize.h / 2;
            this.animatePan(dx, dy,
                {
                    duration: 500
                }
            );
        }
        this.infoWindow.show();
    },
    closeInfoWindow: function()
    {
        if (this.infoWindow)
        {
            this.infoWindow._hide();
        }
    },
    animatePan: function(dx, dy, options)
    {
        if (!this._panX) this._panX = 0;
        if (!this._panY) this._panY = 0;
        if (!this._anim) this._anim = null;
        this._panX += dx;
        this._panY += dy;
        if (this._anim == null)
        {
            var completeFunc = OpenLayers.Function.bind(this.animatePanEnd, this);
            var animOptions = {
                duration: 200,
                onComplete: completeFunc,
                transition: Animator.tx.easeOut
            };
            if (options)
                OpenLayers.Util.extend(animOptions, options);
            this._anim = new Animator(animOptions);
            var func = OpenLayers.Function.bind(this.animatePanStep, this);
            this._anim.addSubject(func);
            this._anim.play();
            this._animRunning = true;
        } else
        {
            this._lastX = 0;
            this._lastY = 0;
            this._anim.play();
        }
    },
    animatePanStep: function(value)
    {
        var dx = parseInt(this._panX * value);
        var dy = parseInt(this._panY * value);
        this.panDrag(dx - this._lastX, dy - this._lastY, true);
        this._lastX = dx;
        this._lastY = dy;
    },
    animatePanEnd: function()
    {
        this._panX = 0;
        this._panY = 0;
        this._lastX = 0;
        this._lastY = 0;
        this._anim = null;
        this.panDrag(0, 0, false);
    },
    panDrag: function(dx, dy, dragging)
    {
        var center = this.getCenter();
        var resolution = this.getResolution();
        var extent = this.getExtent();
        var centerPx = new OpenLayers.Pixel(1 / resolution * (center.lon - extent.left), 1 / resolution * (extent.top - center.lat));
        var newCenterPx = centerPx.add(dx, dy);
        var newCenterMapPoint = this.getMapPointFromViewPortPx(newCenterPx);
        this.setCenter(newCenterMapPoint, null, dragging);
    },
    addOverlay: function(overlay)
    {
        if (overlay instanceof OpenLayers.Marker)
            this.markerLayer.addMarker(overlay);
        else
            if (overlay instanceof TISolution.Polyline)
            this.vectorLayer.addFeatures(overlay.feature);
    },
    getCenter: function()
    {
        if (this.center instanceof OpenLayers.LonLat)
        {
            this.center = new TISolution.MapPoint(this.center.lon, this.center.lat);
        }
        return this.center;
    },
    setCenter: function(mapPoint, zoom, dragging, forceZoomChange)
    {
        if (mapPoint instanceof OpenLayers.LonLat)
        {
            mapPoint = new TISolution.MapPoint(mapPoint.lon, mapPoint.lat);
        }
        OpenLayers.Map.prototype.setCenter.call(this, mapPoint, zoom, dragging, forceZoomChange);
    },
    updateSize: function()
    {
        this.events.element.offsets = null;
        var newSize = this.getCurrentSize();
        var oldSize = this.getSize();
        if (oldSize == null) this.size = oldSize = newSize;
        if (!newSize.equals(oldSize))
        {
            this.size = newSize;
            for (var i = 0; i < this.layers.length; i++)
            {
                this.layers[i].onMapResize();
            }
            for (var i = 0; i < this.controls.length; i++)
            {
                if (this.controls[i].onMapResize) this.controls[i].onMapResize();
            }
            if (this.baseLayer != null)
            {
                var center = new OpenLayers.Pixel(newSize.w / 2, newSize.h / 2);
                var centerLL = this.getLonLatFromViewPortPx(center);
                var zoom = this.getZoom();
                this.zoom = null;
                this.setCenter(this.getCenter(), zoom);
            }
        }
    },
    getMapPointFromViewPortPx: function(viewPortPx)
    {
        var mapPoint = null;
        if (this.baseLayer != null)
        {
            mapPoint = this.baseLayer.getMapPointFromViewPortPx(viewPortPx);
        }
        return mapPoint;
    },
    getViewPortPxFromMapPoint: function(mapPoint)
    {
        var px = null;
        if (this.baseLayer != null)
        {
            px = this.baseLayer.getViewPortPxFromMapPoint(mapPoint);
        }
        return px;
    },
    getMapPointFromPixel: function(px)
    {
        return this.getMapPointFromViewPortPx(px);
    },
    getPixelFromMapPoint: function(mapPoint)
    {
        return this.getViewPortPxFromMapPoint(mapPoint);
    },
    getMapPointFromLayerPx: function(px)
    {
        px = this.getViewPortPxFromLayerPx(px);
        return this.getMapPointFromViewPortPx(px);
    },
    getLayerPxFromMapPoint: function(mapPoint)
    {
        var px = this.getViewPortPxFromMapPoint(mapPoint);
        return this.getLayerPxFromViewPortPx(px);
    },    
    CLASS_NAME: "TISolution.Map"
});
TISolution.DEFAULT_MAPOPTIONS_WITHOUT_CONTROLS = {
    maxResolution: 0.703125,
    numZoomLevels: 17,
    maxExtent: new TISolution.MapBounds(-180, -90, 180, 90),
    tileSize: new TISolution.ScreenSize(256, 256),
    units: 'degrees',
    projection: "EPSG:4326",
    theme: OpenLayers._getScriptLocation() + 'theme/default/style.css'
};
TISolution.DEFAULT_MAPOPTIONS = {
    maxResolution: 0.703125,
    numZoomLevels: 17,
    maxExtent: new TISolution.MapBounds(-180, -90, 180, 90),
    tileSize: new TISolution.ScreenSize(256, 256),
    units: 'degrees',
    projection: "EPSG:4326",
    theme: OpenLayers._getScriptLocation() + 'theme/default/style.css',
    zoom: null,
    controls: [new OpenLayers.Control.Navigation(), new OpenLayers.Control.KeyboardDefaults(), new TISolution.Control.CopyrightCollection(), new OpenLayers.Control.ArgParser()]
};
TISolution.DEFAULT_OVERVIEW_MAPOPTIONS = {
    maxResolution: 0.703125,
    numZoomLevels: 17,
    maxExtent: new TISolution.MapBounds(-180, -90, 180, 90),
    tileSize: new TISolution.ScreenSize(256, 256),
    units: 'degrees',
    projection: "EPSG:4326",
    theme: OpenLayers._getScriptLocation() + 'theme/default/style.css',
    controls: [new OpenLayers.Control.ArgParser()],
    zoom: null
};
TISolution.Layer.MapOverlay = OpenLayers.Class(OpenLayers.Layer, {
    position: null,
    size: null,
    html: null,
    initialize: function(name, options)
    {
        OpenLayers.Layer.prototype.initialize.apply(this, arguments);
        this.div.innerHTML = this.html;
        if (options)
        {
            if (options.position) this.setPosition(options.position);
            if (options.size) this.setSize(options.size);
        }
    },
    destroy: function()
    {
        this.position = null;
        this.size = null;
        this.html = null;
        OpenLayers.Layer.prototype.destroy.apply(this, arguments);
    },
    setHTML: function(html)
    {
        this.html = html;
        this.div.innerHTML = this.html;
    },
    setPosition: function(px)
    {
        if (px) this.position = px.clone();
    },
    setSize: function(size)
    {
        if (size != null)
        {
            this.size = size;
        }
    },
    moveTo: function(bounds, zoomChanged, dragging)
    {
        var tlpos = new OpenLayers.LonLat(this.position.lon, this.position.lat + this.size.h);
        var tlpx = this.map.getLayerPxFromLonLat(tlpos);
        var brpos = new OpenLayers.LonLat(this.position.lon + this.size.w, this.position.lat);
        var brpx = this.map.getLayerPxFromLonLat(brpos);
        var sz = new OpenLayers.Size(brpx.x - tlpx.x, brpx.y - tlpx.y);
        OpenLayers.Util.modifyDOMElement(this.div, null, tlpx, sz);
        var display = this.visibility;
        if (!this.isBaseLayer)
        {
            display = display && this.inRange;
        }
        this.display(display);
    },
    CLASS_NAME: "TISolution.Layer.MapOverlay"
});
TISolution.Layer.ScreenOverlay = OpenLayers.Class(OpenLayers.Layer, {
    position: null,
    size: null,
    html: null,
    initialize: function(name, options)
    {
        OpenLayers.Layer.prototype.initialize.apply(this, arguments);
        this.div.innerHTML = this.html;
    },
    setHTML: function(html)
    {
        if (html != this.html)
        {
            this.html = html;
            this.div.innerHTML = this.html;
        }
    },
    setPosition: function(px)
    {
        this.position = px;
    },
    setSize: function(size)
    {
        this.size = size;
    },
    _calculatePosition: function()
    {
        var pos;
        var px = this.position;
        if (px)
        {
            if (px instanceof TISolution.Control.ControlPosition)
            {
                var offsetx = 0;
                var offsety = 0;
                var width = 0;
                var height = 0;
                if (px.offset)
                {
                    offsetx = px.offset.w;
                    offsety = px.offset.h;
                }
                if (this.size)
                {
                    width = this.size.w;
                    height = this.size.h;
                }
                switch (px.anchor)
                {
                    case TISolution.Control.ControlAnchor.ANCHOR_TOP_LEFT:
                        pos = new OpenLayers.Pixel(offsetx, offsety);
                        break;
                    case TISolution.Control.ControlAnchor.ANCHOR_TOP_RIGHT:
                        pos = new OpenLayers.Pixel(this.map.size.w - width - offsetx, offsety);
                        break;
                    case TISolution.Control.ControlAnchor.ANCHOR_BOTTOM_LEFT:
                        pos = new OpenLayers.Pixel(offsetx, this.map.size.h - height - offsety);
                        break;
                    case TISolution.Control.ControlAnchor.ANCHOR_BOTTOM_RIGHT:
                        pos = new OpenLayers.Pixel(this.map.size.w - width - offsetx, this.map.size.h - height - offsety);
                        break;
                    default:
                        pos = new OpenLayers.Pixel(offsetx, offsety);
                        break;
                }
            } else
            {
                pos = px.clone();
            }
        }
        return pos;
    },
    moveTo: function(bounds, zoomChanged, dragging)
    {
        var pos = this._calculatePosition();
        var left = 0 - parseInt(OpenLayers.Element.getStyle(this.map.layerContainerDiv, 'left')) + pos.x;
        var top = 0 - parseInt(OpenLayers.Element.getStyle(this.map.layerContainerDiv, 'top')) + pos.y;
        var px = new OpenLayers.Pixel(left, top);
        OpenLayers.Util.modifyDOMElement(this.div, null, px);
        var display = this.visibility;
        if (!this.isBaseLayer)
        {
            display = display && this.inRange;
        }
        this.display(display);
    },
    CLASS_NAME: "TISolution.Layer.ScreenOverlay"
});
TISolution.Layer.WMS = OpenLayers.Class(OpenLayers.Layer.WMS, {
    //gridProjection: null,
    initialize: function(mapversion)
    {
        var layerName = null;
        //this.gridProjection = new TISolution.GridProjection();        
        if (mapversion == "geo")
            layerName = "geo_layer";
        else
            layerName = "desenv";
        var wmsUrl = TISolution.getServerBase() + TISolution.getTileServerPath();
        var apikey = TISolution.getApiKey();
        var url = TISolution.getURL();
        var params = {
            format: 'image/png',
            key: apikey,
            url: url,
            layers: layerName,
            srs: 'EPSG:4326',
            height: '256',
            width: '256',
            styles: '',
            format: 'image/png',
            tiled: 'true',
            BGCOLOR: '0x6BA0BB'
        };
        var options = {
            buffer: 0,
            displayInLayerSwitcher: false,
            transitionEffect: 'resize'
        };
        OpenLayers.Layer.WMS.prototype.initialize.call(this, layerName, wmsUrl, params, options);
    },
    destroy: function()
    {
        OpenLayers.Layer.WMS.prototype.destroy.apply(this, arguments);
    },
    clone: function(obj)
    {
        if (obj == null)
        {
            obj = new TISolution.Layer.WMS();
        }
        return obj;
    },
    //        moveTo: function(bounds, zoomChanged, dragging)
    //        {
    //            if (zoomChanged)
    //            {
    ////                this.clearGrid();
    ////                this.map.tileSize = this.tileSize250;
    ////                this.setTileSize(this.tileSize250);
    //                
    ////                if (this.map.resolutions[this.map.zoom] <= 2)
    ////                {
    ////                    this.clearGrid();
    ////                    this.map.tileSize = this.tileSize250;
    ////                    this.setTileSize(this.tileSize250);
    ////                }
    ////                else
    ////                {
    ////                    this.clearGrid();
    ////                    this.map.tileSize = this.tileSize200;
    ////                    this.setTileSize(this.tileSize200);
    ////                }
    ////                this.params.LAYERS = this.map.resolutions[this.map.zoom];
    //            }
    //            OpenLayers.Layer.WMS.prototype.moveTo.apply(this, arguments);
    //        },
    getMapPointFromViewPortPx: function(viewPortPx)
    {
        var mapPoint = null;
        if (viewPortPx != null)
        {
            var size = this.map.getSize();
            var center = this.map.getCenter();
            if (center)
            {
                var res = this.map.getResolution();
                var delta_x = viewPortPx.x - (size.w / 2);
                var delta_y = viewPortPx.y - (size.h / 2);
                mapPoint = new TISolution.MapPoint(center.lon + delta_x * res, center.lat - delta_y * res);
            }
        }
        return mapPoint;
    },
    //        getViewPortPxFromLonLat: function(lonlat)
    //        {
    //            var px = null; if (lonlat != null)
    //            {
    //                var bng_lonlat = lonlat.clone(); if (bng_lonlat.lon <= 180 && bng_lonlat.lat <= 90)
    //                { bng_lonlat = this.gridProjection.getMapPointFromLonLat(bng_lonlat); }
    //                var resolution = this.map.getResolution(); var extent = this.map.getExtent(); px = new OpenLayers.Pixel(Math.round(1 / resolution * (bng_lonlat.lon - extent.left)), Math.round(1 / resolution * (extent.top - bng_lonlat.lat)));
    //            }
    //            return px;
    //        }, 
    CLASS_NAME: "TISolution.Layer.WMS"
});
OpenLayers.Handler.Keyboard.prototype.activate = function()
{
    if (OpenLayers.Handler.prototype.activate.apply(this, arguments))
    {
        for (var i = 0; i < this.KEY_EVENTS.length; i++)
        {
            OpenLayers.Event.observe(document, this.KEY_EVENTS[i], this.eventListener);
        }
        return true;
    } else
    {
        return false;
    }
};
OpenLayers.Handler.Keyboard.prototype.deactivate = function()
{
    var deactivated = false;
    if (OpenLayers.Handler.prototype.deactivate.apply(this, arguments))
    {
        for (var i = 0; i < this.KEY_EVENTS.length; i++)
        {
            OpenLayers.Event.stopObserving(document, this.KEY_EVENTS[i], this.eventListener);
        }
        deactivated = true;
    }
    return deactivated;
};
OpenLayers.Control.KeyboardDefaults.prototype.draw = function()
{
    this.handler = new OpenLayers.Handler.Keyboard(this, {
        "keydown": this.defaultKeyPress
    });
    this.activate();
};
OpenLayers.Control.KeyboardDefaults.prototype.defaultKeyPress = function(code)
{
    var panFunc;
    switch (code)
    {
        case OpenLayers.Event.KEY_LEFT:
            if (this.map.animatePan) this.map.animatePan(-this.slideFactor, 0);
            else this.map.pan(-this.slideFactor, 0);
            break;
        case OpenLayers.Event.KEY_RIGHT:
            if (this.map.animatePan) this.map.animatePan(this.slideFactor, 0);
            else this.map.pan(this.slideFactor, 0);
            break;
        case OpenLayers.Event.KEY_UP:
            if (this.map.animatePan) this.map.animatePan(0, -this.slideFactor);
            else this.map.pan(0, -this.slideFactor);
            break;
        case OpenLayers.Event.KEY_DOWN:
            if (this.map.animatePan) this.map.animatePan(0, this.slideFactor);
            else this.map.pan(0, this.slideFactor);
            break;
        case 33:
            var size = this.map.getSize();
            if (this.map.animatePan) this.map.animatePan(0, -0.75 * size.h);
            else this.map.pan(0, -0.75 * size.h);
            break;
        case 34:
            var size = this.map.getSize();
            if (this.map.animatePan) this.map.animatePan(0, 0.75 * size.h);
            else this.map.pan(0, 0.75 * size.h);
            break;
        case 35:
            var size = this.map.getSize();
            if (this.map.animatePan) this.map.animatePan(0.75 * size.h, 0);
            else this.map.pan(0.75 * size.h, 0);
            break;
        case 36:
            var size = this.map.getSize();
            if (this.map.animatePan) this.map.animatePan(-0.75 * size.h, 0);
            else this.map.pan(-0.75 * size.h, 0);
            break;
        case 43:
            this.map.zoomIn();
            break;
        case 45:
            this.map.zoomOut();
            break;
        case 107:
            this.map.zoomIn();
            break;
        case 109:
            this.map.zoomOut();
            break;
    }
};
//OpenLayers.Control.DragPan.prototype.panMap = function(xy)
//{
//    if (this.panned == false)
//    {
//        this.startX = xy.x;
//        this.startY = xy.y;
//        this.numPans = 0;
//    }
//    this.panned = true;
//    this.numPans++;
//    this.deltaX = this.handler.last.x - xy.x;
//    this.deltaY = this.handler.last.y - xy.y;
//    var size = this.map.getSize();
//    var newXY = new OpenLayers.Pixel(size.w / 2 + this.deltaX, size.h / 2 + this.deltaY);
//    var newCenter = this.map.getLonLatFromViewPortPx(newXY);
//    this.map.setCenter(newCenter, null, this.handler.dragging);
//};
//OpenLayers.Control.DragPan.prototype.panMapDone = function(xy)
//{
//    if (this.panned)
//    {
//        var smoothEnd = false;
//        if (Math.abs(this.deltatX) > 4 || Math.abs(this.deltaY) > 4)
//        {
//            smoothEnd = true;
//        }
//        this.panMap(xy);
//        if (smoothEnd == true && this.map.animatePan)
//        {
//            var dx = this.startX - xy.x;
//            var dy = this.startY - xy.y;
//            var duration;
//            var distSqr = dx * dx + dy * dy;
//            var max = this.map.size.w * this.map.size.w + this.map.size.h * this.map.size.h;
//            var factor = distSqr * 100 / (max * this.numPans);
//            if (factor > 4) factor = 4;
//            dx *= factor / this.numPans;
//            dy *= factor / this.numPans;
//            duration = 100 * factor;
//            if (duration < 200) duration = 200;
//            if (duration > 400) duration = 400;
//            var options = {
//                duration: duration,
//                transition: Animator.tx.easeOut
//            };
//            this.map.animatePan(dx, dy, options);
//        }
//        this.panned = false;
//    }
//};
//OpenLayers.Layer.Vector.prototype.moveTo = function(bounds, zoomChanged, dragging)
//{
//    OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
//    if (!dragging)
//    {
//        this.renderer.root.style.visibility = "hidden";
//        if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1)
//        {
//            this.div.scrollLeft = this.div.scrollLeft;
//        }
//        this.div.style.left = -parseInt(this.map.layerContainerDiv.style.left) + "px";
//        this.div.style.top = -parseInt(this.map.layerContainerDiv.style.top) + "px";
//        var extent = this.map.getExtent();
//        this.renderer.setExtent(extent);
//        this.renderer.root.style.visibility = "visible";
//    }
//    if (!this.drawn || zoomChanged)
//    {
//        this.drawn = true;
//        for (var i = 0; i < this.features.length; i++)
//        {
//            var feature = this.features[i];
//            this.drawFeature(feature);
//        }
//    }
//};
//OpenLayers.Renderer.Elements.prototype.drawGeometry = function(geometry, style, featureId)
//{
//    var className = geometry.CLASS_NAME;
//    if ((className == "OpenLayers.Geometry.Collection") || (className == "OpenLayers.Geometry.MultiPoint") || (className == "OpenLayers.Geometry.MultiLineString") || (className == "OpenLayers.Geometry.MultiPolygon"))
//    {
//        for (var i = 0; i < geometry.components.length; i++)
//        {
//            this.drawGeometry(geometry.components[i], style, featureId);
//        }
//        return;
//    };
//    var nodeType = this.getNodeType(geometry);
//    var node = this.nodeFactory(geometry.id, nodeType, geometry);
//    node._featureId = featureId;
//    node._geometryClass = geometry.CLASS_NAME;
//    node._style = style;
//    node = this.drawGeometryNode(node, geometry);
//    if (node.parentNode != this.root)
//    {
//        this.root.appendChild(node);
//    }
//};
//OpenLayers.Renderer.Elements.prototype.drawGeometryNode = function(node, geometry, style)
//{
//    style = style || node._style;
//    var options = {
//        'isFilled': true,
//        'isStroked': true
//    };
//    switch (geometry.CLASS_NAME)
//    {
//        case "OpenLayers.Geometry.Point":
//            this.drawPoint(node, geometry);
//            break;
//        case "OpenLayers.Geometry.LineString":
//            options.isFilled = false;
//            this.drawLineString(node, geometry);
//            break;
//        case "OpenLayers.Geometry.LinearRing":
//            this.drawLinearRing(node, geometry);
//            break;
//        case "OpenLayers.Geometry.Polygon":
//            this.drawPolygon(node, geometry);
//            break;
//        case "OpenLayers.Geometry.Surface":
//            this.drawSurface(node, geometry);
//            break;
//        case "OpenLayers.Geometry.Rectangle":
//            this.drawRectangle(node, geometry);
//            break;
//        default:
//            break;
//    }
//    node._style = style;
//    node._options = options;
//    return this.setStyle(node, style, options, geometry);
//};
//OpenLayers.Renderer.VML.prototype.setStyle = function(node, style, options, geometry)
//{
//    style = style || node._style;
//    options = options || node._options;
//    if (node._geometryClass == "OpenLayers.Geometry.Point")
//    {
//        if (style.externalGraphic)
//        {
//            var id = node.id;
//            var _featureId = node._featureId;
//            var _geometryClass = node._geometryClass;
//            var _style = node._style;
//            node = this.createNode("v:rect", id);
//            var fill = this.createNode("v:fill", id + "_image");
//            node.appendChild(fill);
//            node._featureId = _featureId;
//            node._geometryClass = _geometryClass;
//            node._style = _style;
//            fill.src = style.externalGraphic;
//            fill.type = "frame";
//            node.style.flip = "y";
//            if (!(style.graphicWidth && style.graphicHeight))
//            {
//                fill.aspect = "atmost";
//            }
//            var width = style.graphicWidth || style.graphicHeight;
//            var height = style.graphicHeight || style.graphicWidth;
//            width = width ? width : style.pointRadius * 2;
//            height = height ? height : style.pointRadius * 2;
//            var resolution = this.getResolution();
//            var xOffset = (style.graphicXOffset != undefined) ? style.graphicXOffset : -(0.5 * width);
//            var yOffset = (style.graphicYOffset != undefined) ? style.graphicYOffset : -(0.5 * height);
//            node.style.left = ((geometry.x / resolution) + xOffset).toFixed();
//            node.style.top = ((geometry.y / resolution) - (yOffset + height)).toFixed();
//            node.style.width = width;
//            node.style.height = height;
//            style.fillColor = "none";
//            style.strokeColor = "none";
//        } else
//        {
//            this.drawCircle(node, geometry, style.pointRadius);
//        }
//    }
//    if (options.isFilled)
//    {
//        node.setAttribute("fillcolor", style.fillColor);
//    } else
//    {
//        node.setAttribute("filled", "false");
//    }
//    var fills = node.getElementsByTagName("fill");
//    var fill = (fills.length == 0) ? null : fills[0];
//    if (!options.isFilled)
//    {
//        if (fill)
//        {
//            node.removeChild(fill);
//        }
//    } else
//    {
//        if (!fill)
//        {
//            fill = this.createNode('v:fill', node.id + "_fill");
//            node.appendChild(fill);
//        }
//        if (node._geometryClass == "OpenLayers.Geometry.Point" && style.externalGraphic && style.graphicOpacity)
//        {
//            fill.setAttribute("opacity", style.graphicOpacity);
//        } else if (style.fillOpacity)
//        {
//            fill.setAttribute("opacity", style.fillOpacity);
//        }
//    }
//    if (options.isStroked)
//    {
//        node.setAttribute("strokecolor", style.strokeColor);
//        node.setAttribute("strokeweight", style.strokeWidth);
//    } else
//    {
//        node.setAttribute("stroked", "false");
//    }
//    var strokes = node.getElementsByTagName("stroke");
//    var stroke = (strokes.length == 0) ? null : strokes[0];
//    if (!options.isStroked)
//    {
//        if (stroke)
//        {
//            node.removeChild(stroke);
//        }
//    } else
//    {
//        if (!stroke)
//        {
//            stroke = this.createNode('v:stroke', node.id + "_stroke");
//            node.appendChild(stroke);
//        }
//        stroke.setAttribute("opacity", style.strokeOpacity);
//        stroke.setAttribute("endcap", !style.strokeLinecap || style.strokeLinecap == 'butt' ? 'flat' : style.strokeLinecap);
//    }
//    if (style.cursor)
//    {
//        node.style.cursor = style.cursor;
//    }
//    return node;
//};
//OpenLayers.Renderer.SVG.prototype.setStyle = function(node, style, options)
//{
//    style = style || node._style;
//    options = options || node._options;
//    if (node._geometryClass == "OpenLayers.Geometry.Point")
//    {
//        if (style.externalGraphic)
//        {
//            var id = node.getAttributeNS(null, "id");
//            var x = parseFloat(node.getAttributeNS(null, "cx"));
//            var y = parseFloat(node.getAttributeNS(null, "cy"));
//            var _featureId = node._featureId;
//            var _geometryClass = node._geometryClass;
//            var _style = node._style;
//            node = this.createNode("image", id);
//            node._featureId = _featureId;
//            node._geometryClass = _geometryClass;
//            node._style = _style;
//            if (style.graphicWidth && style.graphicHeight)
//            {
//                node.setAttributeNS(null, "preserveAspectRatio", "none");
//            }
//            var width = style.graphicWidth || style.graphicHeight;
//            var height = style.graphicHeight || style.graphicWidth;
//            width = width ? width : style.pointRadius * 2;
//            height = height ? height : style.pointRadius * 2;
//            var xOffset = (style.graphicXOffset != undefined) ? style.graphicXOffset : -(0.5 * width);
//            var yOffset = (style.graphicYOffset != undefined) ? style.graphicYOffset : -(0.5 * height);
//            var opacity = style.graphicOpacity || style.fillOpacity;
//            node.setAttributeNS(null, "x", (x + xOffset).toFixed());
//            node.setAttributeNS(null, "y", (y + yOffset).toFixed());
//            node.setAttributeNS(null, "width", width);
//            node.setAttributeNS(null, "height", height);
//            node.setAttributeNS("http://www.w3.org/1999/xlink", "href", style.externalGraphic);
//            node.setAttributeNS(null, "style", "opacity: " + opacity);
//        } else
//        {
//            node.setAttributeNS(null, "r", style.pointRadius);
//        }
//    }
//    if (options.isFilled)
//    {
//        node.setAttributeNS(null, "fill", style.fillColor);
//        node.setAttributeNS(null, "fill-opacity", style.fillOpacity);
//    } else
//    {
//        node.setAttributeNS(null, "fill", "none");
//    }
//    if (options.isStroked)
//    {
//        node.setAttributeNS(null, "stroke", style.strokeColor);
//        node.setAttributeNS(null, "stroke-opacity", style.strokeOpacity);
//        node.setAttributeNS(null, "stroke-width", style.strokeWidth);
//        node.setAttributeNS(null, "stroke-linecap", style.strokeLinecap);
//    } else
//    {
//        node.setAttributeNS(null, "stroke", "none");
//    }
//    if (style.pointerEvents)
//    {
//        node.setAttributeNS(null, "pointer-events", style.pointerEvents);
//    }
//    if (style.cursor)
//    {
//        node.setAttributeNS(null, "cursor", style.cursor);
//    }
//    return node;
//};
//OpenLayers.Feature.prototype.popupClass = TISolution.InfoWindow;
//OpenLayers.Layer.GML.prototype.gridProjection = new TISolution.GridProjection();
//OpenLayers.Layer.GML.prototype.preFeatureInsert = function(feature)
//{
//    var geometry = feature.geometry;
//    var className = geometry.CLASS_NAME;
//    if ((className == "OpenLayers.Geometry.Collection") || (className == "OpenLayers.Geometry.MultiPoint") || (className == "OpenLayers.Geometry.MultiLineString") || (className == "OpenLayers.Geometry.MultiPolygon"))
//    {
//        for (var i = 0; i < geometry.components.length; i++)
//        {
//            this.fixGeometry(geometry.components[i]);
//        }
//    } else this.fixGeometry(geometry);
//    return feature;
//};
//OpenLayers.Layer.GML.prototype.fixGeometry = function(geometry)
//{
//    switch (geometry.CLASS_NAME)
//    {
//        case "OpenLayers.Geometry.Point":
//            var bng_lonlat = new OpenLayers.LonLat(geometry.x, geometry.y);
//            if (bng_lonlat.lon <= 180 && bng_lonlat.lat <= 90)
//            {
//                bng_lonlat = this.gridProjection.getMapPointFromLonLat(bng_lonlat);
//                geometry.x = bng_lonlat.lon;
//                geometry.y = bng_lonlat.lat;
//            }
//            break;
//        case "OpenLayers.Geometry.LineString":
//            for (var i = 0; i < geometry.components.length; i++)
//            {
//                this.fixGeometry(geometry.components[i]);
//            }
//            break;
//        case "OpenLayers.Geometry.LinearRing":
//            for (var i = 0; i < geometry.components.length; i++)
//            {
//                this.fixGeometry(geometry.components[i]);
//            }
//            break;
//        case "OpenLayers.Geometry.Polygon":
//            for (var i = 0; i < geometry.components.length; i++)
//            {
//                this.fixGeometry(geometry.components[i]);
//            }
//            break;
//        case "OpenLayers.Geometry.Surface":
//            for (var i = 0; i < geometry.components.length; i++)
//            {
//                this.fixGeometry(geometry.components[i]);
//            }
//            break;
//        case "OpenLayers.Geometry.Rectangle":
//            var bl_bng_lonlat = new OpenLayers.LonLat(geometry.x, geometry.y);
//            var tr_bng_lonlat = new OpenLayers.LonLat(geometry.x + geometry.width, geometry.y + geometry.height);
//            if (bl_bng_lonlat.lon <= 180 && bl_bng_lonlat.lat <= 90)
//            {
//                bl_bng_lonlat = this.gridProjection.getMapPointFromLonLat(bl_bng_lonlat);
//                tr_bng_lonlat = this.gridProjection.getMapPointFromLonLat(tr_bng_lonlat);
//                geometry.x = bl_bng_lonlat.lon;
//                geometry.y = bl_bng_lonlat.lat;
//                geometry.width = tr_bng_lonlat.lon - bl_bng_lonlat.lon;
//                geometry.height = tr_bng_lonlat.lat - bl_bng_lonlat.lat;
//            }
//            break;
//        default:
//            break;
//    }
//};
//if (!OpenLayers.Control.prototype.onMapResize) OpenLayers.Control.prototype.onMapResize = function() { };
//OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position, border, overflow, opacity)
//{
//    if (id)
//    {
//        element.id = id;
//    }
//    if (px)
//    {
//        element.style.left = px.x + "px";
//        element.style.top = px.y + "px";
//    }
//    if (sz)
//    {
//        element.style.width = sz.w + "px";
//        element.style.height = sz.h + "px";
//    }
//    if (position)
//    {
//        element.style.position = position;
//    }
//    if (border)
//    {
//        element.style.border = border;
//    }
//    if (overflow)
//    {
//        element.style.overflow = overflow;
//    }
//    if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0)
//    {
//        element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
//        element.style.opacity = opacity;
//    } else if (parseFloat(opacity) == 1.0)
//    {
//        element.style.filter = '';
//        element.style.opacity = '';
//    }
//};
//OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL, position, border, sizing, opacity)
//{
//    OpenLayers.Util.modifyDOMElement(div, id, px, sz, null, null, null, opacity);
//    var img = div.childNodes[0];
//    if (imgURL)
//    {
//        img.src = imgURL;
//    }
//    OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz, "relative", border);
//    if (OpenLayers.Util.alphaHack())
//    {
//        div.style.display = "inline-block";
//        if (sizing == null)
//        {
//            sizing = "scale";
//        }
//        div.style.filter = "progid:DXImageTransform.Microsoft" + ".AlphaImageLoader(src='" + img.src + "', " + "sizingMethod='" + sizing + "')";
//        if (parseFloat(div.style.opacity) >= 0.0 && parseFloat(div.style.opacity) < 1.0)
//        {
//            div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")";
//        }
//        img.style.filter = "alpha(opacity=0)";
//    }
//};
/**
Animator.js 1.1.9
	
This library is released under the BSD license:

Copyright (c) 2006, Bernard Sumption. All rights reserved.
	
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
	
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer. Redistributions in binary
form must reproduce the above copyright notice, this list of conditions and
the following disclaimer in the documentation and/or other materials
provided with the distribution. Neither the name BernieCode nor
the names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission. 
	
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.

**/
function Animator(options)
{
    this.setOptions(options);
    var _this = this;
    this.timerDelegate = function()
    {
        _this.onTimerEvent()
    };
    this.subjects = [];
    this.target = 0;
    this.state = 0;
    this.lastTime = null;
};
Animator.prototype = {
    setOptions: function(options)
    {
        this.options = Animator.applyDefaults({
            interval: 20,
            duration: 400,
            onComplete: function() { },
            onStep: function() { },
            transition: Animator.tx.easeInOut
        },
    options);
    },
    seekTo: function(to)
    {
        this.seekFromTo(this.state, to);
    },
    seekFromTo: function(from, to)
    {
        this.target = Math.max(0, Math.min(1, to));
        this.state = Math.max(0, Math.min(1, from));
        this.lastTime = new Date().getTime();
        if (!this.intervalId)
        {
            this.intervalId = window.setInterval(this.timerDelegate, this.options.interval);
        }
    },
    jumpTo: function(to)
    {
        this.target = this.state = Math.max(0, Math.min(1, to));
        this.propagate();
    },
    toggle: function()
    {
        this.seekTo(1 - this.target);
    },
    addSubject: function(subject)
    {
        this.subjects[this.subjects.length] = subject;
        return this;
    },
    clearSubjects: function()
    {
        this.subjects = [];
    },
    propagate: function()
    {
        var value = this.options.transition(this.state);
        for (var i = 0; i < this.subjects.length; i++)
        {
            if (this.subjects[i].setState)
            {
                this.subjects[i].setState(value);
            } else
            {
                this.subjects[i](value);
            }
        }
    },
    onTimerEvent: function()
    {
        var now = new Date().getTime();
        var timePassed = now - this.lastTime;
        this.lastTime = now;
        var movement = (timePassed / this.options.duration) * (this.state < this.target ? 1 : -1);
        if (Math.abs(movement) >= Math.abs(this.state - this.target))
        {
            this.state = this.target;
        } else
        {
            this.state += movement;
        }
        try
        {
            this.propagate();
        } catch (e) { } finally
        {
            this.options.onStep.call(this);
            if (this.target == this.state)
            {
                window.clearInterval(this.intervalId);
                this.intervalId = null;
                this.options.onComplete.call(this);
            }
        }
    },
    play: function()
    {
        this.seekFromTo(0, 1)
    },
    reverse: function()
    {
        this.seekFromTo(1, 0)
    },
    inspect: function()
    {
        var str = "#<Animator:\n";
        for (var i = 0; i < this.subjects.length; i++)
        {
            str += this.subjects[i].inspect();
        }
        str += ">";
        return str;
    }
}
Animator.applyDefaults = function(defaults, prefs)
{
    prefs = prefs || {};
    var prop, result = {};
    for (prop in defaults) result[prop] = prefs[prop] !== undefined ? prefs[prop] : defaults[prop];
    return result;
}
Animator.makeArray = function(o)
{
    if (o == null) return [];
    if (!o.length) return [o];
    var result = [];
    for (var i = 0; i < o.length; i++) result[i] = o[i];
    return result;
}
Animator.camelize = function(string)
{
    var oStringList = string.split('-');
    if (oStringList.length == 1) return oStringList[0];
    var camelizedString = string.indexOf('-') == 0 ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) : oStringList[0];
    for (var i = 1, len = oStringList.length; i < len; i++)
    {
        var s = oStringList[i];
        camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
    }
    return camelizedString;
}
Animator.apply = function(el, style, options)
{
    if (style instanceof Array)
    {
        return new Animator(options).addSubject(new CSSStyleSubject(el, style[0], style[1]));
    }
    return new Animator(options).addSubject(new CSSStyleSubject(el, style));
}
Animator.makeEaseIn = function(a)
{
    return function(state)
    {
        return Math.pow(state, a * 2);
    }
}
Animator.makeEaseOut = function(a)
{
    return function(state)
    {
        return 1 - Math.pow(1 - state, a * 2);
    }
}
Animator.makeElastic = function(bounces)
{
    return function(state)
    {
        state = Animator.tx.easeInOut(state);
        return ((1 - Math.cos(state * Math.PI * bounces)) * (1 - state)) + state;
    }
}
Animator.makeADSR = function(attackEnd, decayEnd, sustainEnd, sustainLevel)
{
    if (sustainLevel == null) sustainLevel = 0.5;
    return function(state)
    {
        if (state < attackEnd)
        {
            return state / attackEnd;
        }
        if (state < decayEnd)
        {
            return 1 - ((state - attackEnd) / (decayEnd - attackEnd) * (1 - sustainLevel));
        }
        if (state < sustainEnd)
        {
            return sustainLevel;
        }
        return sustainLevel * (1 - ((state - sustainEnd) / (1 - sustainEnd)));
    }
}
Animator.makeBounce = function(bounces)
{
    var fn = Animator.makeElastic(bounces);
    return function(state)
    {
        state = fn(state);
        return state <= 1 ? state : 2 - state;
    }
}
Animator.tx = {
    easeInOut: function(pos)
    {
        return ((-Math.cos(pos * Math.PI) / 2) + 0.5);
    },
    linear: function(x)
    {
        return x;
    },
    easeIn: Animator.makeEaseIn(1.5),
    easeOut: Animator.makeEaseOut(1.5),
    strongEaseIn: Animator.makeEaseIn(2.5),
    strongEaseOut: Animator.makeEaseOut(2.5),
    elastic: Animator.makeElastic(1),
    veryElastic: Animator.makeElastic(3),
    bouncy: Animator.makeBounce(1),
    veryBouncy: Animator.makeBounce(3)
}
function NumericalStyleSubject(els, property, from, to, units)
{
    this.els = Animator.makeArray(els);
    if (property == 'opacity' && window.ActiveXObject)
    {
        this.property = 'filter';
    } else
    {
        this.property = Animator.camelize(property);
    }
    this.from = parseFloat(from);
    this.to = parseFloat(to);
    this.units = units != null ? units : 'px';
}
NumericalStyleSubject.prototype = {
    setState: function(state)
    {
        var style = this.getStyle(state);
        var visibility = (this.property == 'opacity' && state == 0) ? 'hidden' : '';
        var j = 0;
        for (var i = 0; i < this.els.length; i++)
        {
            try
            {
                this.els[i].style[this.property] = style;
            } catch (e)
            {
                if (this.property != 'fontWeight') throw e;
            }
            if (j++ > 20) return;
        }
    },
    getStyle: function(state)
    {
        state = this.from + ((this.to - this.from) * state);
        if (this.property == 'filter') return "alpha(opacity=" + Math.round(state * 100) + ")";
        if (this.property == 'opacity') return state;
        return Math.round(state) + this.units;
    },
    inspect: function()
    {
        return "\t" + this.property + "(" + this.from + this.units + " to " + this.to + this.units + ")\n";
    }
}
function ColorStyleSubject(els, property, from, to)
{
    this.els = Animator.makeArray(els);
    this.property = Animator.camelize(property);
    this.to = this.expandColor(to);
    this.from = this.expandColor(from);
    this.origFrom = from;
    this.origTo = to;
}
ColorStyleSubject.prototype = {
    expandColor: function(color)
    {
        var hexColor, red, green, blue;
        hexColor = ColorStyleSubject.parseColor(color);
        if (hexColor)
        {
            red = parseInt(hexColor.slice(1, 3), 16);
            green = parseInt(hexColor.slice(3, 5), 16);
            blue = parseInt(hexColor.slice(5, 7), 16);
            return [red, green, blue]
        }
        if (window.DEBUG)
        {
            alert("Invalid colour: '" + color + "'");
        }
    },
    getValueForState: function(color, state)
    {
        return Math.round(this.from[color] + ((this.to[color] - this.from[color]) * state));
    },
    setState: function(state)
    {
        var color = '#' + ColorStyleSubject.toColorPart(this.getValueForState(0, state)) + ColorStyleSubject.toColorPart(this.getValueForState(1, state)) + ColorStyleSubject.toColorPart(this.getValueForState(2, state));
        for (var i = 0; i < this.els.length; i++)
        {
            this.els[i].style[this.property] = color;
        }
    },
    inspect: function()
    {
        return "\t" + this.property + "(" + this.origFrom + " to " + this.origTo + ")\n";
    }
}
ColorStyleSubject.parseColor = function(string)
{
    var color = '#',
  match;
    if (match = ColorStyleSubject.parseColor.rgbRe.exec(string))
    {
        var part;
        for (var i = 1; i <= 3; i++)
        {
            part = Math.max(0, Math.min(255, parseInt(match[i])));
            color += ColorStyleSubject.toColorPart(part);
        }
        return color;
    }
    if (match = ColorStyleSubject.parseColor.hexRe.exec(string))
    {
        if (match[1].length == 3)
        {
            for (var i = 0; i < 3; i++)
            {
                color += match[1].charAt(i) + match[1].charAt(i);
            }
            return color;
        }
        return '#' + match[1];
    }
    return false;
}
ColorStyleSubject.toColorPart = function(number)
{
    if (number > 255) number = 255;
    var digits = number.toString(16);
    if (number < 16) return '0' + digits;
    return digits;
}
ColorStyleSubject.parseColor.rgbRe = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i;
ColorStyleSubject.parseColor.hexRe = /^\#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
function DiscreteStyleSubject(els, property, from, to, threshold)
{
    this.els = Animator.makeArray(els);
    this.property = Animator.camelize(property);
    this.from = from;
    this.to = to;
    this.threshold = threshold || 0.5;
}
DiscreteStyleSubject.prototype = {
    setState: function(state)
    {
        var j = 0;
        for (var i = 0; i < this.els.length; i++)
        {
            this.els[i].style[this.property] = state <= this.threshold ? this.from : this.to;
        }
    },
    inspect: function()
    {
        return "\t" + this.property + "(" + this.from + " to " + this.to + " @ " + this.threshold + ")\n";
    }
}
function CSSStyleSubject(els, style1, style2)
{
    els = Animator.makeArray(els);
    this.subjects = [];
    if (els.length == 0) return;
    var prop, toStyle, fromStyle;
    if (style2)
    {
        fromStyle = this.parseStyle(style1, els[0]);
        toStyle = this.parseStyle(style2, els[0]);
    } else
    {
        toStyle = this.parseStyle(style1, els[0]);
        fromStyle = {};
        for (prop in toStyle)
        {
            fromStyle[prop] = CSSStyleSubject.getStyle(els[0], prop);
        }
    }
    var prop;
    for (prop in fromStyle)
    {
        if (fromStyle[prop] == toStyle[prop])
        {
            delete fromStyle[prop];
            delete toStyle[prop];
        }
    }
    var prop, units, match, type, from, to;
    for (prop in fromStyle)
    {
        var fromProp = String(fromStyle[prop]);
        var toProp = String(toStyle[prop]);
        if (toStyle[prop] == null)
        {
            if (window.DEBUG) alert("No to style provided for '" + prop + '"');
            continue;
        }
        if (from = ColorStyleSubject.parseColor(fromProp))
        {
            to = ColorStyleSubject.parseColor(toProp);
            type = ColorStyleSubject;
        } else if (fromProp.match(CSSStyleSubject.numericalRe) && toProp.match(CSSStyleSubject.numericalRe))
        {
            from = parseFloat(fromProp);
            to = parseFloat(toProp);
            type = NumericalStyleSubject;
            match = CSSStyleSubject.numericalRe.exec(fromProp);
            var reResult = CSSStyleSubject.numericalRe.exec(toProp);
            if (match[1] != null)
            {
                units = match[1];
            } else if (reResult[1] != null)
            {
                units = reResult[1];
            } else
            {
                units = reResult;
            }
        } else if (fromProp.match(CSSStyleSubject.discreteRe) && toProp.match(CSSStyleSubject.discreteRe))
        {
            from = fromProp;
            to = toProp;
            type = DiscreteStyleSubject;
            units = 0;
        } else
        {
            if (window.DEBUG)
            {
                alert("Unrecognised format for value of " + prop + ": '" + fromStyle[prop] + "'");
            }
            continue;
        }
        this.subjects[this.subjects.length] = new type(els, prop, from, to, units);
    }
}
CSSStyleSubject.prototype = {
    parseStyle: function(style, el)
    {
        var rtn = {};
        if (style.indexOf(":") != -1)
        {
            var styles = style.split(";");
            for (var i = 0; i < styles.length; i++)
            {
                var parts = CSSStyleSubject.ruleRe.exec(styles[i]);
                if (parts)
                {
                    rtn[parts[1]] = parts[2];
                }
            }
        } else
        {
            var prop, value, oldClass;
            oldClass = el.className;
            el.className = style;
            for (var i = 0; i < CSSStyleSubject.cssProperties.length; i++)
            {
                prop = CSSStyleSubject.cssProperties[i];
                value = CSSStyleSubject.getStyle(el, prop);
                if (value != null)
                {
                    rtn[prop] = value;
                }
            }
            el.className = oldClass;
        }
        return rtn;
    },
    setState: function(state)
    {
        for (var i = 0; i < this.subjects.length; i++)
        {
            this.subjects[i].setState(state);
        }
    },
    inspect: function()
    {
        var str = "";
        for (var i = 0; i < this.subjects.length; i++)
        {
            str += this.subjects[i].inspect();
        }
        return str;
    }
}
CSSStyleSubject.getStyle = function(el, property)
{
    var style;
    if (document.defaultView && document.defaultView.getComputedStyle)
    {
        style = document.defaultView.getComputedStyle(el, "").getPropertyValue(property);
        if (style)
        {
            return style;
        }
    }
    property = Animator.camelize(property);
    if (el.currentStyle)
    {
        style = el.currentStyle[property];
    }
    return style || el.style[property]
}
CSSStyleSubject.ruleRe = /^\s*([a-zA-Z\-]+)\s*:\s*(\S(.+\S)?)\s*$/;
CSSStyleSubject.numericalRe = /^-?\d+(?:\.\d+)?(%|[a-zA-Z]{2})?$/;
CSSStyleSubject.discreteRe = /^\w+$/;
CSSStyleSubject.cssProperties = ['azimuth', 'background', 'background-attachment', 'background-color', 'background-image', 'background-position', 'background-repeat', 'border-collapse', 'border-color', 'border-spacing', 'border-style', 'border-top', 'border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color', 'border-top-style', 'border-right-style', 'border-bottom-style', 'border-left-style', 'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width', 'border-width', 'bottom', 'clear', 'clip', 'color', 'content', 'cursor', 'direction', 'display', 'elevation', 'empty-cells', 'css-float', 'font', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'height', 'left', 'letter-spacing', 'line-height', 'list-style', 'list-style-image', 'list-style-position', 'list-style-type', 'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left', 'max-height', 'max-width', 'min-height', 'min-width', 'orphans', 'outline', 'outline-color', 'outline-style', 'outline-width', 'overflow', 'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left', 'pause', 'position', 'right', 'size', 'table-layout', 'text-align', 'text-decoration', 'text-indent', 'text-shadow', 'text-transform', 'top', 'vertical-align', 'visibility', 'white-space', 'width', 'word-spacing', 'z-index', 'opacity', 'outline-offset', 'overflow-x', 'overflow-y'];
function AnimatorChain(animators, options)
{
    this.animators = animators;
    this.setOptions(options);
    for (var i = 0; i < this.animators.length; i++)
    {
        this.listenTo(this.animators[i]);
    }
    this.forwards = false;
    this.current = 0;
}
AnimatorChain.prototype = {
    setOptions: function(options)
    {
        this.options = Animator.applyDefaults({
            resetOnPlay: true
        },
    options);
    },
    play: function()
    {
        this.forwards = true;
        this.current = -1;
        if (this.options.resetOnPlay)
        {
            for (var i = 0; i < this.animators.length; i++)
            {
                this.animators[i].jumpTo(0);
            }
        }
        this.advance();
    },
    reverse: function()
    {
        this.forwards = false;
        this.current = this.animators.length;
        if (this.options.resetOnPlay)
        {
            for (var i = 0; i < this.animators.length; i++)
            {
                this.animators[i].jumpTo(1);
            }
        }
        this.advance();
    },
    toggle: function()
    {
        if (this.forwards)
        {
            this.seekTo(0);
        } else
        {
            this.seekTo(1);
        }
    },
    listenTo: function(animator)
    {
        var oldOnComplete = animator.options.onComplete;
        var _this = this;
        animator.options.onComplete = function()
        {
            if (oldOnComplete) oldOnComplete.call(animator);
            _this.advance();
        }
    },
    advance: function()
    {
        if (this.forwards)
        {
            if (this.animators[this.current + 1] == null) return;
            this.current++;
            this.animators[this.current].play();
        } else
        {
            if (this.animators[this.current - 1] == null) return;
            this.current--;
            this.animators[this.current].reverse();
        }
    },
    seekTo: function(target)
    {
        if (target <= 0)
        {
            this.forwards = false;
            this.animators[this.current].seekTo(0);
        } else
        {
            this.forwards = true;
            this.animators[this.current].seekTo(1);
        }
    }
}
function Accordion(options)
{
    this.setOptions(options);
    var selected = this.options.initialSection,
  current;
    if (this.options.rememberance)
    {
        current = document.location.hash.substring(1);
    }
    this.rememberanceTexts = [];
    this.ans = [];
    var _this = this;
    for (var i = 0; i < this.options.sections.length; i++)
    {
        var el = this.options.sections[i];
        var an = new Animator(this.options.animatorOptions);
        var from = this.options.from + (this.options.shift * i);
        var to = this.options.to + (this.options.shift * i);
        an.addSubject(new NumericalStyleSubject(el, this.options.property, from, to, this.options.units));
        an.jumpTo(0);
        var activator = this.options.getActivator(el);
        activator.index = i;
        activator.onclick = function()
        {
            _this.show(this.index)
        };
        this.ans[this.ans.length] = an;
        this.rememberanceTexts[i] = activator.innerHTML.replace(/\s/g, "");
        if (this.rememberanceTexts[i] === current)
        {
            selected = i;
        }
    }
    this.show(selected);
}
Accordion.prototype = {
    setOptions: function(options)
    {
        this.options = Object.extend({
            sections: null,
            getActivator: function(el)
            {
                return document.getElementById(el.getAttribute("activator"))
            },
            shift: 0,
            initialSection: 0,
            rememberance: true,
            animatorOptions: {}
        },
    options || {});
    },
    show: function(section)
    {
        for (var i = 0; i < this.ans.length; i++)
        {
            this.ans[i].seekTo(i > section ? 1 : 0);
        }
        if (this.options.rememberance)
        {
            document.location.hash = this.rememberanceTexts[section];
        }
    }
}
/** 
* @requires OpenLayers/Control.js
*/

/**
* Class: TISolution.Control.MeasureControl
*
* Inherits from:
*  - <OpenLayers.Control>
*/
TISolution.Control.MeasureControl =
  OpenLayers.Class(OpenLayers.Control, {
      EVENT_TYPES: ['measure', 'measurepartial', "modechanged"],
      /**  
      * Property: activeColor
      * {String}
      */
      activeColor: "darkblue",

      // DOM Elements

      /**
      * Property: layersDiv
      * {DOMElement} 
      */
      layersDiv: null,

      /** 
      * Property: baseLayersDiv
      * {DOMElement}
      */
      baseLayersDiv: null,

      /** 
      * Property: baseLayers
      * {Array(<OpenLayers.Layer>)}
      */
      baseLayers: null,

      /** 
      * Property: dataLayers
      * {Array(<OpenLayers.Layer>)} 
      */
      dataLayers: null,


      /** 
      * Property: minimizeDiv
      * {DOMElement} 
      */
      minimizeDiv: null,

      /** 
      * Property: maximizeDiv
      * {DOMElement} 
      */
      maximizeDiv: null,

      /**
      * APIProperty: ascending
      * {Boolean} 
      */
      ascending: true,

      measureControls: null,
      tools: null,
      elementOutput: null,

      /**
      * Constructor: TISolution.Control.MeasureControl
      * 
      * Parameters:
      * options - {Object}
      */
      initialize: function(options)
      {
          OpenLayers.Control.prototype.initialize.apply(this, arguments);
      },

      /**
      * APIMethod: destroy 
      */
      destroy: function()
      {
          OpenLayers.Event.stopObservingElement(this.div);
          OpenLayers.Event.stopObservingElement(this.minimizeDiv);
          OpenLayers.Event.stopObservingElement(this.maximizeDiv);
          OpenLayers.Control.prototype.destroy.apply(this, arguments);
      },


      handleMeasure: function(data)
      {
          data.sender.events.triggerEvent("measure", data.eventData);
      },


      handleMeasurePartial: function(data)
      {
          data.sender.events.triggerEvent("measurepartial", data.eventData);
      },


      setOutputElement: function(element)
      {
          this.elementOutput = element;
          var method = function(event)
          {
              var geometry = event.geometry;
              var units = event.units;
              var order = event.order;
              var measure = event.measure;
              var element = this.elementOutput;
              var out = "";
              if (order == 1)
              {
                  out += "Dist&acirc;ncia: " + measure.toFixed(3) + " " + units;
                  out += ", Dist&acirc;ncia do Grande Circulo: " + this.calcVincenty(geometry).toFixed(3) + " km";

              } else
              {

                  out += "<span>Area: " + measure.toFixed(3) + " " + units + "</span>";
              }
              element.innerHTML = out;
          };
          this.events.on(
                {
                    "measure": method,
                    "measurepartial": method,
                    "modechanged": function()
                    {
                        var element = this.elementOutput;
                        element.innerHTML = "";
                    }
                });
      },

      calcVincenty: function(geometry)
      {
          /**
          * Note: this function assumes geographic coordinates and
          *     will fail otherwise.  OpenLayers.Util.distVincenty takes
          *     two objects representing points with geographic coordinates
          *     and returns the geodesic distance between them (shortest
          *     distance between the two points on an ellipsoid) in *kilometers*.
          *
          * It is important to realize that the segments drawn on the map
          *     are *not* geodesics (or "great circle" segments).  This means
          *     that in general, the measure returned by this function
          *     will not represent the length of segments drawn on the map.
          */
          var dist = 0;
          for (var i = 1; i < geometry.components.length; i++)
          {
              var first = geometry.components[i - 1];
              var second = geometry.components[i];
              dist += OpenLayers.Util.distVincenty(
                            { lon: first.x, lat: first.y },
                            { lon: second.x, lat: second.y }
                        );
          }
          return dist;
      },

      /** 
      * Method: setMap
      *
      * Properties:
      * map - {<OpenLayers.Map>} 
      */
      setMap: function(map)
      {
          OpenLayers.Control.prototype.setMap.apply(this, arguments);


          // style the sketch fancy
          var sketchSymbolizers = {
              "Point": {
                  pointRadius: 4,
                  graphicName: "square",
                  fillColor: "white",
                  fillOpacity: 1,
                  strokeWidth: 1,
                  strokeOpacity: 1,
                  strokeColor: "#333333"
              },
              "Line": {
                  strokeWidth: 3,
                  strokeOpacity: 1,
                  strokeColor: "#666666",
                  strokeDashstyle: "dash"
              },
              "Polygon": {
                  strokeWidth: 2,
                  strokeOpacity: 1,
                  strokeColor: "#666666",
                  fillColor: "white",
                  fillOpacity: 0.3
              }
          };

          var style = new OpenLayers.Style();
          style.addRules([new OpenLayers.Rule({ symbolizer: sketchSymbolizers })]);
          var styleMap = new OpenLayers.StyleMap({ "default": style });

          var options = {
              handlerOptions: {
                  style: "default", // this forces default render intent
                  layerOptions: { styleMap: styleMap },
                  persist: true
              }
          };

          this.measureControls = {
              line: new OpenLayers.Control.Measure(OpenLayers.Handler.Path, options),
              polygon: new OpenLayers.Control.Measure(OpenLayers.Handler.Polygon, options)
          };

          var control;
          for (var key in this.measureControls)
          {
              control = this.measureControls[key];

              var methodMeasure = function(event) { var data = { eventData: event, sender: this }; this.handleMeasure(data); };
              control.events.register("measure", this, methodMeasure);
              var methodMeasurePartial = function(event) { var data = { eventData: event, sender: this }; this.handleMeasurePartial(data); };
              control.events.register("measurepartial", this, methodMeasurePartial);
              this.map.addControl(control);
          }
      },

      /**
      * Method: draw
      *
      * Returns:
      * {DOMElement} A reference to the DIV DOMElement containing the 
      *     switcher tabs.
      */
      draw: function()
      {
          OpenLayers.Control.prototype.draw.apply(this);

          // create layout divs
          this.loadContents();

          // set mode to minimize
          if (!this.outsideViewport)
          {
              this.minimizeControl();
          }

          // populate div with current info
          this.redraw();

          return this.div;
      },


      /**
      * Method: checkRedraw
      * Checks if the layer state has changed since the last redraw() call.
      * 
      * Returns:
      * {Boolean} The layer state changed since the last redraw() call. 
      */
      checkRedraw: function()
      {
          var redraw = true;
          return redraw;
      },

      /** 
      * Method: redraw
      * Goes through and takes the current state of the Map and rebuilds the
      *     control to display that state. Groups base layers into a 
      *     radio-button group and lists each data layer with a checkbox.
      *
      * Returns: 
      * {DOMElement} A reference to the DIV DOMElement containing the control
      */
      redraw: function()
      {
          //if the state hasn't changed since last redraw, no need 
          // to do anything. Just return the existing div.
          if (!this.checkRedraw())
          {
              return this.div;
          }


          this.tools =
          {
              none: {
                  type: "none",
                  display: "Navegar",
                  control: null,
                  inputElem: null
              },
              line: {
                  type: "line",
                  display: "Calcular Dist&acirc;ncia",
                  control: this.measureControls.line,
                  inputElem: null
              },
              polygon: {
                  type: "polygon",
                  display: "Calcular Area",
                  control: this.measureControls.polygon,
                  inputElem: null
              }
          };

          for (var property in this.tools)
          {
              var option = this.tools[property];

              // create input element
              var inputElem = document.createElement("input");
              inputElem.id = "radio_measure"; //this.id + "_input_" + option.type;
              inputElem.name = "baseLayers";
              inputElem.type = "radio";
              inputElem.value = option.type;
              inputElem.defaultChecked = (option.type == "none");
              option.inputElem = inputElem;

              var context = {
                  'tool': option,
                  'MeasureControl': this
              };

              OpenLayers.Event.observe(inputElem, "mouseup",
                    OpenLayers.Function.bindAsEventListener(this.onInputClick, context));

              // create span
              var labelSpan = document.createElement("span");
              labelSpan.innerHTML = option.display;
              labelSpan.style.verticalAlign = (true) ? "bottom" : "baseline";
              OpenLayers.Event.observe(labelSpan, "click",
                    OpenLayers.Function.bindAsEventListener(this.onInputClick, context));

              // create line break
              var br = document.createElement("br");


              var groupDiv = this.baseLayersDiv;
              groupDiv.appendChild(inputElem);
              groupDiv.appendChild(labelSpan);
              groupDiv.appendChild(br);

              // if no baselayers, dont display the baselayer label
              this.baseLbl.style.display = (true) ? "" : "none";
          }

          this.tools.none.inputElem.checked = true;
          return this.div;
      },

      /** 
      * Method:
      * A label has been clicked, check or uncheck its corresponding input
      * 
      * Parameters:
      * e - {Event} 
      *
      * Context:  
      *  - {DOMElement} inputElem
      *  - {<TISolution.Control.MeasureControl>} layerSwitcher
      *  - {<OpenLayers.Layer>} layer
      */

      onInputClick: function(e)
      {
          if (!this.tool.inputElem.disabled)
          {
              for (var property in this.MeasureControl.tools)
              {
                  var option = this.MeasureControl.tools[property];

                  if (this.tool != option)
                  {
                      option.inputElem.checked = false;
                      if (option.control)
                          option.control.deactivate();
                  }
                  else
                  {
                      option.inputElem.checked = true;
                      if (this.tool.type != "none")
                          this.MeasureControl.measureControls[this.tool.type].activate();
                  }

                  this.MeasureControl.events.triggerEvent("modechanged", this.tool.type);
              }
          }
          OpenLayers.Event.stop(e);
      },

      /**
      * Method: onLayerClick
      * Need to update the map accordingly whenever user clicks in either of
      *     the layers.
      * 
      * Parameters: 
      * e - {Event} 
      */
      onLayerClick: function(e)
      {
          this.updateMap();
      },


      /** 
      * Method: updateMap
      * Cycles through the loaded data and base layer input arrays and makes
      *     the necessary calls to the Map object such that that the map's 
      *     visual state corresponds to what the user has selected in 
      *     the control.
      */
      updateMap: function()
      {

          // set the newly selected base layer        
          for (var i = 0, len = this.baseLayers.length; i < len; i++)
          {
              var layerEntry = this.baseLayers[i];
              if (layerEntry.inputElem.checked)
              {
                  this.map.setBaseLayer(layerEntry.layer, false);
              }
          }

          // set the correct visibilities for the overlays
          for (var i = 0, len = this.dataLayers.length; i < len; i++)
          {
              var layerEntry = this.dataLayers[i];
              layerEntry.layer.setVisibility(layerEntry.inputElem.checked);
          }

      },

      /** 
      * Method: maximizeControl
      * Set up the labels and divs for the control
      * 
      * Parameters:
      * e - {Event} 
      */
      maximizeControl: function(e)
      {

          //HACK HACK HACK - find a way to auto-size this layerswitcher
          this.div.style.width = "20em";
          this.div.style.height = "";

          this.showControls(false);

          if (e != null)
          {
              OpenLayers.Event.stop(e);
          }
      },

      /** 
      * Method: minimizeControl
      * Hide all the contents of the control, shrink the size, 
      *     add the maximize icon
      *
      * Parameters:
      * e - {Event} 
      */
      minimizeControl: function(e)
      {

          this.div.style.width = "0px";
          this.div.style.height = "0px";

          this.showControls(true);

          if (e != null)
          {
              OpenLayers.Event.stop(e);
          }
      },

      /**
      * Method: showControls
      * Hide/Show all LayerSwitcher controls depending on whether we are
      *     minimized or not
      * 
      * Parameters:
      * minimize - {Boolean}
      */
      showControls: function(minimize)
      {

          this.maximizeDiv.style.display = minimize ? "" : "none";
          this.minimizeDiv.style.display = minimize ? "none" : "";

          this.layersDiv.style.display = minimize ? "none" : "";
      },

      /** 
      * Method: loadContents
      * Set up the labels and divs for the control
      */
      loadContents: function()
      {

          //configure main div
          this.div.style.position = "absolute";
          this.div.style.top = "25px";
          this.div.style.right = "0px";
          this.div.style.left = "";
          this.div.style.fontFamily = "sans-serif";
          this.div.style.fontWeight = "bold";
          this.div.style.marginTop = "3px";
          this.div.style.marginLeft = "3px";
          this.div.style.marginBottom = "3px";
          this.div.style.fontSize = "smaller";
          this.div.style.color = "white";
          this.div.style.backgroundColor = "transparent";

          OpenLayers.Event.observe(this.div, "mouseup", OpenLayers.Function.bindAsEventListener(this.mouseUp, this));
          OpenLayers.Event.observe(this.div, "click", this.ignoreEvent);
          OpenLayers.Event.observe(this.div, "mousedown", OpenLayers.Function.bindAsEventListener(this.mouseDown, this));
          OpenLayers.Event.observe(this.div, "dblclick", this.ignoreEvent);

          // layers list div        
          this.layersDiv = document.createElement("div");
          this.layersDiv.id = this.id + "_layersDiv";
          this.layersDiv.style.paddingTop = "5px";
          this.layersDiv.style.paddingLeft = "10px";
          this.layersDiv.style.paddingBottom = "5px";
          this.layersDiv.style.paddingRight = "75px";
          this.layersDiv.style.backgroundColor = this.activeColor;

          // had to set width/height to get transparency in IE to work.
          // thanks -- http://jszen.blogspot.com/2005/04/ie6-opacity-filter-caveat.html
          //
          this.layersDiv.style.width = "100%";
          this.layersDiv.style.height = "100%";

          this.baseLbl = document.createElement("div");
          //this.baseLbl.innerHTML = OpenLayers.i18n("baseLayer");
          this.baseLbl.innerHTML = OpenLayers.i18n("Ferramentas");
          this.baseLbl.style.marginTop = "3px";
          this.baseLbl.style.marginLeft = "3px";
          this.baseLbl.style.marginBottom = "3px";

          this.baseLayersDiv = document.createElement("div");
          this.baseLayersDiv.style.paddingLeft = "10px";
          /*OpenLayers.Event.observe(this.baseLayersDiv, "click", 
          OpenLayers.Function.bindAsEventListener(this.onLayerClick, this));
          */

          if (this.ascending)
          {
              this.layersDiv.appendChild(this.baseLbl);
              this.layersDiv.appendChild(this.baseLayersDiv);
          } else
          {
              this.layersDiv.appendChild(this.baseLbl);
              this.layersDiv.appendChild(this.baseLayersDiv);
          }

          this.div.appendChild(this.layersDiv);

          OpenLayers.Rico.Corner.round(this.div, {
              corners: "tl bl",
              bgColor: "transparent",
              color: this.activeColor,
              blend: false
          });

          OpenLayers.Rico.Corner.changeOpacity(this.layersDiv, 0.75);

          var imgLocation = OpenLayers.Util.getImagesLocation();
          var sz = new OpenLayers.Size(18, 18);

          // maximize button div
          var img = imgLocation + 'layer-switcher-maximize.png';
          this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MaximizeDiv", null, sz, img, "absolute");
          this.maximizeDiv.style.top = "55px";
          this.maximizeDiv.style.right = "0px";
          this.maximizeDiv.style.left = "";
          this.maximizeDiv.style.display = "none";
          OpenLayers.Event.observe(this.maximizeDiv, "click", OpenLayers.Function.bindAsEventListener(this.maximizeControl, this));

          this.div.appendChild(this.maximizeDiv);

          // minimize button div
          var img = imgLocation + 'layer-switcher-minimize.png';
          var sz = new OpenLayers.Size(18, 18);
          this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MinimizeDiv", null, sz, img, "absolute");
          this.minimizeDiv.style.top = "55px";
          this.minimizeDiv.style.right = "0px";
          this.minimizeDiv.style.left = "";
          this.minimizeDiv.style.display = "none";
          OpenLayers.Event.observe(this.minimizeDiv, "click", OpenLayers.Function.bindAsEventListener(this.minimizeControl, this));

          this.div.appendChild(this.minimizeDiv);
      },

      /** 
      * Method: ignoreEvent
      * 
      * Parameters:
      * evt - {Event} 
      */
      ignoreEvent: function(evt)
      {
          OpenLayers.Event.stop(evt);
      },

      /** 
      * Method: mouseDown
      * Register a local 'mouseDown' flag so that we'll know whether or not
      *     to ignore a mouseUp event
      * 
      * Parameters:
      * evt - {Event}
      */
      mouseDown: function(evt)
      {
          this.isMouseDown = true;
          this.ignoreEvent(evt);
      },

      /** 
      * Method: mouseUp
      * If the 'isMouseDown' flag has been set, that means that the drag was 
      *     started from within the LayerSwitcher control, and thus we can 
      *     ignore the mouseup. Otherwise, let the Event continue.
      *  
      * Parameters:
      * evt - {Event} 
      */
      mouseUp: function(evt)
      {
          if (this.isMouseDown)
          {
              this.isMouseDown = false;
              this.ignoreEvent(evt);
          }
      },

      CLASS_NAME: "TISolution.Control.MeasureControl"
  });
/** JSONScriptRequest library from Yahoo! jsr_class.js

Software License Agreement

Yahoo! SDK Copyright (c) 2005, Yahoo! Inc.
All rights reserved.

Redistribution and use of the Yahoo! SDK in source and
binary forms, with or without modification, are permitted
provided that the following conditions are met:

* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.

* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.

* Neither the name of Yahoo! Inc. nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of Yahoo! Inc.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

(The foregoing Agreement is the BSD License, Copyright
2005 by the Open Source Institute)

**/
function JSONscriptRequest(fullUrl)
{
    this.fullUrl = fullUrl;
    this.noCacheIE = '&noCacheIE=' + (new Date()).getTime();
    this.headLoc = document.getElementsByTagName("head").item(0);
    this.scriptId = 'JscriptId' + JSONscriptRequest.scriptCounter++;
}
JSONscriptRequest.scriptCounter = 1;
JSONscriptRequest.prototype.buildScriptTag = function()
{
    this.scriptObj = document.createElement("script");
    this.scriptObj.setAttribute("type", "text/javascript");
    this.scriptObj.setAttribute("charset", "utf-8");
    this.scriptObj.setAttribute("src", this.fullUrl + this.noCacheIE);
    this.scriptObj.setAttribute("id", this.scriptId);
}
JSONscriptRequest.prototype.removeScriptTag = function()
{
    this.headLoc.removeChild(this.scriptObj);
}
JSONscriptRequest.prototype.addScriptTag = function()
{
    this.headLoc.appendChild(this.scriptObj);
}
/**  
*  
*  Contains portions of Rico <http://openrico.org/>
* 
*  Copyright (c) 2005 Sabre Airline Solutions  
*  
*  Licensed under the Apache License, Version 2.0 (the "License"); you
*  may not use this file except in compliance with the License. You
*  may obtain a copy of the License at
*  
*         http://www.apache.org/licenses/LICENSE-2.0  
*  
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
*  implied. See the License for the specific language governing
*  permissions and limitations under the License. 
*
**/
OpenLayers.Rico = new Object();
OpenLayers.Rico.Corner = {
    round: function(e, options)
    {
        e = OpenLayers.Util.getElement(e);
        this._setOptions(options);
        var color = this.options.color;
        if (this.options.color == "fromElement") color = this._background(e);
        var bgColor = this.options.bgColor;
        if (this.options.bgColor == "fromParent") bgColor = this._background(e.offsetParent);
        this._roundCornersImpl(e, color, bgColor);
    },
    changeColor: function(theDiv, newColor)
    {
        theDiv.style.backgroundColor = newColor;
        var spanElements = theDiv.parentNode.getElementsByTagName("span");
        for (var currIdx = 0; currIdx < spanElements.length; currIdx++)
        {
            spanElements[currIdx].style.backgroundColor = newColor;
        }
    },
    changeOpacity: function(theDiv, newOpacity)
    {
        var mozillaOpacity = newOpacity;
        var ieOpacity = 'alpha(opacity=' + newOpacity * 100 + ')';
        theDiv.style.opacity = mozillaOpacity;
        theDiv.style.filter = ieOpacity;
        var spanElements = theDiv.parentNode.getElementsByTagName("span");
        for (var currIdx = 0; currIdx < spanElements.length; currIdx++)
        {
            spanElements[currIdx].style.opacity = mozillaOpacity;
            spanElements[currIdx].style.filter = ieOpacity;
        }
    },
    reRound: function(theDiv, options)
    {
        var topRico = theDiv.parentNode.childNodes[0];
        var bottomRico = theDiv.parentNode.childNodes[2];
        theDiv.parentNode.removeChild(topRico);
        theDiv.parentNode.removeChild(bottomRico);
        this.round(theDiv.parentNode, options);
    },
    _roundCornersImpl: function(e, color, bgColor)
    {
        if (this.options.border) this._renderBorder(e, bgColor);
        if (this._isTopRounded()) this._roundTopCorners(e, color, bgColor);
        if (this._isBottomRounded()) this._roundBottomCorners(e, color, bgColor);
    },
    _renderBorder: function(el, bgColor)
    {
        var borderValue = "1px solid " + this._borderColor(bgColor);
        var borderL = "border-left: " + borderValue;
        var borderR = "border-right: " + borderValue;
        var style = "style='" + borderL + ";" + borderR + "'";
        el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>"
    },
    _roundTopCorners: function(el, color, bgColor)
    {
        var corner = this._createCorner(bgColor);
        for (var i = 0; i < this.options.numSlices; i++) corner.appendChild(this._createCornerSlice(color, bgColor, i, "top"));
        el.style.paddingTop = 0;
        el.insertBefore(corner, el.firstChild);
    },
    _roundBottomCorners: function(el, color, bgColor)
    {
        var corner = this._createCorner(bgColor);
        for (var i = (this.options.numSlices - 1); i >= 0; i--) corner.appendChild(this._createCornerSlice(color, bgColor, i, "bottom"));
        el.style.paddingBottom = 0;
        el.appendChild(corner);
    },
    _createCorner: function(bgColor)
    {
        var corner = document.createElement("div");
        corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
        return corner;
    },
    _createCornerSlice: function(color, bgColor, n, position)
    {
        var slice = document.createElement("span");
        var inStyle = slice.style;
        inStyle.backgroundColor = color;
        inStyle.display = "block";
        inStyle.height = "1px";
        inStyle.overflow = "hidden";
        inStyle.fontSize = "1px";
        var borderColor = this._borderColor(color, bgColor);
        if (this.options.border && n == 0)
        {
            inStyle.borderTopStyle = "solid";
            inStyle.borderTopWidth = "1px";
            inStyle.borderLeftWidth = "0px";
            inStyle.borderRightWidth = "0px";
            inStyle.borderBottomWidth = "0px";
            inStyle.height = "0px";
            inStyle.borderColor = borderColor;
        } else if (borderColor)
        {
            inStyle.borderColor = borderColor;
            inStyle.borderStyle = "solid";
            inStyle.borderWidth = "0px 1px";
        }
        if (!this.options.compact && (n == (this.options.numSlices - 1))) inStyle.height = "2px";
        this._setMargin(slice, n, position);
        this._setBorder(slice, n, position);
        return slice;
    },
    _setOptions: function(options)
    {
        this.options = {
            corners: "all",
            color: "fromElement",
            bgColor: "fromParent",
            blend: true,
            border: false,
            compact: false
        }
        OpenLayers.Util.extend(this.options, options || {});
        this.options.numSlices = this.options.compact ? 2 : 4;
        if (this._isTransparent()) this.options.blend = false;
    },
    _whichSideTop: function()
    {
        if (this._hasString(this.options.corners, "all", "top")) return "";
        if (this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0) return "";
        if (this.options.corners.indexOf("tl") >= 0) return "left";
        else if (this.options.corners.indexOf("tr") >= 0) return "right";
        return "";
    },
    _whichSideBottom: function()
    {
        if (this._hasString(this.options.corners, "all", "bottom")) return "";
        if (this.options.corners.indexOf("bl") >= 0 && this.options.corners.indexOf("br") >= 0) return "";
        if (this.options.corners.indexOf("bl") >= 0) return "left";
        else if (this.options.corners.indexOf("br") >= 0) return "right";
        return "";
    },
    _borderColor: function(color, bgColor)
    {
        if (color == "transparent") return bgColor;
        else if (this.options.border) return this.options.border;
        else if (this.options.blend) return this._blend(bgColor, color);
        else return "";
    },
    _setMargin: function(el, n, corners)
    {
        var marginSize = this._marginSize(n);
        var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
        if (whichSide == "left")
        {
            el.style.marginLeft = marginSize + "px";
            el.style.marginRight = "0px";
        } else if (whichSide == "right")
        {
            el.style.marginRight = marginSize + "px";
            el.style.marginLeft = "0px";
        } else
        {
            el.style.marginLeft = marginSize + "px";
            el.style.marginRight = marginSize + "px";
        }
    },
    _setBorder: function(el, n, corners)
    {
        var borderSize = this._borderSize(n);
        var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
        if (whichSide == "left")
        {
            el.style.borderLeftWidth = borderSize + "px";
            el.style.borderRightWidth = "0px";
        } else if (whichSide == "right")
        {
            el.style.borderRightWidth = borderSize + "px";
            el.style.borderLeftWidth = "0px";
        } else
        {
            el.style.borderLeftWidth = borderSize + "px";
            el.style.borderRightWidth = borderSize + "px";
        }
        if (this.options.border != false) el.style.borderLeftWidth = borderSize + "px";
        el.style.borderRightWidth = borderSize + "px";
    },
    _marginSize: function(n)
    {
        if (this._isTransparent()) return 0;
        var marginSizes = [5, 3, 2, 1];
        var blendedMarginSizes = [3, 2, 1, 0];
        var compactMarginSizes = [2, 1];
        var smBlendedMarginSizes = [1, 0];
        if (this.options.compact && this.options.blend) return smBlendedMarginSizes[n];
        else if (this.options.compact) return compactMarginSizes[n];
        else if (this.options.blend) return blendedMarginSizes[n];
        else return marginSizes[n];
    },
    _borderSize: function(n)
    {
        var transparentBorderSizes = [5, 3, 2, 1];
        var blendedBorderSizes = [2, 1, 1, 1];
        var compactBorderSizes = [1, 0];
        var actualBorderSizes = [0, 2, 0, 0];
        if (this.options.compact && (this.options.blend || this._isTransparent())) return 1;
        else if (this.options.compact) return compactBorderSizes[n];
        else if (this.options.blend) return blendedBorderSizes[n];
        else if (this.options.border) return actualBorderSizes[n];
        else if (this._isTransparent()) return transparentBorderSizes[n];
        return 0;
    },
    _hasString: function(str)
    {
        for (var i = 1; i < arguments.length; i++) if (str.indexOf(arguments[i]) >= 0) return true;
        return false;
    },
    _blend: function(c1, c2)
    {
        var cc1 = OpenLayers.Rico.Color.createFromHex(c1);
        cc1.blend(OpenLayers.Rico.Color.createFromHex(c2));
        return cc1;
    },
    _background: function(el)
    {
        try
        {
            return OpenLayers.Rico.Color.createColorFromBackground(el).asHex();
        } catch (err)
        {
            return "#ffffff";
        }
    },
    _isTransparent: function()
    {
        return this.options.color == "transparent";
    },
    _isTopRounded: function()
    {
        return this._hasString(this.options.corners, "all", "top", "tl", "tr");
    },
    _isBottomRounded: function()
    {
        return this._hasString(this.options.corners, "all", "bottom", "bl", "br");
    },
    _hasSingleTextChild: function(el)
    {
        return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3;
    }
}
OpenLayers.Rico.Color = OpenLayers.Class({
    initialize: function(red, green, blue)
    {
        this.rgb = {
            r: red,
            g: green,
            b: blue
        };
    },
    setRed: function(r)
    {
        this.rgb.r = r;
    },
    setGreen: function(g)
    {
        this.rgb.g = g;
    },
    setBlue: function(b)
    {
        this.rgb.b = b;
    },
    setHue: function(h)
    {
        var hsb = this.asHSB();
        hsb.h = h;
        this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
    },
    setSaturation: function(s)
    {
        var hsb = this.asHSB();
        hsb.s = s;
        this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
    },
    setBrightness: function(b)
    {
        var hsb = this.asHSB();
        hsb.b = b;
        this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
    },
    darken: function(percent)
    {
        var hsb = this.asHSB();
        this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent, 0));
    },
    brighten: function(percent)
    {
        var hsb = this.asHSB();
        this.rgb = OpenLayers.Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent, 1));
    },
    blend: function(other)
    {
        this.rgb.r = Math.floor((this.rgb.r + other.rgb.r) / 2);
        this.rgb.g = Math.floor((this.rgb.g + other.rgb.g) / 2);
        this.rgb.b = Math.floor((this.rgb.b + other.rgb.b) / 2);
    },
    isBright: function()
    {
        var hsb = this.asHSB();
        return this.asHSB().b > 0.5;
    },
    isDark: function()
    {
        return !this.isBright();
    },
    asRGB: function()
    {
        return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
    },
    asHex: function()
    {
        return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
    },
    asHSB: function()
    {
        return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
    },
    toString: function()
    {
        return this.asHex();
    }
});
OpenLayers.Rico.Color.createFromHex = function(hexCode)
{
    if (hexCode.length == 4)
    {
        var shortHexCode = hexCode;
        var hexCode = '#';
        for (var i = 1; i < 4; i++) hexCode += (shortHexCode.charAt(i) + shortHexCode.charAt(i));
    }
    if (hexCode.indexOf('#') == 0) hexCode = hexCode.substring(1);
    var red = hexCode.substring(0, 2);
    var green = hexCode.substring(2, 4);
    var blue = hexCode.substring(4, 6);
    return new OpenLayers.Rico.Color(parseInt(red, 16), parseInt(green, 16), parseInt(blue, 16));
}
OpenLayers.Rico.Color.createColorFromBackground = function(elem)
{
    var actualColor = RicoUtil.getElementsComputedStyle(OpenLayers.Util.getElement(elem), "backgroundColor", "background-color");
    if (actualColor == "transparent" && elem.parentNode) return OpenLayers.Rico.Color.createColorFromBackground(elem.parentNode);
    if (actualColor == null) return new OpenLayers.Rico.Color(255, 255, 255);
    if (actualColor.indexOf("rgb(") == 0)
    {
        var colors = actualColor.substring(4, actualColor.length - 1);
        var colorArray = colors.split(",");
        return new OpenLayers.Rico.Color(parseInt(colorArray[0]), parseInt(colorArray[1]), parseInt(colorArray[2]));
    } else if (actualColor.indexOf("#") == 0)
    {
        return OpenLayers.Rico.Color.createFromHex(actualColor);
    } else return new OpenLayers.Rico.Color(255, 255, 255);
}
OpenLayers.Rico.Color.HSBtoRGB = function(hue, saturation, brightness)
{
    var red = 0;
    var green = 0;
    var blue = 0;
    if (saturation == 0)
    {
        red = parseInt(brightness * 255.0 + 0.5);
        green = red;
        blue = red;
    } else
    {
        var h = (hue - Math.floor(hue)) * 6.0;
        var f = h - Math.floor(h);
        var p = brightness * (1.0 - saturation);
        var q = brightness * (1.0 - saturation * f);
        var t = brightness * (1.0 - (saturation * (1.0 - f)));
        switch (parseInt(h))
        {
            case 0:
                red = (brightness * 255.0 + 0.5);
                green = (t * 255.0 + 0.5);
                blue = (p * 255.0 + 0.5);
                break;
            case 1:
                red = (q * 255.0 + 0.5);
                green = (brightness * 255.0 + 0.5);
                blue = (p * 255.0 + 0.5);
                break;
            case 2:
                red = (p * 255.0 + 0.5);
                green = (brightness * 255.0 + 0.5);
                blue = (t * 255.0 + 0.5);
                break;
            case 3:
                red = (p * 255.0 + 0.5);
                green = (q * 255.0 + 0.5);
                blue = (brightness * 255.0 + 0.5);
                break;
            case 4:
                red = (t * 255.0 + 0.5);
                green = (p * 255.0 + 0.5);
                blue = (brightness * 255.0 + 0.5);
                break;
            case 5:
                red = (brightness * 255.0 + 0.5);
                green = (p * 255.0 + 0.5);
                blue = (q * 255.0 + 0.5);
                break;
        }
    }
    return {
        r: parseInt(red),
        g: parseInt(green),
        b: parseInt(blue)
    };
}
OpenLayers.Rico.Color.RGBtoHSB = function(r, g, b)
{
    var hue;
    var saturation;
    var brightness;
    var cmax = (r > g) ? r : g;
    if (b > cmax) cmax = b;
    var cmin = (r < g) ? r : g;
    if (b < cmin) cmin = b;
    brightness = cmax / 255.0;
    if (cmax != 0) saturation = (cmax - cmin) / cmax;
    else saturation = 0;
    if (saturation == 0) hue = 0;
    else
    {
        var redc = (cmax - r) / (cmax - cmin);
        var greenc = (cmax - g) / (cmax - cmin);
        var bluec = (cmax - b) / (cmax - cmin);
        if (r == cmax) hue = bluec - greenc;
        else if (g == cmax) hue = 2.0 + redc - bluec;
        else hue = 4.0 + greenc - redc;
        hue = hue / 6.0;
        if (hue < 0) hue = hue + 1.0;
    }
    return {
        h: hue,
        s: saturation,
        b: brightness
    };
}
