﻿/// <reference path="./JavascriptConstants.aspx/Cineplex.Constants.js" />
/// <reference path="./API/Agility.UGC.API.js" />
/// <reference path="./External/jquery.cookies.2.2.0.js" />
/// <reference path="./External/jquery.autocomplete-vsdoc.js" />
/// <reference path="./Cineplex.js" />

Agility.RegisterNamespace("Cineplex");

(function(Cineplex) {

    Cineplex.MapDialog = function(theatreMap) {
        this.theatreMap = theatreMap;
    };
    
    Cineplex.MapDialog.prototype.open = function(theatreMappings) {
        var theatreMap = this.theatreMap;
        $("#cineplex-map-dialog").load(Agility.ResolveUrl("~/Dialogs/Theatre-Map.aspx"), null, function() { 
            theatreMap.load(theatreMappings); 
        });
        $("#cineplex-map-dialog").CineplexDialog("open");
        $("#cineplex-video-dialog a").focus();
    };
    
    
    
    
    
    Cineplex.TheatreMap = function(mapDataService, mapLegend, mapPointCache, iconLookup) {
        this.mapDataService = mapDataService;
        this.mapLegend = mapLegend;
        this.mapPointCache = mapPointCache;
        this.iconLookup = iconLookup;
        this.map = null;
        this.searchedBounds = null;
    };
    
    Cineplex.TheatreMap.prototype.load = function (theatreMappings) {
        var self = this;
        google.load("maps", "2.x", { "callback": function() {
            var map = self.map = new google.maps.Map2(document.getElementById("cineplex-map-dialog-map"));
            map.setUIToDefault();
            
            var location = Cineplex.UserContext.GetCurrentLocation();
            if (theatreMappings.length > 1 && location) {
                var geocoder = new GClientGeocoder();
                geocoder.getLatLng(location, function (centrePoint) { self.getInitialPoints(centrePoint, theatreMappings); });
            } else if (theatreMappings.length == 1) {
                var lat = parseAndFixFloat(theatreMappings[0].latitude),
                    lng = parseAndFixFloat(theatreMappings[0].longitude);
                self.getInitialPoints(new GLatLng(lat, lng), theatreMappings);
            }
        }});
    };
    
    Cineplex.TheatreMap.prototype.getInitialPoints = function(centrePoint, theatreMappings) {
        //set centre
        var defaultZoom = (theatreMappings.length > 1) ? 9 : 15;
        this.map.setCenter(centrePoint, defaultZoom);
        
        //get points
        var self = this,
            searchBounds = new Cineplex.MapBounds(self.map.getBounds()).searchBounds(),
            sw = searchBounds.getSouthWest(),
            ne = searchBounds.getNorthEast();
        this.searchedBounds = searchBounds;
        this.mapDataService.getInitialPoints(sw.lat(), sw.lng(), ne.lat(), ne.lng(), function(data) { 
            if (data) {
                self.showInitialPoints(theatreMappings, data.MapPoints, data.MapPointTypes, data.TypeOrder); 
            }
        });
    };
    
    Cineplex.TheatreMap.prototype.showInitialPoints = function(theatreMappings, additionalPoints, pointTypes, typeOrder) {
        //initialize cache collections
        this.iconLookup.setPointTypes(pointTypes);
        this.mapPointCache.addPoints(additionalPoints);
        
        this.addTheatres(theatreMappings);
        var visiblePoints = this.mapPointCache.getVisiblePoints(this.map.getBounds());
        this.addPoints(visiblePoints);
        this.mapLegend.showTypes(this.iconLookup.getActiveTypes(), typeOrder);
        
        var self = this;
        GEvent.addListener(self.map, "moveend", function() {
            self.updatePointsAfterMove(typeOrder);
        });
    };
    
    Cineplex.TheatreMap.prototype.addTheatres = function(theatreMappings) {
        var icon = this.iconLookup.find("Theatre");

        for (var i = 0; i < theatreMappings.length; i++) {
            var t = theatreMappings[i];

            var point = new GLatLng(parseAndFixFloat(t.latitude), parseAndFixFloat(t.longitude));
            point.theatre = t;
            var marker = new GMarker(point, { title: t.theatre, icon: icon });
            marker.theatre = t;
            point.marker = marker;

            GEvent.addListener(marker, "click", showInfoWindowTheatre);
            this.map.addOverlay(marker);
            if (i == 0) {
                showInfoWindowTheatre(point);
            }
        }
        
        function showInfoWindowTheatre(point) {
            var tid = point.theatre.theatreid;

            var url = Agility.ResolveUrl("~/Services/TheatreMapInfoWindowHtml.aspx?theatreid=" + tid);
            $.ajax({
                url: url,
                success: function(data) {
                    point.marker.openInfoWindowHtml(data);
                }
            });
        }
    }
    
    Cineplex.TheatreMap.prototype.addPoints = function(mapPoints) {
        for (var i = 0; i < mapPoints.length; i++) {
            var mp = mapPoints[i],
                pos = new GLatLng(mp.Latitude, mp.Longitude),
                typeID = mp.MapPointType,
                icon = this.iconLookup.find(typeID),
                marker = new GMarker(pos, { title: mp.Title, icon: icon });
                
            pos.marker = marker;
            pos.pointID = mp.ID;
            var onMarkerClick = showInfoWindowAddlPoint;
            // Change marker click event for different map point types
            if (typeID == "GreenPParking") {
                onMarkerClick = showInfoWindowGreenPParking;
            }
            GEvent.addListener(marker, "click", onMarkerClick);
            this.map.addOverlay(marker);
        }
        
        function showInfoWindowAddlPoint(point) {
            var pointID = point.pointID,
                url = Agility.ResolveUrl("~/Services/TheatreMapAddlPointInfoWindowHtml.aspx?pointid=" + pointID);
            $.ajax({
                url: url,
                success: function(data) {
                    point.marker.openInfoWindowHtml(data);
                }
            });
        };

        function showInfoWindowGreenPParking(point) {
            var pointID = point.pointID,
                url = Agility.ResolveUrl("~/Services/TheatreMapGreenPParkingInfoWindowHtml.aspx?pointid=" + pointID);
            $.ajax({
                url: url,
                success: function(data) {
                    point.marker.openInfoWindowHtml(data);
                }
            });
        };
    };
    
    Cineplex.TheatreMap.prototype.updatePointsAfterMove = function(typeOrder) {
        var visibleBounds = this.map.getBounds();
        if (!this.searchedBounds.contains(visibleBounds)) {
            //do a call to get more data
            var sw = visibleBounds.getSouthWest(),
                ne = visibleBounds.getNorthEast(),
                self = this;
            this.mapDataService.getAdditionalPoints(sw.lat(), sw.lng(), ne.lat(), ne.lng(), function(data) {
                if (data && data.MapPoints) {
                    self.mapPointCache.addPoints(data.MapPoints);
                    var visiblePoints = self.mapPointCache.getVisiblePoints(visibleBounds);
                    self.addPoints(visiblePoints);
                    self.mapLegend.showTypes(self.iconLookup.getActiveTypes(), typeOrder);
                }
            });
        } else {
            //use existing data
            var visiblePoints = this.mapPointCache.getVisiblePoints(visibleBounds);
            this.addPoints(visiblePoints);
            this.mapLegend.showTypes(this.iconLookup.getActiveTypes(), typeOrder);
        }
    };
    
    function parseAndFixFloat(str) {
        if (typeof(str) != "string") return str;
        return parseFloat(str.replace(",", "."));
    }
    
    
    
    
    
    Cineplex.MapDataService = function() {
        //empty constructor
    };
    
    Cineplex.MapDataService.prototype.getInitialPoints = function(minLat, minLng, maxLat, maxLng, callback) {
        var url = Agility.ResolveUrl("~/Services/AdditionalMapPointLookup.ashx?initial=true&callback=?"),
            query = "&minlat=" + minLat + "&minlng=" + minLng + "&maxlat=" + maxLat + "&maxlng=" + maxLng;
        $.getJSON(url, query, callback);
    };
    
    Cineplex.MapDataService.prototype.getAdditionalPoints = function(minLat, minLng, maxLat, maxLng, callback) {
        var url = Agility.ResolveUrl("~/Services/AdditionalMapPointLookup.ashx?callback=?"),
            query = "&minlat=" + minLat + "&minlng=" + minLng + "&maxlat=" + maxLat + "&maxlng=" + maxLng;
        $.getJSON(url, query, callback);
    };
    
    
    
    
    
    Cineplex.MapLegend = function() {
        //empty constructor
    };
    
    Cineplex.MapLegend.prototype.showTypes = function(pointTypes, typeOrder) {
        var $rotator = $(".Rotator", $("#cineplex-map-dialog-legend"));
        $rotator.css("visibility", "hidden");
        if ($rotator.length > 0) {
            $rotator.data("pageIndex", 0);

            var $results = $("#cineplex-map-dialog-legend-items");
            $results.setTemplateElement("cineplex-map-dialog-results-template");
            $results.setParam("last", pointTypes.length);
            $results.processTemplate({
                PointTypes: pointTypes,
                TypeOrder: typeOrder
            });

            Cineplex.InitializeRotator($rotator);
        }
    };
    
    
    
    
    
    Cineplex.MapPointCache = function() {
        this.points = {};
    }
    
    Cineplex.MapPointCache.prototype.addPoints = function(points) {
        for(var i = 0; i < points.length; i++) {
            this.addPoint(points[i]);
        }
    };
    
    Cineplex.MapPointCache.prototype.addPoint = function(point) {
        var key = point.Latitude + "," + point.Longitude;
        if (!this.points[key]) {
            this.points[key] = point;
        }
    };
    
    Cineplex.MapPointCache.prototype.getVisiblePoints = function(bounds) {        
        var visiblePoints = [];

        for(var key in this.points) {
            var point = this.points[key];
            if (!point.Visible && this.pointInBounds(point, bounds)) {
                visiblePoints.push(point);
                point.Visible = true;   
            }
        }
        
        return visiblePoints;
    };
    
    Cineplex.MapPointCache.prototype.pointInBounds = function(point, bounds) {
        var minLat = bounds.getSouthWest().lat(),
            minLng = bounds.getSouthWest().lng(),
            maxLat = bounds.getNorthEast().lat(),
            maxLng = bounds.getNorthEast().lng();
        return point.Latitude >= minLat && point.Latitude <= maxLat
            && point.Longitude >= minLng && point.Longitude <= maxLng;
    };
    
    
    
    
    
    Cineplex.MapBounds = function(bounds) {
        this.bounds = bounds;
    };
    
    Cineplex.MapBounds.prototype.searchBounds = function() {
        var sw = this.bounds.getSouthWest(),
            ne = this.bounds.getNorthEast(),
            searchSW = new GLatLng(sw.lat() - 10, sw.lng() - 10),
            searchNE = new GLatLng(ne.lat() + 10, ne.lng() + 10);
        return new Cineplex.MapBounds(new GLatLngBounds(searchSW, searchNE));
    };
    
    Cineplex.MapBounds.prototype.getSouthWest = function () {
        return this.bounds.getSouthWest();
    };
    
    Cineplex.MapBounds.prototype.getNorthEast = function() {
        return this.bounds.getNorthEast();
    };
    
    Cineplex.MapBounds.prototype.contains = function(bounds) {
        var thisSW = this.getSouthWest(),
            thisNE = this.getNorthEast(),
            checkSW = bounds.getSouthWest(),
            checkNE = bounds.getNorthEast();
        return thisSW.lat() < checkSW.lat() && thisSW.lng() < checkSW.lng() 
            && thisNE.lat() > checkNE.lat() && thisNE.lng() > checkNE.lng();
    };
    
    
    
    
    
    Cineplex.IconLookup = function() {
        this.pointTypes = {};
        this.activePointTypes = {};
        this.icons = {};
    };
    
    Cineplex.IconLookup.prototype.setPointTypes = function(pointTypes) {
        this.pointTypes = pointTypes;
    };
    
    Cineplex.IconLookup.prototype.find = function(typeID) {
        if (!this.icons[typeID] && this.pointTypes[typeID]) {
            var pointType = this.pointTypes[typeID];
            this.icons[typeID] = this.buildIcon(pointType);
            this.activePointTypes[typeID] = pointType;
        }
        return this.icons[typeID];
    };
    
    Cineplex.IconLookup.prototype.buildIcon = function(mapPointType) {
        var icon = new GIcon();
        icon.image = mapPointType.IconImageUrl;
        icon.shadow = mapPointType.IconShadowUrl;
        icon.printImage = mapPointType.IconPrintUrl;
        icon.mozPrintImage = mapPointType.IconMozPrintUrl;
        icon.printShadow = mapPointType.IconPrintShadowUrl;
        icon.transparent = mapPointType.IconTransparentUrl;
        icon.imageMap = mapPointType.ImageMapCoords;
        icon.iconSize = new GSize(mapPointType.IconSize.X, mapPointType.IconSize.Y);
        icon.shadowSize = new GSize(mapPointType.ShadowSize.X, mapPointType.ShadowSize.Y);
        icon.iconAnchor = new GPoint(mapPointType.IconAnchor.X, mapPointType.IconAnchor.Y);
        icon.infoWindowAnchor = new GPoint(mapPointType.InfoWindowAnchor.X, mapPointType.InfoWindowAnchor.Y);
        return icon;
    }
    
    Cineplex.IconLookup.prototype.getActiveTypes = function() {
        // Add Green P Parking to the active points if user is in Toronto.
        var greenPParkingKey = "GreenPParking";
        if (Cineplex.UserContext.GetCurrentLocation() == "TORONTO - ON"
         && !this.activePointTypes[greenPParkingKey]
         && this.pointTypes[greenPParkingKey]) {
            this.activePointTypes[greenPParkingKey] = this.pointTypes[greenPParkingKey];   
        }
        
        return this.activePointTypes;
    };

})(Cineplex, jQuery);