var gmapConstructor = function(initView)
{

    var CONST = {
        useMap:             true,
        serviceUrl:         "/user/glist.xml"
    };

    var allPoints = {}; // points cache
    var pointsOnMap = {}; // points on map

    var Hint = {
            _elem:      document.getElementById("gmHint"),
            _tail:      new MouseTail("gmHint", 12, 18),
            show:       function(n, a) {
                            var h = Hint._elem;
                            while (h.firstChild) h.removeChild(h.firstChild);
                            h.appendChild(document.createElement("div").appendChild(document.createTextNode(n)));
                            if (a)
                            {
                                var x = h.appendChild(document.createElement("div"));
                                x.className = "gray";
                                x.appendChild(document.createTextNode(a));
                            }
                            Hint._tail.show();
                        },
            hide:       function(m) { Hint._tail.hide(); }
        };

    function parseUserNode(itemNode)
    {
        var item = {};
        item.id = itemNode.getAttribute("id");
        forEachChildNode(itemNode, function(node) {
            if (node.nodeType != 1) return;
            if (node.tagName == "center") {
                this.center = new GLatLng(parseFloat(node.getAttribute("lat")), parseFloat(node.getAttribute("lng")));
            } else if (node.tagName == "span") {
                this.span = new GLatLng(parseFloat(node.getAttribute("height")), parseFloat(node.getAttribute("width")));
            } else if (node.tagName == "name") {
                this.name = GXml.value(node);
            } else if (node.tagName == "address") {
                this.address = GXml.value(node);
            } else if (node.tagName == "vehicle") {
                this.vehicle = GXml.value(node);
            } else if (node.tagName == "preview") {
                this.preview = {
                        src:    node.getAttribute("src"),
                        width:  node.getAttribute("width"),
                        height: node.getAttribute("height")
                };
            }
        }, item);
        return item;
    }

    function UserPoint(itemNode)
    {
        var item = parseUserNode(itemNode);

/*        
        item.element = Create.elem("DIV");
        item.element.className = "GMapInfoWin";

        var info = item.element.appendChild(Create.elem("DIV"));
        info.className = "userDiv";

        var a = info.appendChild(Create.elem("A"));
        a.href = pageParams.host + "/"+item.id;
        if(initView.inIframe) a.target = "_top";

        item.previewImg = a.appendChild(Create.elem("IMG"));
        item.previewImg.setAttribute("src",    CONST.waitImgSrc);
        item.previewImg.setAttribute("width",  item.preview.width);
        item.previewImg.setAttribute("height", item.preview.height);

        GEvent.addDomListener(a, "mouseover", function(){ Hint.show(this.name, this.vehicle, this.address); }.bind(item) );
        GEvent.addDomListener(a, "mouseout",  function(){ Hint.hide(); });

        a = info.appendChild(Create.elem("div")).appendChild(Create.elem("a"));
        a.href = pageParams.host + "/"+item.id;
        a.className = "name";
        if(initView.inIframe) a.target = "_top";
        a.appendChild(Create.text(item.name));
        info.appendChild(Create.elem("DIV")).appendChild(Create.text(item.address));

        var zl = zoomLinks();
        zl.zoomTo.onclick = function() {
                    var zl = map.getCurrentMapType().getSpanZoomLevel(item.center, item.span, map.getSize());
                    map.setZoom(zl);
                };
        item.element.appendChild(zl.block);
*/

        item.marker = new GMarker(item.center, userIcon);
/*
        GEvent.addListener(item.marker, "click", function() {
                this.previewImg.setAttribute("src", this.preview.src);
                this.marker.openInfoWindow(this.element, {maxWidth: 300});
            }.bind(item));
*/

        GEvent.addListener(item.marker, "click", function() { window.location.href = '/user/' + item.id; });
        GEvent.addListener(item.marker, "mouseover", function(){ Hint.show(item.name, item.vehicle, item.address); });
        GEvent.addListener(item.marker, "mouseout",  function(){ Hint.hide(); });

        return item;
    }

    var currentCoords = document.getElementById("currentCoords");

    var dataLoadTimer = null;
    var nowLoading = false;
    var isLoadingFlag = false;
    var lastLoadedCenter = null;

    var lload = document.getElementById("loadLabel");
    
    function onLoadStart()
    {
        nowLoading = true;
        dataLoadTimer = null;
        lload.innerHTML = "loading data…"; 
    }

    function onLoadEnd()
    {
        nowLoading = false;
        if (isLoadingFlag) { isLoadingFlag = false; loadData(); }
        lload.innerHTML = ""; 
    }

    function onMapZoom()
    {
        if (dataLoadTimer) window.clearTimeout(dataLoadTimer);
        dataLoadTimer = window.setTimeout(loadData, 1000);
        currentCoords.innerHTML = printLatLon(map.getCenter());
    }

    function onMapMove()
    {
        if (lastLoadedCenter)
        {
            var lastPt = map.fromLatLngToDivPixel(lastLoadedCenter);
            var currPt = map.fromLatLngToDivPixel(map.getCenter());
            if(Math.abs(lastPt.x - currPt.x) < 20 && Math.abs(lastPt.y - currPt.y) < 20) return;
        }
        onMapZoom();
    }

    var sessionKey = Math.random();

    function loadData()
    {
        if (!CONST.useMap) return;
        if (nowLoading) { isLoadingFlag = true; return; }
        onLoadStart();
        var b = map.getBounds();
        var ppd = map.getSize().width/(b.toSpan().lng());
        var url = CONST.serviceUrl+"?mode=map&sw="+b.getSouthWest().toUrlValue()+"&ne="+b.getNorthEast().toUrlValue()+"&ppd=" + ppd + "&zoom=" + map.getZoom();
        if (true) url += "&skey=" + sessionKey;
        GDownloadUrl(url, onDataLoad);
        lastLoadedCenter = map.getCenter();
    }

    function forEachChildNode(root, callback, thisObj)
    {
        for (var c = root.firstChild; c; c = c.nextSibling) callback.call(thisObj, c);
    }

    function onDataLoad(data, responseCode)
    {
        onLoadEnd();
        if (responseCode != 200)
        {
            alert("Data error: " + responseCode);
            return false;
        }
        
        if (!data)
        {
            alert("Data error: nothing found");
            return false;
        }
        var loadedPoints = {};
        var xml = GXml.parse(data);
        forEachChildNode(xml.documentElement, function(itemNode){
            if (itemNode.nodeType != 1 || (itemNode.nodeName != "user")) return;
            var id = itemNode.getAttribute("id");
            var item = null;
            if (typeof allPoints[id] != "undefined") item = allPoints[id];
            else if (itemNode.nodeName == "user") item = UserPoint(itemNode);
            else return;
            allPoints[id] = item;
            loadedPoints[id] = item;
        });

        for(var id in pointsOnMap) if(typeof loadedPoints[id] == "undefined") map.removeOverlay(allPoints[id].marker);
        for(var id in loadedPoints) if(typeof pointsOnMap[id] == "undefined") map.addOverlay(allPoints[id].marker)
        pointsOnMap = loadedPoints;
        return true;
    }

    // Map initialization

    var userIcon = new GIcon();
    userIcon.image = "/site/flag.png";
    userIcon.iconSize = new GSize(16, 15);
    userIcon.iconAnchor = new GPoint(6, 14);
    userIcon.infoWindowAnchor = new GPoint(18, 1);

    var map = null;
    
    if(CONST.useMap) {
        map = new GMap2(document.getElementById("map"));
        map.enableScrollWheelZoom();
        map.getContainer().style.overflow="hidden";

        map.addControl(new GLargeMapControl());
        map.addControl(new GMapTypeControl());
        map.addControl(new GScaleControl());
        map.addControl(new GOverviewMapControl());

        var mt = map.getCurrentMapType();
        map.setCenter(initView.center, initView.zoom, mt);

        GEvent.addListener(map, "moveend", onMapMove);
        GEvent.addListener(map, "zoomend", onMapZoom);

        onMapZoom();
    }

    function printLatLon(ll) {
        var s, loc;

        loc = {};
        loc.val = ll.lat();
        loc.abs = Math.abs(loc.val);
        loc.deg = Math.floor(loc.abs);
        loc.min = Math.floor(60*(loc.abs - loc.deg));
        loc.sec = Math.round(3600*(loc.abs - loc.deg - loc.min/60));
        if(loc.min < 10) loc.min = "0" + loc.min;
        if(loc.sec < 10) loc.sec = "0" + loc.sec;
        s = loc.deg + "\xB0" + loc.min + "'"+ loc.sec + '"' + ((loc.val >= 0)? "N" : "S" ) + "lat";

        loc = {};
        loc.val = ll.lng();
        loc.abs = Math.abs(loc.val);
        loc.deg = Math.floor(loc.abs);
        loc.min = Math.floor(60*(loc.abs - loc.deg));
        loc.sec = Math.round(3600*(loc.abs - loc.deg - loc.min/60));
        if(loc.min < 10) loc.min = "0" + loc.min;
        if(loc.sec < 10) loc.sec = "0" + loc.sec;
        s = s + " " + loc.deg + "\xB0" + loc.min + "'"+ loc.sec + '"' + ((loc.val >= 0)? "E" : "W" ) + "lon";
        return s;
    }


}


