/**
* Placeholder for Map interaction.
* @author Guy Whitfield
*/

Object.size = function (obj) {
    var size = 0, key;
    for (key in obj) {
        if (obj.hasOwnProperty(key)) size++;
    }
    return size;
};


rn.Map = function () {
    var that = this;
    var bingMap = null;
    var CREDENTIALS = "AjyasSPZDnA0hhZfvyJQNKcgacA72AwTb9xXovTNgmnm5xvXmPIZubUVUp_ePDTp";
    var MAP_NODE = "map";
    var GLOBAL_DEPLOYMENT_ZOOM_LEVEL = 2;
    var EVENT_ZOOM_LEVEL = 6;
    var FADEOUT_SPEED = 50;
    var DEFAULT_LOCATION = { 'Latitude': '50.801831', 'Longitude': '-1.109642' }; // HMS Victory
    this.mapData = {};
    this.globalDeploymentData = {};
    this.eventData = {}
    this.scopedGlobalDeploymentData = {};
    this.eventIndex;
    this.mapAvailable = false;

    this.settings = {
        animate: true,
        credentials: CREDENTIALS,
        zoom: EVENT_ZOOM_LEVEL,
        mapTypeId: 'a',
        showLogo: false,
        showScalebar: false,
        enableSearchLogo: false,
        showCopyright: false,
        labelOverlay: 1,
        tilt: false,
        showDashboard: false,
        throbState: true
    };

    this.init = function () {

        if ((typeof (Microsoft.Maps.Map) != "undefined")) {
            this.mapAvailable = true;
        }

        if (this.mapAvailable) {
            rn.Events.registerGlobalEvent(this);
            $('#map-container .no-js').removeClass('no-js');
            $('#map-container').prepend('<div class="spinner"></div>');
            this.domNode = $('#map');

            var qs = window.location;
            var service = "http://" + qs.hostname + "/News-and-Events/Events?ajax=1";

            $.ajax({
                url: service,
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (data) {
                    that.setEventData(data);
                    that.initialiseMapandPanels(data);
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    rn.Console.log("XMLHttpRequest=" + XMLHttpRequest.responseText + "\ntextStatus=" + textStatus + "\nerrorThrown=" + errorThrown);
                }
            });

        }
    };

    this.getGlobalDeploymentData = function (zoomLevel) {
        if (typeof (Microsoft) != "undefined") {
            var qs = window.location;
            var service = "http://" + qs.hostname + "/The-Fleet?ajax=1";

            $.ajax({
                url: service,
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (data) {
                    var evtData = jQuery.extend(true, {}, that.eventData);
                    var size = Object.size(evtData);
                    evtData[size] = data;
                    that.purge();
                    that.initMapWithData('event', evtData, zoomLevel);
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    rn.Console.log("XMLHttpRequest=" + XMLHttpRequest.responseText + "\ntextStatus=" + textStatus + "\nerrorThrown=" + errorThrown);
                }
            });

        }
    }

    this.scopeDeploymentData = function () {

        if (typeof (Microsoft) != "undefined") {
            var qs = window.location;
            var servicePrefix = 'http://';
            var servicePostfix = '?ajax=1';
            var pathName = qs.pathname;
            var zoomLevel = GLOBAL_DEPLOYMENT_ZOOM_LEVEL;


            if ($('body.unit').length > 0) {
                zoomLevel = EVENT_ZOOM_LEVEL;
                var splitPathName = ((document.location.pathname).substr(1)).split('/');
                var lastItem = (splitPathName.length) - 1;

                // If unit present chomp the string to be minus the last item
                var itemToMatch = splitPathName[lastItem];
                var indexOfItemToMatch = pathName.indexOf(itemToMatch);
                var trimmedPathName = pathName.substr(0, indexOfItemToMatch);
                pathName = trimmedPathName;
            }
            var service = servicePrefix + qs.hostname + pathName + servicePostfix;

            $.ajax({
                url: service,
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (data) {
                    var evtData = jQuery.extend(true, {}, that.eventData);
                    var size = Object.size(evtData);
                    evtData[size] = data;
                    that.scopedGlobalDeploymentData = data;
                    that.purge();
                    that.initMapWithData('deployment', evtData, zoomLevel);
                    that.initPanels();
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    rn.Console.log("XMLHttpRequest=" + XMLHttpRequest.responseText + "\ntextStatus=" + textStatus + "\nerrorThrown=" + errorThrown);
                }
            });

        }
    }

    this.initPanels = function () {
        rn.panelMapSettings.init();
        rn.panelEvents.init();
        rn.panelNews.init();
        rn.panelVessel.init();
        rn.panelMapCarousel.init();
    }

    this.setEventData = function (events) {

        var evtData = jQuery.extend(true, {}, events);

        $.each(evtData, function () {
            this.air = [];
            this.land = [];
            this.sea = [];
        });
        that.eventData = evtData;
    }

    this.fadetrue = function () {
        $('.map-pin img[src$="event.png"]').fadeTo(1000, 1);
    }

    this.fadefalse = function () {
        $('.map-pin img[src$="event.png"]').fadeTo(1000, 0.5);
    }

    this.throb = function () {
        if (rn.map.settings.throbState == true) {
            rn.map.settings.throbState = false;
        } else {
            rn.map.settings.throbState = true;
        }
        eval('rn.map.fade' + rn.map.settings.throbState + '();');
    }

    this.initialiseMapandPanels = function (data) {
        this.mapData.items = data;

        var pathname = (document.location.pathname).toUpperCase();
        if (pathname.indexOf('THE-FLEET') == 1) {
            rn.Events.fireGlobalEvent(rn.Events.registry.EVENT_SCOPED_DEPLOYMENT, {});
        } else {
            this.initMapWithData('event');
            this.initPanels();
        }

    }

    this.initMapWithData = function (type, data, zoomLevel) {

        var mapPins = data || this.mapData.items;
        var zoomLevel = zoomLevel || EVENT_ZOOM_LEVEL;

        this.getMap();
        this.setMapCenter(type, zoomLevel);

        // Initialise required entity collections
        this.layerLand = new Microsoft.Maps.EntityCollection();
        this.layerSea = new Microsoft.Maps.EntityCollection();
        this.layerAir = new Microsoft.Maps.EntityCollection();
        this.layerEvents = new Microsoft.Maps.EntityCollection();
        this.layerLandRelationships = new Microsoft.Maps.EntityCollection();
        this.layerSeaRelationships = new Microsoft.Maps.EntityCollection();
        this.layerAirRelationships = new Microsoft.Maps.EntityCollection();
        this.gridTileSource = new Microsoft.Maps.TileSource({ uriConstructor: '/images/map/grid.png' });
        this.gridlayer = new Microsoft.Maps.TileLayer({ mercator: this.gridTileSource, opacity: 1 });
        this.entitiesLayer = rn.map.getEntities();

        $.each(mapPins, function () {
            var eventLon = 0;
            if (typeof (this.location) != "undefined") {
                that.createMapPin(this, 'event', that.layerEvents);
                eventLon = this.location.Longitude;
            }
            $.each(this.air, function () {
                that.createMapPin(this, 'air', that.layerAir, that.layerAirRelationships, eventLon);
            });
            $.each(this.land, function () {
                that.createMapPin(this, 'land', that.layerLand, that.layerLandRelationships, eventLon);
            });
            $.each(this.sea, function () {
                that.createMapPin(this, 'sea', that.layerSea, that.layerSeaRelationships, eventLon);
            });
        });


        // Push the layers to the map
        if (!($.browser.msie && parseInt($.browser.version, 10) < 7)) {
            this.entitiesLayer.push(this.gridlayer);
        }
        this.entitiesLayer.push(this.layerLandRelationships);
        this.entitiesLayer.push(this.layerSeaRelationships);
        this.entitiesLayer.push(this.layerAirRelationships);
        this.entitiesLayer.push(this.layerEvents);
        this.entitiesLayer.push(this.layerLand);
        this.entitiesLayer.push(this.layerSea);
        this.entitiesLayer.push(this.layerAir);

        //Initiate the throbber - exclude older versions of IE
        if (!($.browser.msie && parseInt($.browser.version, 10) < 9)) {
            window.setInterval(rn.map.throb, 1200);
        }
    }

    this.purge = function () {
        if (null != rn.map.entitiesLayer) {
            rn.map.entitiesLayer.clear();
        }
        $('.infobox').hide();
    }

    /** 
    * Wrapped bing functions
    */

    var createMap = function () {
        var mapNode = document.getElementById(MAP_NODE);
        if ((typeof (Microsoft.Maps.Map) != "undefined")) {
            bingMap = new Microsoft.Maps.Map(mapNode, that.settings);
        } else {
            that.mapAvailable = false;
            return false;
        }
        rn.Events.fireGlobalEvent(rn.Events.registry.EVENT_MAP_LOADED, {});
        // Add a event handlers
        Microsoft.Maps.Events.addHandler(bingMap, 'viewchangestart', function () { that.hideInfoBoxes(); });
        Microsoft.Maps.Events.addHandler(bingMap, 'mouseover', function () { bingMap.focus(); });
        Microsoft.Maps.Events.addHandler(bingMap, 'mouseout', function () { bingMap.blur(); });
        Microsoft.Maps.Events.addHandler(bingMap, "viewchangeend", function () { rn.Events.fireGlobalEvent(rn.Events.registry.EVENT_VIEW_CHANGE_END, {}) });
    };

    this.getMap = function () {
        if (!bingMap) {
            createMap();
        } else {
            return bingMap;
        }
    };

    this.setZoom = function (zoomLevel) {
        bingMap.setView({ zoom: zoomLevel });
    };

    this.zoomIn = function () {
        this.setView({ zoom: bingMap.getZoom() + 1 });
    };

    this.zoomOut = function () {
        this.setView({ zoom: bingMap.getZoom() - 1 });
    };

    this.setView = function (viewOptions, pin) {
        bingMap.setView(viewOptions);
    };

    this.getBounds = function () {
        return bingMap.getBounds();
    };

    this.tryLocationToPixel = function (location, reference) {
        return bingMap.tryLocationToPixel(location, reference);
    }

    this.getEntities = function () { return bingMap.entities; }
    this.getCenter = function () { return bingMap.getCenter(); }
    this.getHeading = function () { return bingMap.getHeading(); }
    this.getOptions = function () { return bingMap.getOptions(); }
    this.getZoom = function () { return bingMap.getZoom(); }
    this.getZoomRange = function () { return bingMap.getZoomRange(); }

    this.setMapCenter = function (type, zoomLevel) {
        var centreLocation;
        var itemIndex = 0;
        var type = type || 'event';
        var iterator = rn.map.mapData.items;
        unitType = 'sea';

        if (type == 'deployment') { //TODO: START HERE
            iterator = that.scopedGlobalDeploymentData;
            if (iterator.sea.length > 0) {
                iterator = iterator.sea;
            } else if (iterator.sea.land > 0) {
                iterator = iterator.land;
                unitType = 'land';
            } else if (iterator.sea.air > 0) {
                iterator = iterator.air;
                unitType = 'air';
            }
        }

        $.each(iterator, function (index) {
            if (this.active) {
                itemIndex = index;
                if (type == 'event') {
                    that.eventIndex = index;
                }
                return false;
            }
        });

        switch (type) {
            case 'event':
                if (typeof (this.mapData) != "undefined" && typeof (this.mapData.items[itemIndex].location) != "undefined") {
                    centreLocation = new Microsoft.Maps.Location(this.mapData.items[itemIndex].location.Latitude, this.mapData.items[itemIndex].location.Longitude);
                }
                break;
            case 'deployment':
                if (typeof (this.scopedGlobalDeploymentData) != "undefined" && this.scopedGlobalDeploymentData[unitType].length > 0) {
                    centreLocation = new Microsoft.Maps.Location(this.scopedGlobalDeploymentData[unitType][itemIndex].location.Latitude, this.scopedGlobalDeploymentData[unitType][itemIndex].location.Longitude);
                }
                break;

            default:
                centreLocation = new Microsoft.Maps.Location(DEFAULT_LOCATION.Latitude, DEFAULT_LOCATION.Longitude);
        }
        this.setView({ center: centreLocation, zoom: zoomLevel });
    }

    this.getLocation = function (lat, lon) {
        return new Microsoft.Maps.Location(lat, lon);
    }

    this.setLocation = function (lat, lon) {
        var location = this.getLocation(lat, lon);
        this.setView({ center: location });
    }

    this.createMapPin = function (data, type, layer, relationshiplayer, eventLon) {

        var anchor = { x: 16, y: 16 }
        var width = 33;
        var height = 33;
        var parentName = "";
        var boxOrientation = "";
        var icon = '/images/default-pin.png';
        var descriptor = "VESSEL";
        var unitTypeIcon = 'images/map/units/' + data.icon;


        if (data.parent) {
            var parentLocation;
            parentLocation = data.parent.location;
            parentName = "<h3>On board</h3><p>" + (data.parent.name || "Classified") + "</p>";
        }

        if (type == "air") {
            descriptor = "AIRCRAFT";
        }

        var html = "<div class='pin'></div><div class='unit-content'><h2>" + data.name + "</h2><img class='unit' alt='" + data.name + "' src='/" + unitTypeIcon + "' /><div class='details'><h3>" + descriptor + "</h3><p>" + data.unitType + "</p>" + parentName + "<h3>Mission</h3><p class='last'>" + (data.mission || '') + "</p><a href='" + data.pageLink + "'>Find out more ></a></div></div><a href='#' class='close' title='Close'>close</a>";

        var pinData = {
            event: {
                icon: "/images/map/event.png",
                html: "<h2>" + data.location.PlaceName + "</h2><h3>" + data.name + "</h3><p>" + data.location.LocationInDegrees + "<br><a class='event-link' href='" + data.pageLink + "'>Follow the story ></a></p>",
                anchor: { x: 38, y: 32 },
                width: 76,
                height: 76,
                type: type
            },
            air: {
                icon: icon,
                html: html,
                anchor: anchor,
                width: width,
                height: height,
                type: type
            },
            land: {
                icon: icon,
                html: html,
                anchor: anchor,
                width: width,
                height: height,
                type: type
            },
            sea: {
                icon: icon,
                html: html,
                anchor: anchor,
                width: width,
                height: height,
                type: type
            },
            fallback: {
                icon: icon,
                html: html,
                anchor: anchor,
                width: width,
                height: height,
                type: 'fallback'
            }
        };
        pinData = pinData[type] || pinData.fallback;

        var pinlocation = new Microsoft.Maps.Location(data.location.Latitude, data.location.Longitude);
        var pin = new Microsoft.Maps.Pushpin(pinlocation, { typeName: 'map-pin', icon: pinData.icon, anchor: pinData.anchor, width: pinData.width, height: pinData.height });

        //Check for boxOrientation here
        if ((eventLon) && (eventLon > data.location.Longitude)) {
            boxOrientation = " westerly";
        }

        pin.setInfoBox(new InfoBox("<div class='" + pinData.type + boxOrientation + "'>" + pinData.html + "</div>"), pinData.type);

        //Add pin to relevant layer
        layer.push(pin);


        if (data.parent && typeof (data.parent) != "undefined") {
            var options = { strokeColor: new Microsoft.Maps.Color(70, 255, 255, 255), strokeThickness: 1, visible: true };
            var polyline = new Microsoft.Maps.Polyline([pinlocation, new Microsoft.Maps.Location(data.parent.location.Latitude, data.parent.location.Longitude)], options);

            if ($.browser.msie) {
                //Polylines cause IE7&8 some difficulties so they are removed
                if ($.browser.version != '7.0' && $.browser.version != '8.0') {
                    relationshiplayer.push(polyline);
                }
            } else {
                relationshiplayer.push(polyline);
            }
        }

        //Use for initialising the event layer entities
        if (type == 'event') {
            Microsoft.Maps.Events.invoke(pin, 'click', { target: { location: pinlocation, type: type} });
        }

    }

    this.setInfoboxPosition = function (evt, domNode) {
        // Calculate the pixel position of the owner pushpin 
        // relative to the map control

        var loc = (typeof (evt.target.location) != "undefined") ? evt.target.location : evt.target.getLocation();

        var pinLocation = rn.map.tryLocationToPixel(loc, Microsoft.Maps.PixelReference.control);

        var x = -17;
        var y = -37;

        //Find any children of the dom that are west of the event pin
        if ($(domNode).find('.westerly').length > 0) {
            var adjustedOffset = {
                event: { x: 42, y: -24 },
                air: { x: -158, y: y },
                land: { x: -158, y: y },
                sea: { x: -184, y: y },
                fallback: { x: -184, y: y }
            }
            adjustedOffset = adjustedOffset[evt.target.type] || adjustedOffset.fallback;
            x = adjustedOffset.x;
            y = adjustedOffset.y
        }

        var offset = {
            event: { x: 42, y: -24 },
            air: { x: x, y: y },
            land: { x: x, y: y },
            sea: { x: x, y: y },
            fallback: { x: x, y: y }
        };
        offset = offset[evt.target.type] || offset.fallback;

        // Display the infobox at the correct pixel coordinates
        $(domNode).css({
            'left': (pinLocation.x + offset.x),
            'top': (pinLocation.y + offset.y)
        });
        return;
    }

    this.hideInfoBoxes = function () {
        $('.infobox').fadeOut(this.FADEOUT_SPEED);
    }

    this.toggleLayer = function (layer) {
        layer.setOptions({ visible: !layer.getVisible() });
    }

    this.showLayer = function (layer, relationship, type) {
        layer.setOptions({ visible: true });

        if (layer == rn.map.layerSea) {
            if (rn.map.layerAir.getVisible()) rn.map.layerAirRelationships.setOptions({ visible: true });
            if (rn.map.layerLand.getVisible()) rn.map.layerLandRelationships.setOptions({ visible: true });
        } else if (rn.map.layerSea.getVisible()) {
            relationship.setOptions({ visible: true });
        }
    }

    this.hideLayer = function (layer, relationship, type) {
        layer.setOptions({ visible: false });
        var selector = ".infobox ." + type;

        if (layer == rn.map.layerSea) {
            rn.map.layerAirRelationships.setOptions({ visible: false });
            rn.map.layerSeaRelationships.setOptions({ visible: false });
            rn.map.layerLandRelationships.setOptions({ visible: false });

        } else {
            relationship.setOptions({ visible: false });
        }
        $(selector).parent().hide();
    }

    this.resizeMapNode = function () {
        if (rn.panelMapSettings.mapState) {
            var mapNode = $('#map');
            mapNode.width($(window).width());
            mapNode.height($(window).height());
        }
    }

    /**
    * EVENT LISTENERS
    */

    /**
    * onMapSizeToggle - listens for the toggle firing when the map is sent fullscreen, or back again.
    */
    this.onMapSizeToggle = function () {

        if (rn.panelMapSettings.mapState) {
            $('#map').appendTo('body').css({ 'position': 'absolute', 'top': '0', 'left': '0', 'z-index': '2500' });
            this.resizeMapNode();

        } else {
            $('#map').insertBefore($('#map-settings')).css({ 'position': 'relative', 'height': '380px', 'width': '970px' });
        }
    };

    this.onGlobalDeployment = function () {
        this.getGlobalDeploymentData(GLOBAL_DEPLOYMENT_ZOOM_LEVEL);
    };

    this.onScopedDeployment = function () {
        this.scopeDeploymentData();
    };

    this.onShowVesselOnMap = function () {
        this.setView({ zoom: EVENT_ZOOM_LEVEL });
    }


    return this;
}

rn.map = new rn.Map();

