var handlers;

if (!handlers) {
    handlers = {};
}

(function() {

    /**/
    handlers.positionMapDiv = function() {
        var mapDiv = $id('map');
        var perspectiveViewDiv = $id('perspective-view');
        //in an effort to fix IE z-index bug I have repositioned the "map" inside as relative don't need offset
        var offset = 268 + $id('container').offsetLeft + 'px';
        //perspectiveViewDiv.style.left = mapDiv.style.left = offset;
        perspectiveViewDiv.style.left = mapDiv.style.left = "0";
    };

    /**/
    handlers.setupControlsHandlers = function() {

        SWMap.animationSelectionControl.setupHandlers();

        general.addListener(
            'inspectorSearchTextBox',
            'keypress',
            function(evt) {
                if (evt.keyCode === 13) {
                    inspectorManager.search.doSearch(
                        'inspectorSearchResultsContainer',
                        $id('inspectorSearchTextBox').value
                    );
                    YAHOO.util.Event.preventDefault(evt);
                    return false;
                }
            }
        );

        general.addListener(
            'inspectorSearchButton',
            'mousedown',
            function(evt) {
                inspectorManager.search.doSearch(
                    'inspectorSearchResultsContainer',
                    $id('inspectorSearchTextBox').value
                );
                YAHOO.util.Event.preventDefault(evt);
                return false;
            }
        );

        general.addListener(
            'playpause',
            'mousedown',
            function(evt) {
                SWMap.animationControl.playPauseControl();
                YAHOO.util.Event.preventDefault(evt);
                return false;
            }
        );
    };


    /**/
    handlers.mouseMoveHandler = function(evt) {
        var target = evt.target || evt.srcElement;

        var mapDiv = SWMap.map.divs.mapDiv;

        if (!general.isNodeOrChildOf(target, mapDiv)) {
            SWMap.tooltip.hide();
        }
    };



    /* */
    handlers.setupMapHandlers = function() {

        SWMap.loadingMessage.show();

        var map = SWMap.map;

        GEvent.addListener(map, "dragstart", onDragStart);
        GEvent.addListener(map, "dragend", onDragEnd);
        GEvent.addListener(map, "moveend", onMoveEnd);
        GEvent.addListener(map, "zoomend", onZoomEnd);
        GEvent.addListener(map, "dblclick", onDoubleClick);
        GEvent.addListener(map, "maptypechanged", onMapTypeChanged);

        general.addListener(window, 'resize', handlers.positionMapDiv);
        general.addListener(window, 'mouseout', handlers.mouseMoveHandler);
    };

    var lastRegion = null;
    /*    */
    handlers.updateAfterMove = function(showAnimation) {
        var map = SWMap.map;

        map.keepViewOffEdgeOfWorld();

        var region = map.getCenter().getTightestContainingRegion();
        if (showAnimation) {
            SWMap.animationControl.setAnimation(region);
            try {
                SWMap.regionDataTabs.displayRegionData(region); // TODO this is causing long running script error at seemingly random
            }
            catch (err) {
                //let this fall through
            }

        } else {
            if (region !== lastRegion) {
                SWMap.regionDataTabs.displayClickForRegion(region);
            }
            SWMap.animationControl.setType('off');
        }

		lastRegion = region;

        var regionsInZoom = SW.Regions.regionsInZoom;
        for (var i = 0; i < regionsInZoom.length; i++) {
            regionsInZoom[i].updatePosition();
        }

        SWMap.regionTrail.updateTrail();
    };

    handlers.updateAfterZoom = function(newZoom, showAnimation) {   
        SWMap.loadingMessage.show();
        SW.Regions.hoveredRegionChangeable = false;
        SW.Regions.updateRegionsInZoom(newZoom);
        SWMap.markerGrid.updateMarkerDisplay();
        SWMap.tooltip.hide(); // in case tooltip got stuck because of a zoom (probably not necessary, but just to be sure)
        handlers.updateAfterMove(showAnimation);
        SW.Regions.hoveredRegionChangeable = true;
        SWMap.loadingMessage.hide();
    };

    ////// MAP VIEW CHANGE HANDLERS


    ///// MAP TYPE CHANGED

    var onMapTypeChanged;

    handlers.setMapTypeChangedHandler = function(handler) {
        onMapTypeChangedHandler = onMapTypeChangedHandlers[handler];
    };

    var onMapTypeChangedHandlers = {
        DUMMY: function() {
        },
        DEFAULT: function() {
            SWMap.historyControl.addState();
        }
    };

    handlers.setMapTypeChangedHandler('DEFAULT');

    /*  */
    var onMapTypeChanged = handlers.onMapTypeChanged = function() {
        var handler = onMapTypeChangedHandler;
        handlers.setMapTypeChangedHandler('DUMMY');  // allows handler itself to trigger a MapTypeChanged event without anything happening
        handler();
        handlers.setMapTypeChangedHandler('DEFAULT');
    };

    var onMapTypeChangeHandlers = {
        DUMMY: function() { },
        DEFAULT: function() {
            SWMap.historyControl.addState();
        }
    };

    var onMapTypeChangeHandles = {};

    handlers.setOnMapTypeChangeHandler = function(handlerName) {
        var handle = GEvent.addListener(
                SWMap.map,
                'maptypechanged',
                onMapTypeChangeHandlers[handlerName]
            );
        onMapTypeChangeHandles[handlerName] = handle;
    };

    handlers.removeOnMapTypeChangeHandler = function(handlerName) {
        var handle = onMapTypeChangeHandles[handlerName];
        if (handle) {
            GEvent.removeListener(handle);
        }
    };


    ///// ZOOM END

    var onZoomEndHandler;

    handlers.setZoomEndHandler = function(handler) {
        onZoomEndHandler = onZoomEndHandlers[handler];
    };

    var onZoomEndHandlers = {
        DUMMY: function() {
        },
        DEFAULT: function(oldZoom, newZoom) {
            handlers.updateAfterZoom(newZoom, false);
            if (newZoom === 0) {
                mapGeneral.centerAndZoomOnRegionAnimation(SWMap.world.worldRegion);
            } else {
                SWMap.historyControl.addState();
            }
        },
        ON_ZOOM_TO_REGION: function(oldZoom, newZoom) {
            handlers.updateAfterZoom(newZoom, true);
            SWMap.historyControl.addState();
        },
        ON_PLAY_AFTER_ZOOM_TO_REGION: function(oldZoom, newZoom) {
            handlers.updateAfterZoom(newZoom, true);
            SWMap.historyControl.addState();

            // if animation starts too soon, animation plays out with ugly flickering (because of race condition), so make sure all rendering work gets done first
            window.setTimeout(
                    function() {
                        SWMap.animationControl.play(false);
                    },
                    0
                );
        }
    };

    handlers.setZoomEndHandler('DEFAULT');

    /*  */
    var onZoomEnd = handlers.onZoomEnd = function(oldZoom, newZoom) {
        var handler = onZoomEndHandler;
        handlers.setZoomEndHandler('DUMMY');  // allows handler itself to trigger a Zoomend event without anything happening
        handler(oldZoom, newZoom);
        handlers.setZoomEndHandler('DEFAULT');
    };


    ///// MOVE END

    var onMoveEndHandler;

    handlers.setMoveEndHandler = function(handler) {
        onMoveEndHandler = onMoveEndHandlers[handler];
    };

    function afterPan(getRegion) {
        SW.Regions.hoveredRegionChangeable = false;
        var regionsInZoom = SW.Regions.regionsInZoom;
        for (var i = 0; i < regionsInZoom.length; i++) {
            regionsInZoom[i].updatePosition();
        }
        SWMap.regionTrail.updateTrail();
        SWMap.markerGrid.updateMarkerDisplay();
        var map = SWMap.map;
        SWMap.historyControl.addState();
        var region = (getRegion) ? map.getCenter().getTightestContainingRegion() : SWMap.animationControl.animation;
        SWMap.regionDataTabs.displayRegionData(region); // the animation will be a region object
    }

    var onMoveEndHandlers = {
        DUMMY: function() {
        },
        DEFAULT: function() {
        },
        ON_PAN_TO_MARKER: function() {
            afterPan(true);
            SW.Regions.hoveredRegionChangeable = true;
        },
        ON_PAN_AFTER_SETTING_ANIMATION: function() {
            afterPan();
            SW.Regions.hoveredRegionChangeable = true;
        },
        // same as above but plays at the end
        ON_PLAY_AFTER_PAN_AFTER_SETTING_ANIMATION: function() {
            afterPan();
            // if animation starts too soon, animation plays out with ugly flickering (because of race condition), so make sure all rendering work gets done first
            window.setTimeout(
                    function() {
                        SWMap.animationControl.play(false);
                    },
                    0
                );
            SW.Regions.hoveredRegionChangeable = true;
        }
    };

    handlers.setMoveEndHandler('DEFAULT');

    /*  */
    var onMoveEnd = handlers.onMoveEnd = function() {
        var handler = onMoveEndHandler;
        handlers.setMoveEndHandler('DUMMY');  // disable before dispatch to allow handler itself to trigger a moveend event without anything happening
        handler();
        handlers.setMoveEndHandler('DEFAULT');
    };


    ///// DRAG END

    var onDragEndHandler;

    handlers.setDragEndHandler = function(handler) {
        onDragEndHandler = onDragEndHandlers[handler];
    };


    var onDragEndHandlers = {
        DUMMY: function() {
        },
        DEFAULT: function() {
            SW.Regions.hoveredRegionChangeable = true; // used by ClickableRegionDiv
            general.clearDelay('marker update');
            handlers.updateAfterMove(false);
            SWMap.historyControl.addState();
            handlers.delayedMarkerUpdate();
        }
    };

    handlers.setDragEndHandler('DEFAULT');

    /*  */
    var onDragEnd = handlers.onDragEnd = function() {
        var handler = onDragEndHandler;
        handlers.setDragEndHandler('DUMMY');  // disable before dispatch to allow handler itself to trigger a dragend event without anything happening
        handler();
        handlers.setDragEndHandler('DEFAULT');
    };


    handlers.delayedMarkerUpdate = function(delay) {
        delay = delay || 450;

        general.clearDelay('marker update'); // this may be redundant with same call in onDragStart(), but it doesn't harm anything here
        general.addDelay(delay, 'marker update',
                function() {
                    SWMap.markerGrid.updateMarkerDisplay();
                }
            );
    };



    ///// DRAG START

    var onDragStartHandler;

    handlers.setDragStartHandler = function(handler) {
        onDragStartHandler = handlers.onDragStartHandlers[handler];
    };


    handlers.onDragStartHandlers = {
        DUMMY: function() {
        },
        DEFAULT: function() {
            SW.Regions.hoveredRegionChangeable = false; // flag to prevent hovered region div from changing visibility while dragging (otherwise, when dragging the map, the cursor tends to futz around a bit, causing the current hovered over region to change rapidly in some cases, which is annoying)
            SWMap.animationControl.setType('off');
            general.clearDelay('marker update');

        }
    };

    handlers.setDragStartHandler('DEFAULT');

    /*  */
    var onDragStart = function() {
        var handler = onDragStartHandler;
        handlers.setDragStartHandler('DUMMY');  // disable before dispatch to allow handler itself to trigger a dragStart event without anything happening
        handler();
        handlers.setDragStartHandler('DEFAULT');
    };


    /// DOUBLE CLICK

    function onDoubleClick(overlay, point) {
        SWMap.animationControl.setType('off');
    }

})();
