﻿/// <reference name="MicrosoftAjax.js"/>

Type.registerNamespace("AirQuestSite");

AirQuestSite.MapMarkerManagerBehavior = function(element) {
    AirQuestSite.MapMarkerManagerBehavior.initializeBase(this, [element]);

    this.recentState = {
        zoom: -1,
        loadedBounds: null
    };

    this._markers = {};
    this._markerServiceParam = { mode: "d" };
}

AirQuestSite.MapMarkerManagerBehavior.prototype = {

    _mapControl: null,
    _theMap: null,

    _markerServiceParam: null,
    _theMarkerService: null,
    _markers: null,
    _icons: null,

    onMapMove$event: null,
    onMapMoveEnd$event: null,
    onMapLoad$event: null,
    onMapClick$event: null,
    onMapInitialized$handler: null,

    recentState: null,
    lastZoomRegistered: -1,
    executingRequest: null,
    tmrDelayServerRequest: -1,

    initialize: function() {
        AirQuestSite.MapMarkerManagerBehavior.callBaseMethod(this, 'initialize');

        //this._mapControl = Sys.UI.Behavior.getBehaviorsByType(this.get_element(), AirQuestSite.MapAreaControl)[0];
        this._mapControl = this.get_element().control;
        this.onMapInitialized$handler = Function.createDelegate(this, this.onMapInitialized);
        this._mapControl.add_mapInitialized(this.onMapInitialized$handler);

        this._theMarkerService = new AirQuestSite.MapMarkerManager();

        //this.onMapMove$event = GEvent.addListener(this._theMap, "move", Function.createDelegate(this, this.onMapMove));        

    },

    onMapInitialized: function(sender, args) {
        this._theMap = this._mapControl.get_map();
        this._icons = this._mapControl.get_icons();
        Sys.Debug.assert(this._mapControl != null, "Nenalezl jsem MapControl extender", true);

        this.onMapMoveEnd$event = GEvent.addListener(this._theMap, "moveend", Function.createDelegate(this, this.onMapMoveEnd));
        if(this._theMap.isLoaded()) {
            this.onMapLoad();
        } else {
            this.onMapLoad$event = GEvent.addListener(this._theMap, "load", Function.createDelegate(this, this.onMapLoad));
        }

        this.onMapClick$event = GEvent.addListener(this._theMap, "click", Function.createDelegate(this, this.onMapClick));
    },

    get_markerServiceParam: function() {
        return Sys.Serialization.JavaScriptSerializer.serialize(this._markerServiceParam);
    },

    set_markerServiceParam: function(val) {
        this._markerServiceParam = Sys.Serialization.JavaScriptSerializer.deserialize(val)
    },

    get_serviceParamObject: function() {
        return this._markerServiceParam;
    },

    onMapMove: function() {
        //this.handleMapMoved();
    },

    onMapMoveEnd: function() {
        this.handleMapMoved();
    },

    onMapLoad: function() {
        this.handleMapMoved();
    },

    get_markerService: function() {
        return this._theMarkerService;
    },

    handleMapMoved: function(bForce) {

        var bounds = this._theMap.getBounds();
        var zoom = this._theMap.getZoom();

        var bNeedServerSet = (this.recentState.zoom != zoom) || !this.recentState.loadedBounds.containsBounds(bounds);
        if(bNeedServerSet || bForce) {
            if(this.tmrDelayServerRequest != -1) {
                window.clearTimeout(this.tmrDelayServerRequest);
            }

            this.tmrDelayServerRequest = window.setTimeout(Function.createDelegate(this, this.requestSetFromServer), (this.lastZoomRegistered != -1 && this.lastZoomRegistered != zoom) ? 750 : 50);
        }

    },

    requestSetFromServer: function() {

        this.tmrDelayServerRequest = -1;

        var bounds = this._theMap.getBounds();
        var zoom = this._theMap.getZoom();
        this.lastZoomRegistered = zoom;

        // calculate bounds to load
        var proj = this._theMap.getCurrentMapType().getProjection();
        var pt1 = proj.fromLatLngToPixel(bounds.getSouthWest(), zoom);
        var pt2 = proj.fromLatLngToPixel(bounds.getNorthEast(), zoom);
        var sz = this._theMap.getSize();
        var offset = Math.max(sz.width, sz.height) / 2;

        var ptLoad1 = new GPoint(pt1.x - offset, pt1.y + offset);
        var ptLoad2 = new GPoint(pt2.x + offset, pt2.y - offset);

        var boundsLoad = new GLatLngBounds(proj.fromPixelToLatLng(ptLoad1, zoom), proj.fromPixelToLatLng(ptLoad2, zoom));
        this.recentState.loadedBounds = boundsLoad;
        this.recentState.zoom = zoom;

        // make the call            
        if(this.executingRequest) {
            // cancel if one is pending
            var theExecutor = this.executingRequest.get_executor();
            if(!theExecutor.get_responseAvailable()) {
                theExecutor.abort();
            }
        }

        pt1 = boundsLoad.getSouthWest();
        pt2 = boundsLoad.getNorthEast();


        this.executingRequest = this._theMarkerService.GetMarkersInBounds(pt1.lat(), pt2.lat(), pt1.lng(), pt2.lng(), zoom, this.get_markerServiceParam(),
            Function.createDelegate(this, this.onProcessResponse), Function.createDelegate(this, this.onServerError));


    },

    onProcessResponse: function(resp, ctx) {
        this.executingRequest = null;

        // window.status = "Počet bodů: " + resp.length;

        // read in-set
        var markerList = {};
        for(var i = 0; i < resp.length; ++i) {
            var m = resp[i];
            m.__exists = !(!this._markers[m.id]);
            markerList[m.id] = m;
        }
        // delete missing markers
        for(var id in this._markers) {
            var m = this._markers[id];
            if(m && !markerList[id]) {
                if(m.__managed) {
                    this.destroyMarker(id);
                }
            }
        }
        // add new markers
        for(var id in markerList) {
            var m = markerList[id];
            if(!m.__exists) {
                this.createMarker(m);
            }
        }
    },

    add_preCreateMarker: function(handler) {
        var e = Function._validateParams(arguments, [{ name: "handler", type: Function}]);
        if(e) throw e;
        this.get_events().addHandler("precreate", handler);
    },

    remove_preCreateMarker: function(handler) {
        var e = Function._validateParams(arguments, [{ name: "handler", type: Function}]);
        if(e) throw e;
        this.get_events().removeHandler("precreate", handler);
    },

    add_markerCreated: function(handler) {
        var e = Function._validateParams(arguments, [{ name: "handler", type: Function}]);
        if(e) throw e;
        this.get_events().addHandler("markercreated", handler);
    },

    remove_markerCreated: function(handler) {
        var e = Function._validateParams(arguments, [{ name: "handler", type: Function}]);
        if(e) throw e;
        this.get_events().removeHandler("markercreated", handler);
    },

    add_preRemoveMarker: function(handler) {
        var e = Function._validateParams(arguments, [{ name: "handler", type: Function}]);
        if(e) throw e;
        this.get_events().addHandler("preremove", handler);
    },

    remove_preRemoveMarker: function(handler) {
        var e = Function._validateParams(arguments, [{ name: "handler", type: Function}]);
        if(e) throw e;
        this.get_events().removeHandler("preremove", handler);
    },


    createMarker: function(markerData) {
        var h = this.get_events().getHandler("precreate");
        var args = new AirQuestSite.MarkerEventArgs(markerData, null);
        if(h != null) {
            h(this, args);
        }

        if(!args._cancel) {
            var id = markerData.id;

            var pos = new GLatLng(markerData.lat, markerData.lon);

            if(this._markers[id]) {
                this.destroyMarker(id);
            }


            var bClickable = true;
            if(markerData.quest && (this._markerServiceParam.mode == "quest_opened" || this._markerServiceParam.mode == "quest")) {
                bClickable = false;
            }
            var gm = new GMarker(pos, { title: markerData.name, draggable: markerData.draggable == true, icon: this._icons[markerData.ico], clickable: bClickable });
            gm.__id = id;
            this._theMap.addOverlay(gm);

            var evt = null;

            if(markerData.draggable == true) {
                evt = GEvent.addListener(gm, "dragend", Function.createDelegate(this, Function.createCallback(this.onMarkerDragEnd, markerData)));
            }

            this._markers[id] = { data: markerData, m: gm, __managed: !(markerData.foreground), __dragevt: evt, boundary: null };

            if(markerData.quest && markerData.quest.boundary) {
                var bnd = GPolygon.fromEncoded(
                    {
                        polylines: [
                            {
                                color: "#ff0000",
                                weight: (this._markerServiceParam.mode == "quest_opened" || this._markerServiceParam.mode == "quest") ? 3 : 1,
                                opacity: 1,
                                points: markerData.quest.boundary[0],
                                zoomFactor: 2,
                                levels: markerData.quest.boundary[1]
                            }
                         ],
                        fill: (this._markerServiceParam.mode == "quest_opened" || this._markerServiceParam.mode == "quest") ? false : true,
                        color: "#FFCC33",
                        opacity: 0.25,
                        outline: true
                    }
                );

                this._theMap.addOverlay(bnd);
                this._markers[id].boundary = bnd;

                if(((this._markerServiceParam.mode == "route_edit") || ((this._markerServiceParam.mode == "route_showquest" || this._markerServiceParam.mode == "quest_opened"))) && (markerData.quest.lat != 0)) {
                    var gmQuest = new GMarker(new GLatLng(markerData.quest.lat, markerData.quest.lon), { title: "Hledaný bod", draggable: false, icon: this._icons["qptgt"], clickable: false /*, zIndexProcess: function(m) { return 19500; }*/ });
                    this._markers[id].questMarker = gmQuest;
                    this._markers[id].guessMarkers = new Array();
                    this._theMap.addOverlay(gmQuest);

                    if(markerData.quest.guesses) {
                        var g = markerData.quest.guesses;
                        for(var i = 0; i < g.length; ++i) {
                            var strName = g[i].strOwner;
                            var createOpts = {
                                title: (strName == "@" ? "Váš tip" : strName), draggable: false, icon: this._icons[strName == "@" ? "qpguessmy" : "qpguess"], clickable: false
                            };
                            /*
                            if(strName == "@") {
                                createOpts.zIndexProcess = function(m) { return 19501 };
                            }*/
                            var gmGuess = new GMarker(new GLatLng(g[i].lat, g[i].lon), createOpts);
                            this._markers[id].guessMarkers.push(gmGuess);
                            this._theMap.addOverlay(gmGuess);

                        }
                        //zIndexProcess                       
                    } else {
                        this._theMap.addOverlay(gmQuest);
                    }
                }
            }

            h = this.get_events().getHandler("markercreated");
            args = new AirQuestSite.MarkerEventArgs(markerData, this._markers[id]);
            if(h != null) {
                h(this, args);
            }



        }
    },

    getMarkerDataById: function(id) {
        var gm = this._markers[id];
        return gm ? gm.data : null;
    },

    refreshMarker: function(id) {
        var gm = this._markers[id];
        if(gm) {
            this.destroyMarker(id);            
        }
        this.handleMapMoved(true);
    },

    destroyMarker: function(id) {
        var gm = this._markers[id];
        if(gm) {

            var h = this.get_events().getHandler("preremove");
            var args = new AirQuestSite.MarkerEventArgs(gm.data, gm);
            if(h != null) {
                h(this, args);
            }

            if(gm.boundary) {
                this._theMap.removeOverlay(gm.boundary);
                gm.boundary = null;
            }

            if(gm.questMarker) {
                this._theMap.removeOverlay(gm.questMarker);

                if(gm.guessMarkers) {
                    for(var i = 0; i < gm.guessMarkers.length; ++i) {
                        this._theMap.removeOverlay(gm.guessMarkers[i]);
                        gm.guessMarkers[i] = null;
                    }
                }

                gm.questMarker = null;
            }

            this._theMap.removeOverlay(gm.m);
            if(gm.__dragevt) {
                GEvent.removeListener(gm.__dragevt);
            }

            gm.__id = null;
            this._markers[id] = null;
            delete this._markers[id];
        }
    },



    onServerError: function(error) {

    },

    onMapClick: function(overlay, latlng, ovlLatLng) {

        var marker = null;

        if(overlay && overlay.__id && (marker = this._markers[overlay.__id])) {
            this.onClickMarker(marker);
        }

    },

    add_clickMarker: function(handler) {
        var e = Function._validateParams(arguments, [{ name: "handler", type: Function}]);
        if(e) throw e;
        this.get_events().addHandler("clickmarker", handler);
    },

    remove_clickMarker: function(handler) {
        var e = Function._validateParams(arguments, [{ name: "handler", type: Function}]);
        if(e) throw e;
        this.get_events().removeHandler("clickmarker", handler);
    },

    onClickMarker: function(marker) {

        var args = new AirQuestSite.MarkerEventArgs(marker.data, marker);
        var h = this.get_events().getHandler("clickmarker");
        if(h) {
            h(this, args);
        }

        if(!args._cancel) {
            this._theMap.openInfoWindow(marker.m.getLatLng(), this._mapControl.get_waitInfoWindowContent(), { onOpenFn: Function.createDelegate(this, Function.createCallback(this.onOpenWaitInfoWindow, marker)) });
        }
    },

    onOpenWaitInfoWindow: function(marker) {
        this._theMarkerService.GetInfoWindowContent(marker.data.id, Function.createDelegate(this, this.onGetInfoWindowContentResponse));
    },

    onGetInfoWindowContentResponse: function(resp, ctx) {
        var iw = this._theMap.getInfoWindow();
        if(!iw.isHidden()) {
            var tabs = new Array();
            if(resp.length == 1) {
                var divCnt = document.createElement("div");
                divCnt.innnerHTML = resp[0];
                tabs.push(new GInfoWindowTab(null, divCnt));
            } else {
                var idx = 0;
                while(idx * 2 + 1 < resp.length) {
                    var divCnt = document.createElement("div");
                    divCnt.innerHTML = resp[idx * 2 + 1];
                    tabs.push(new GInfoWindowTab(resp[idx * 2], divCnt));
                    ++idx;
                }
            }

            this._theMap.updateInfoWindow(tabs);
        }
    },

    add_markerMoved: function(handler) {
        var e = Function._validateParams(arguments, [{ name: "handler", type: Function}]);
        if(e) throw e;
        this.get_events().addHandler("markermoved", handler);
    },

    remove_markerMoved: function(handler) {
        var e = Function._validateParams(arguments, [{ name: "handler", type: Function}]);
        if(e) throw e;
        this.get_events().removeHandler("markermoved", handler);
    },

    onMarkerDragEnd: function(latlng, marker) {

        var oldPos = { lat: marker.lat, lon: marker.lon };
        marker.lat = latlng.lat();
        marker.lon = latlng.lng();

        var h = this.get_events().getHandler("markermoved");
        if(h) {
            var args = new Sys.EventArgs();
            args._marker = marker;
            args._oldpos = oldPos;
            h(this, args);
        }
    },

    dispose: function() {

        for(var id in this._markers) {
            this.destroyMarker(id);
        }

        //GEvent.removeListener(this.onMapMove$event);
        GEvent.removeListener(this.onMapClick$event);
        GEvent.removeListener(this.onMapMoveEnd$event);
        if(this.onMapLoad$event) {
            GEvent.removeListener(this.onMapLoad$event);
        }

        AirQuestSite.MapMarkerManagerBehavior.callBaseMethod(this, 'dispose');
    }
}
AirQuestSite.MapMarkerManagerBehavior.registerClass('AirQuestSite.MapMarkerManagerBehavior', Sys.UI.Behavior);


/************************ MarkerEventArgs ********************/

AirQuestSite.MarkerEventArgs = function Sys$CancelEventArgs(markerData, markerContext) {
    AirQuestSite.MarkerEventArgs.initializeBase(this);
    this._cancel = false;
    this._marker = markerData;
    this._markerContext = markerContext;
}

AirQuestSite.MarkerEventArgs.prototype = {

    cancel: function() {
        this._cancel = true;
    }

}

AirQuestSite.MarkerEventArgs.registerClass('AirQuestSite.MarkerEventArgs', Sys.EventArgs);



if(typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

