//This prototype is provided by the Mozilla foundation and
//is distributed under the MIT license.
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
if (!Array.prototype.map)
{
  Array.prototype.map = function(fun /*, thisp*/)
  {
    var len = this.length;
    if (typeof fun != "function")
      throw new TypeError();

    var res = new Array(len);
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this)
        res[i] = fun.call(thisp, this[i], i, this);
    }

    return res;
  };
}

GOverlay.create = function(data,options)
{
    switch(data.type)
    {
        case 'PolygonMarker': return GPolygon.create(data,options);
        case 'PolylineMarker': return GPolyline.create(data,options);
        default: return GMarker.create(data,options);
    }
}

GMarker.create = function(data,options) 
{
    var point = new GLatLng(parseFloat(data.latitude),parseFloat(data.longitude));
    var object = new GMarker(point,options);
    object.id = data.id;
    object.zoom_min = data.zoom_min;
    object.zoom_max = data.zoom_max;
    object.type = data.type;
    return object;
}

GPolygon.create = function(data,options)
{
    var p = [];
    if(data.encoded_path) { p = decodeLine(data.encoded_path); }
    var object = new GPolygon(p,'#ff0000', 2, 0.7, '#ff0000', 0.2);
    object.id = data.id;
    object.zoom_min = data.zoom_min;
    object.zoom_max = data.zoom_max;
    return object;
}

GPolyline.create = function(data,options)
{
    var p = [];
    if(data.encoded_path) { p = decodeLine(data.encoded_path); }
    var object = new GPolyline(p,'#0000ff', 2, 0.7);
    object.id = data.id;
    object.zoom_min = data.zoom_min;
    object.zoom_max = data.zoom_max;
    return object;    
}

GIcon.create = function(object)
{
    var data = JSON.parse(object.json);
    var f = new GIcon();
    f.image = data.image;
    f.shadow = data.shadow;
    f.hilight = data.hilight;
    f.id = object.id;
    f.is_default = object.is_default;
    f.sequence_number = object.sequence_number;
    
    if(data.iconSize)
    {
        f.iconSize = new GSize(parseInt(data.iconSize.width),parseInt(data.iconSize.height));
    }
    if(data.shadowSize)
    {
        f.shadowSize = new GSize(parseInt(data.shadowSize.width),parseInt(data.shadowSize.height));
    }
    if(data.iconAnchor)
    {
        f.iconAnchor = new GPoint(parseInt(data.iconAnchor.x),parseInt(data.iconAnchor.y));
    }
    if(data.infoWindowAnchor)
    {
        f.infoWindowAnchor = new GPoint(parseInt(data.infoWindowAnchor.x),parseInt(data.infoWindowAnchor.y));
    }
    if(data.infoShadowAnchor)
    {
        f.infoShadowAnchor = new GPoint(parseInt(data.infoShadowAnchor.x),parseInt(data.infoShadowAnchor.y));
    }
    return f;
    
}

GMarker.prototype.asJSON = function()
{    
    return {
        type: this.type,
        id: this.id, 
        zoom_min: this.zoom_min,
        zoom_max: this.zoom_max, 
        latitude: (this.getLatLng().lat()),
        longitude: (this.getLatLng().lng()),
        icon_id: this.getIcon().id
    };
}

GPolygon.prototype.asJSON = function()
{    
    path = this.encoded_path();
    return this.getBounds() != null ? { 
    type: "PolygonMarker",
    id: this.id, 
    zoom_min: this.zoom_min, 
    zoom_max: this.zoom_max, 
    latitude: (this.getBounds().getCenter().lat()),
    longitude: (this.getBounds().getCenter().lng()),
    bounds_north: (this.getBounds().getNorthEast().lat()),
    bounds_east: (this.getBounds().getNorthEast().lng()),
    bounds_west: (this.getBounds().getSouthWest().lng()),
    bounds_south: (this.getBounds().getSouthWest().lat()),
    encoded_path: path.encoded_path,
    encoded_levels: path.encoded_levels,
    fill_style: JSON.stringify(this.fillStyle),
    stroke_style: JSON.stringify(this.strokeStyle)
    } : {    
    type: "PolygonMarker",
    id: this.id, 
    zoom_min: this.zoom_min, 
    zoom_max: this.zoom_max,
    fill_style: JSON.stringify(this.fillStyle),
    stroke_style: JSON.stringify(this.strokeStyle)
    };
}

GPolyline.prototype.asJSON = function()
{    
    path = this.encoded_path();
    return this.getBounds() != null ? { 
    type: "PolylineMarker",
    id: this.id, 
    zoom_min: this.zoom_min, 
    zoom_max: this.zoom_max, 
    latitude: (this.getBounds().getCenter().lat()),
    longitude: (this.getBounds().getCenter().lng()),
    bounds_north: (this.getBounds().getNorthEast().lat()),
    bounds_east: (this.getBounds().getNorthEast().lng()),
    bounds_west: (this.getBounds().getSouthWest().lng()),
    bounds_south: (this.getBounds().getSouthWest().lat()),
    encoded_path: path.encoded_path,
    encoded_levels: path.encoded_levels,
    stroke_style: JSON.stringify(this.strokeStyle)
    } : {    
    type: "PolylineMarker",
    id: this.id, 
    zoom_min: this.zoom_min, 
    zoom_max: this.zoom_max,
    stroke_style: JSON.stringify(this.strokeStyle)
    };
}

