﻿function NetworkMap(map, minZoomLevel, maxZoomLevel, locked) {

    this._vemap = new Microsoft.Maps.Map(document.getElementById('myMap'), {
        credentials: "AjLbr7D0tsVUlM14nzOG4KnyUkWMiIIHXrqBmvqqdt-9pyiOEZsJgZWawHB-Y92i",
        showScalebar: false,
        showMapTypeSelector: false,
        backgroundColor : new Microsoft.Maps.Color(1, 255, 255, 255)
    });

    this._mapjq = $("#MicrosoftMap MapTypeId_m");
    this._minZoomLevel = minZoomLevel;
    this._maxZoomLevel = maxZoomLevel;

    this._locked = locked;

    this._data = null;
    this._shapeLayer = null;

    this._inClickEvent = false;
    this._mapCenter = new Microsoft.Maps.Location(45.0, 0.0);

    this._previousShape;
    this._currentZoom;
    this._customInfoBox;
}


NetworkMap.prototype = {

    init: function () {

        var me = this;

        Microsoft.Maps.registerModule("CustomInfoboxModule", "/scripts/BM7.Infobox.js");
        Microsoft.Maps.loadModule("CustomInfoboxModule", { callback: function () {
            me._customInfoBox = new CustomInfobox(me._vemap);
        }
        });

        this._vemap.onLoadMap = createRef(this, this._changeBGColour);

        var opt = this._vemap.getOptions();
        //opt.LoadBaseTiles = false;
        //this._vemap.LoadMap(this._mapCenter, this._minZoomLevel, VEMapStyle.Road, this._locked, VEMapMode.Mode2D, false, 0, opt);
        //this._vemap.HideDashboard();
        //this._vemap.SetDashboardSize(VEDashboardSize.Tiny);
        //hiding bing 6.2 dashboard
        opt.center = this._mapCenter;
        opt.mapTypeId = Microsoft.Maps.MapTypeId.mercator;
        this._vemap.setView(opt);

        $('#MSVE_navAction_ObliqueMapView').hide();
        $('#MSVE_navAction_AerialMapStyle').hide();
        $('#MSVE_navAction_showLabels').hide();
        $('#MSVE_navAction_RoadMapStyle').hide();
        $('#MSVE_navAction_topBar').hide();
        $('#MSVE_navAction_topBackground').css('width', '51px');
        $('#MSVE_navAction_toggleGlyphInner').hide();

        //http://www.southwesttrains.co.uk/tiles
        var tileOptions = { uriConstructor: 'http://www.southwesttrains.co.uk/tiles/{quadkey}.png', animationDisplay: 'show' };
        var tileSource = new Microsoft.Maps.TileSource(tileOptions);
        var tilelayer = new Microsoft.Maps.TileLayer({ mercator: tileSource, opacity: 1 });


        //        tileSourceSpec.NumServers = 1;
        //        tileSourceSpec.MaxZoomLevel = 8;
        //        tileSourceSpec.ZIndex = 100;
        this._vemap.entities.push(tilelayer);


        //this._vemap.AddTileLayer(tileSourceSpec, true);

        if (!this._locked) {
            Microsoft.Maps.Events.addHandler(this._vemap, "click", createRef(this, this._onClick));
        }

        Microsoft.Maps.Events.addHandler(this._vemap, "onmouseover", createRef(this, this._onMouseOver));
        Microsoft.Maps.Events.addThrottledHandler(this._vemap, "viewchangeend", createRef(this, this._onEndZoom), 250);

        //Microsoft.Maps.Events.addHandler(this._vemap, "onstartzoom", createRef(this, this._changeBGColour));
        //Microsoft.Maps.Events.addHandler(this._vemap, "onendzoom", createRef(this, this._changeBGColour));
        //Microsoft.Maps.Events.addHandler(this._vemap, "viewchange", self._onStartPan);
        //Microsoft.Maps.Events.addHandler(this._vemap, "onendpan", createRef(this, this._changeBGColour));
        //Microsoft.Maps.Events.addHandler(this._vemap, "onchangeview", createRef(this, this._changeBGColour));
        //Microsoft.Maps.Events.addHandler(this._vemap, "onmousewheel", createRef(this, this._changeBGColour));
        //Microsoft.Maps.Events.addHandler(this._vemap, "onkeypress", createRef(this, this._changeBGColour));

        //this._bgColourTimer = setInterval(createRef(this, this._changeBGColour), 100);

        //use the watcher script to watch the background colour for changes
        //this._mapjq.watch("backgroundColor", createRef(this, this._changeBGColour), 100, "_mapBGColour");

        $.ajax({

            url: "stationdata.ashx",
            dataType: "json",
            success: createRef(this, this._dataLoaded)

        });

        setInterval(function () {
            if (me._vemap.getZoom() == 1) {
                var imgList = $("#myMap div:eq(3) img");
                $(imgList[0]).css("opacity", 0);
                $(imgList[3]).css("opacity", 0);
                $(imgList[4]).css("opacity", 0);
                $(imgList[7]).css("opacity", 0);
            }
            //$(this).hide();
            //            $("#myMap img").each(function (index) {
            //                if(this.src.contains("1.png"))
            //                    $(this).hide();
            //            });
        }, 100);

    },

    _onStartPan: function (e) {
        e.handled = true;
        return;
    },
    _changeBGColour: function (e) {

        if (this._mapjq.css("backgroundColor") != "#FFFFFF")
            this._mapjq.css("backgroundColor", "#FFFFFF");

        //setTimeout(createRef(this, function() { this._mapjq.css("backgroundColor", "#FFFFFF"); }), 1);
        //return false;
    },

    _pageLoad: function (hash) {

        //window.ero.hide = function(a) {
        //    return;
        //}

        if (!this._inClickEvent && hash) {
            this._setPoint(hash, true);
        }
    },


    _dataLoaded: function (data) {

        /*
        
        data	{...}	Object
        Items	{...}	Object
        [0]	{...}	Object
        additional_descriptive_text	""	String
        additional_search_text	""	String
        client_id	"Addlestone"	String
        country	"United Kingdom"	String
        fax	""	String
        GeocodeDate	"16/08/2007"	String
        GeocodeSource	"cp072"	String
        GeoQuality	4	Long
        GeoQualitySpecified	true	Boolean
        id	7	Long
        idSpecified	true	Boolean
        image_alt	""	String
        image_src	""	String
        image_url	""	String
        item_type	"station"	String
        lat	51.37317	Double
        latSpecified	true	Boolean
        lon	-0.48437	Double
        lonSpecified	true	Boolean
        name	"Addlestone"	String
        nearest_station_crs	"ASN"	String
        nearest_station_name	"Addlestone"	String
        nm_lat	69.51145745	Double
        nm_latSpecified	true	Boolean
        nm_lon	57.15087891	Double
        nm_lonSpecified	true	Boolean
        nm_name	"Addlestone"	String
        pc	"KT15 2PB"	String
        radius_override	""	String
        state	""	String
        street	"Station Road"	String
        telephone	""	String
        town	"Addlestone, Weybridge"	String
        url	""	String
                       
        */

        //debugger;

        this._data = data;

        this._shapeLayer = new Microsoft.Maps.EntityCollection();

        this._currentZoom = this._vemap.getZoom();
        this._addShapes();

        //this._shapeLayer.Show();

        if (this.OnDataLoad != null)
            this.OnDataLoad(data);

        //init history
        $.history.init(createRef(this, this._pageLoad));

        //lastly, check the querystring to see if we had a station specified

        var crsCode = querySt("stn");

        if (crsCode != null) {
            //this.SelectPoint(crsCode, true);
            //$.history.load(crsCode);
            this.SelectPoint(crsCode);
        }
        else {

            //debugger;

            var hash = window.location.hash.substring(1);
            //hash = hash.replace(/^.*#/, '');
            // moves to a new page. 
            // pageload is called at once.
            //$.history.load(hash);
            this.SelectPoint(hash);
        }

    },

    //data load callback
    OnDataLoad: null,

    //point selected callback
    OnPointSelected: null,

    //popup content writing callback
    OnCreatingPopup: null,

    //select a point
    SelectPoint: function (id) {

        $.history.load(id);

    },

    findDestinationByStartAndVector: function (startPoint, direction, distance) {
        // Convert lat & lng from degrees into radians
        var lat1 = startPoint.latitude / 180 * Math.PI;
        var lng1 = startPoint.longitude / 180 * Math.PI;
        direction = direction / 180 * Math.PI;

        var angDist = distance / 3963.21; // 3963.21 = radius of earth in miles

        var lat2 = Math.asin(Math.sin(lat1) * Math.cos(angDist) + Math.cos(lat1) * Math.sin(angDist) * Math.cos(direction));
        var lng2 = lng1 + Math.atan2(Math.sin(direction) * Math.sin(angDist) * Math.cos(lat1), Math.cos(angDist) - Math.sin(lat1) * Math.sin(lat2));

        // Convert the new position back into degrees and create a LatLong
        var finalLat = lat2 / Math.PI * 180;
        var finalLng = lng2 / Math.PI * 180;

        finalLat = (finalLat / 20037508.34) * 180;
        finalLng = (finalLng / 20037508.34) * 180;

        finalLat = 180 / Math.PI * (2 * Math.atan(Math.exp(finalLat * Math.PI / 180)) - Math.PI / 2);

        var destPoint = new Microsoft.Maps.Location(finalLat, finalLng);

        return destPoint;
    },

    getCirclePoints: function (center, radius, numPoints) {
        var points = new Array();

        for (var theta = 0; theta < 360; theta += 360 / numPoints) {
            points.push(this.findDestinationByStartAndVector(center, theta, radius));
        }

        return points;
    },

    createCircle: function (center, distance, points, options) {
        return new Microsoft.Maps.Polygon(this.getCirclePoints(center, distance, points), options);
    },

    createCircle2: function (center, radius, options) {

        var centerX = center.latitude;
        var centerY = center.longitude;
        var points = new Array();
        // Fidelity is how "fine" you want to draw the circle   
        // Generally, the bigger the circle, the smaller your incremental value   
        // needs to be to get a "perfect circle".  Play with this value to see    
        // what I mean.  This value will make it go 360 degrees around the circle   
        fidelity = Math.PI / 180;
        for (var angle = 0; angle < 2 * Math.PI; angle += fidelity) {
            var X;
            var Y;
            X = Math.cos(angle) * radius + centerX;
            Y = Math.sin(angle) * radius + centerY;

            // Do what you need to do with X,Y (store them, draw something with   
            // them, etc...
            points.push(new Microsoft.Maps.Location(X, Y));
        }
        return new Microsoft.Maps.Polygon(points, options);
    },


    _addShapes: function () {
        if (this._shapeLayer == null)
            return;

        this._shapeLayer.clear();
        var data = this._data;

        for (var index in data.Items) {

            var ll = new Microsoft.Maps.Location(data.Items[index].nm_lat, data.Items[index].nm_lon);

            //var circleIconHTML = this._getIconMarkup(this._vemap.getZoom(), "Clear");
            //var ppoptions = { icon: "Images/Clear_32.png" };
            var polygonOptions = {
                fillColor: new Microsoft.Maps.Color(100, 0, 0, 255),
                strokeColor: new Microsoft.Maps.Color(100, 255, 0, 0)
            };


            var wh = 2 * Math.pow(2, this._vemap.getZoom());
            var tl = (wh / 2);

            var pushpinOptions = { typeName: "stationPushpin", icon: 'Images/clear_' + wh + ".png", visible: true, anchor: new Microsoft.Maps.Point(tl, tl), width: tl * 2, height: tl * 2 };
            //var circle = this.createCircle(ll, 250, 60, polygonOptions);
            var circle = new Microsoft.Maps.Pushpin(ll, pushpinOptions);

            //circle._visible = false;

            circle.data = data.Items[index];
            circle.selected = false;

            //circle.SetTitle(data.Items[index].nearest_station_name);

            var description;

            //if we have a custom popup creation callback
            if (this.OnCreatingPopup != null) {
                description = this.OnCreatingPopup(data.Items[index]);
            }
            else {  //use the default
                description = "<div class='popuptitle'>" + data.Items[index].nearest_station_name + "</div>" +
                               "<div class=popuplinks>" +
                                        "<a href=\"" + data.Items[index].station_information_url + "\">Station Information</a><br/>" +
                                        "<a href=\"" + data.Items[index].station_map_download_url + "\">Download Station Map</a><br/>" +
                                        "<a href=\"" + data.Items[index].station_map_view_url + "\">View this station on a road map</a><br/><br/>" +
                                        "<span style='color:black'>" + data.Items[index].street + ", " + data.Items[index].pc + "</span>" +
                              "</div>";
            }

            //circle.SetDescription(description);

            circle.description = description;
            //circle.SetCustomIcon(circleIconHTML);
            //var pushpinClick = Microsoft.Maps.Events.addHandler(circle, 'click', function() { });

            this._shapeLayer.push(circle);

            data.Items[index].Shape = circle;
        }

        this._vemap.entities.push(this._shapeLayer);

        if (this._previousShape != null)
            this._previousShape.setOptions({ icon: 'Images/icon_' + wh + ".png" });

    },

    _setPoint: function (id, doCallback) {

        var data = this._data;

        for (var index in data.Items) {

            if (data.Items[index].nearest_station_crs == id) {

                this._selectShape(data.Items[index].Shape, true, true, doCallback);
                break;
            }
        }

    },

    //get the map
    GetMap: function () {

        return this._vemap;

    },


    _onClick: function (e) {
        if (e.targetType == "map") {
            var point = new Microsoft.Maps.Point(e.getX(), e.getY());
            var loc = e.target.tryPixelToLocation(point);
            $('#status').empty().html(loc.latitude + ", " + loc.longitude);
        }
        if (e.targetType == "pushpin") {
            this._inClickEvent = true;

            $.history.load(e.target.data.nearest_station_crs);

            this._selectShape(e.target, false, true, true, true);

            this._inClickEvent = false;
        }

    },

    _selectShape: function (selectedShape, setCenter, showInfo, doCallback) {

        if (selectedShape) {
            var wh = 2 * Math.pow(2, this._vemap.getZoom());
            var tl = (wh / 2);

            if (this._previousShape != null)
                this._previousShape.setOptions({ icon: 'Images/clear_' + wh + ".png" });

            selectedShape.setOptions({ icon: 'Images/icon_' + wh + ".png" });
            this._previousShape = selectedShape;
            if (showInfo) {
                this._customInfoBox.show(selectedShape.getLocation(), selectedShape.description);
            }

            if (doCallback && this.OnPointSelected != null) {
                this.OnPointSelected(selectedShape.data);
            }

            selectedShape.selected = true;

            var loc = new Microsoft.Maps.Location(selectedShape.data.nm_lat, selectedShape.data.nm_lon);
            var opt = this._vemap.getOptions();
            opt.centerOffset = new Microsoft.Maps.Point(20, 100);
            opt.center = loc;
            if (!this._inClickEvent)
                opt.zoom = 4;
            this._vemap.setView(opt);
        }

    },

    _onMouseOver: function (e) {

        if (e.elementID) {

            var shape = this._vemap.GetShapeByID(e.elementID);

            if (shape) {
                return shape.selected !== true;
            }
        }

    },

    _onEndZoom: function (e) {
        if (this._vemap.getZoom() < this._minZoomLevel) {
            this._vemap.setView({ zoom: this._minZoomLevel });
            return true;
        }
        else if (this._vemap.getZoom() > this._maxZoomLevel) {
            this._vemap.setView({ zoom: this._maxZoomLevel });
            return true;
        }

        if (this._currentZoom != this._vemap.getZoom()) {
            this._addShapes();
            this._currentZoom = this._vemap.getZoom();
        }
        return;
        //debugger;



        for (var shapeIdx = 0; shapeIdx < this._shapeLayer.GetShapeCount(); ++shapeIdx) {

            var shape = this._shapeLayer.GetShapeByIndex(shapeIdx);
            var wh = 2 * Math.pow(2, this._vemap.GetZoomLevel());

            if (shape.selected) {

                shape.SetCustomIcon(this._getIconMarkup(this._vemap.GetZoomLevel(), "Icon"));
                shape.Show();
            }
            else {

                shape.SetCustomIcon(this._getIconMarkup(this._vemap.GetZoomLevel(), "Clear"));
                shape.Show();
            }

        }
    },

    _getIconMarkup: function (zl, image) {

        var wh = 2 * Math.pow(2, zl);
        var tl = 12 - (wh / 2);

        var iconMarkup = "<div style=\"position:relative;top:" + tl + "px;left:" + tl + "px;\">" +
                                "<span style=\"display:inline-block;filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='Images/" + image + "_" + wh + ".png');\">" +
                                    "<img style=\"filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);\" src=\"Images/" + image + "_" + wh + ".png\" border=\"0\" alt=\"\">" +
                                "</span>" +
                           "</div>";


        return iconMarkup;
    }
};

String.prototype.contains = function (it) { return this.indexOf(it) != -1; };