GMarker.prototype.getBounds = function()
{
    return new GLatLngBounds(this.getLatLng(),this.getLatLng());
}

GMarker.prototype.hilight = function(should)
{
    if(should)
    {
        for(i in document.markers)
        {
            (document.markers[i]).hilight(false);
        }
        this.setImage(this.getIcon().hilight);
        document.selected_marker = this;
    }
    else
    {
        this.setImage(this.getIcon().image);
        if(this === document.selected_marker)
        {
            document.selected_marker = null;
        }
    }
}

GPolygon.prototype.hilight = function(should)
{
    if(should)
    {
        for(i in document.markers)
        {
            (document.markers[i]).hilight(false);
        }
        this.setStrokeStyle({color: "#FF9900"});
        this.setFillStyle({color: "#FF00FF"});
        this.enableEditing();
        document.selected_marker = this;
    }
    else
    {
        this.setStrokeStyle({color: "#FF0000"});
        this.setFillStyle({color: "#00FF99"});
        this.disableEditing();
        if(this === document.selected_marker)
        {
            document.selected_marker = null;
        }
            
    }
}

GPolyline.prototype.hilight = function(should)
{
    if(should)
    {
        for(i in document.markers)
        {
            (document.markers[i]).hilight(false);
        }
        this.setStrokeStyle({color: "#0099FF", weight: 2});
        this.enableEditing();
        document.selected_marker = this;
    }
    else
    {
        this.setStrokeStyle({color: "#0000FF", weight: 3});
        this.disableEditing();
        if(this === document.selected_marker)
        {
            document.selected_marker = null;
        }
        
    }
}


/*
function make_icon(color)
{
    var f = new GIcon();
    //f.image = "http://labs.google.com/ridefinder/images/mm_20_" + color + ".png";
    //f.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
    f.image = "/Images/mm_20_" + color + ".png";
    f.shadow = "/Images/mm_20_shadow.png";
    f.iconSize = new GSize(12,20);
    f.shadowSize = new GSize(22,20);
    f.iconAnchor = new GPoint(6,20);
    f.infoWindowAnchor = new GPoint(6,1);
    f.infoShadowAnchor = new GPoint(13,13);
    return f;
}
*/

// Encode a signed number in the encode format.
function encodeSignedNumber(num) {
    var sgn_num = num << 1;
    
    if (num < 0) {
        sgn_num = ~(sgn_num);
    }
    
    return(encodeNumber(sgn_num));
}

// Encode an unsigned number in the encode format.
function encodeNumber(num) {
    var encodeString = "";
    
    while (num >= 0x20) {
        encodeString += (String.fromCharCode((0x20 | (num & 0x1f)) + 63));
        num >>= 5;
    }
    
    encodeString += (String.fromCharCode(num + 63));
    return encodeString;
}

function encoded_path()
{
    var encoded_points = "";
    var encoded_levels = "";
    var plat = 0;
    var plng = 0;

    for(var i = 0; i < this.getVertexCount(); ++i) 
    {
        var point = this.getVertex(i);
        var lat = point.lat();
        var lng = point.lng();
        var level = this.zoom_min;
        
        var late5 = Math.floor(lat * 1e5);
        var lnge5 = Math.floor(lng * 1e5);
        
        dlat = late5 - plat;
        dlng = lnge5 - plng;
        
        plat = late5;
        plng = lnge5;
        
        encoded_points += encodeSignedNumber(dlat) + encodeSignedNumber(dlng);
        encoded_levels += encodeNumber(level);
    }
    return { encoded_path: encoded_points, encoded_levels: encoded_levels };
}

GPolygon.prototype.encoded_path = encoded_path;
GPolyline.prototype.encoded_path = encoded_path;

function decodeLine (encoded) {
    var len = encoded.length;
    var index = 0;
    var array = [];
    var lat = 0;
    var lng = 0;
    
    while (index < len) {
        var b;
        var shift = 0;
        var result = 0;
        do {
            b = encoded.charCodeAt(index++) - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        var dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
        lat += dlat;
        
        shift = 0;
        result = 0;
        do {
            b = encoded.charCodeAt(index++) - 63;
            result |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        var dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
        lng += dlng;
        
        array.push(new GLatLng(lat * 1e-5, lng * 1e-5));
    }
    
    return array;
}

// Decode an encoded levels string into a list of levels.
function decodeLevels(encoded) {
    var levels = [];
    
    for (var pointIndex = 0; pointIndex < encoded.length; ++pointIndex) {
        var pointLevel = encoded.charCodeAt(pointIndex) - 63;
        levels.push(pointLevel);
    }
    
    return levels;
}

function marker_bounds(ms,zoom)
{
    var b = null;
    for(var i = ms.length-1; i >= 0; --i)
    {
        var m = ms[i];
        if(zoom >= parseInt(m.zoom_min) && zoom <= parseInt(m.zoom_max))
        {
            if(b == null)
            {
                var tmp = m.getBounds();
                b = new GLatLngBounds(tmp.getSouthWest(),tmp.getNorthEast());
            }
            else
            {
                var tmp = m.getBounds();
                b.extend(tmp.getSouthWest());
                b.extend(tmp.getNorthEast());
            }
        }
    }
    return b;
}

