topics = {
    topicUser: '',
    updatesFragmentUrl: 'fragments/topicupdates.htm',
    pageNum: 1,
    intervalId: '',
    refreshInterval: 30000,
    apiBaseUrl: '',
    webBaseUrl: '',
    webservicesBaseUrl: '',
    mapUpdatesApiUrlTemplate: new Template('#{baseUrl}/user/#{topicName}/updates.json'),
    mapInstance: '',
    mapCoordinate: '',
    mapZoomLevel: '',
    mapNumPins: 100,
    mapNumDaysNew: 2,
    mapNumHasComments: 2,
    mapIconDefault: '',
    mapIconNew: '',
    mapIconNewHasComments: '',
    mapIconHasComments: '',
    mapIconMulti: '',
    mapUpdatesHash: new Hash(),
    mapLocationsHash: new Hash(),
    showingMap: false,
    apiRequestLengthLimit: 100,
    init: function() {
        if($('topicContents')) {
            topics.checkForPageChange(true);
            setInterval("topics.checkForPageChange();", 100);
        }
        if($('mapTab')) {
            setInterval("topics.checkForTabChange();", 100);
        }
        if($('refreshOff')) {
            $('refreshOff').observe('click', topics.refreshUpdates);
        }
        if($('refreshOn')) {
            $('refreshOn').observe('click', topics.stopRefresh);
            if($('refreshOn').visible()) {
                topics.refreshUpdates();
            }
        }
    },
    loadUpdates: function(pageNum, goToTop) {
        var url = topics.updatesFragmentUrl + '?name=' + topics.topicUser + '&page=' + pageNum;
        new Ajax.Updater({ success: 'topicContents' }, url, {
            onComplete: function(resp) {
                if(topics.loggedOut) {
                    ZannelUtil.checkRequiredLogin();
                }
                page.userpage.locationTooltipAddObservers();
                $$('.playIcon').each( function(item) {
                    item.observe('click', topics.stopRefresh);
                });
            }
        });
        if(goToTop) {
            window.scrollTo(0,0);
        }
    },
    refreshUpdates: function(event) {
        if(event) {
            event.stop();
        }
        $('refreshOff').hide();
        $('refreshOn').show();
        if(topics.intervalId == '') {
            topics.intervalId = setInterval("topics.loadUpdates(1)", topics.refreshInterval);
        }
    },
    stopRefresh: function(event) {
        if(event) {
            event.stop();
        }
        $('refreshOn').hide();
        $('refreshOff').show();
        if(topics.intervalId != '') {
            clearInterval(topics.intervalId);
            topics.intervalId = '';
        }
    },
    mapTab: function(lat, long, zoomLevel) {
        topics.showingMap = true;
        $('mapTab').hide();
        $('mapTabSelected').show();
        $('feedTabSelected').hide();
        $('feedTab').show();
        topics.stopRefresh();
        $('topicContents').hide();
        if($('uploadBoxArea')) {
            $('uploadBoxArea').hide();
        }
        if($('mapHelp')) {
            $('mapHelp').show();
        }
        $('topicMapContainer').show();
        topics.initMap();
    },
    feedTab: function() {
        topics.showingMap = false;   
        topics.loadUpdates(1);
        $('feedTabSelected').show();
        $('feedTab').hide();
        $('mapTabSelected').hide();
        $('mapTab').show();
        topics.refreshUpdates();
        $('topicMapContainer').hide();
        if($('mapHelp')) {
            $('mapHelp').hide();
        }
        if($('uploadBoxArea')) {
            $('uploadBoxArea').show();
        }
        $('topicContents').show();
    },
    initMap: function() {
        if(GBrowserIsCompatible()) {
            if(topics.mapInstance == '') {
                topics.mapInstance = new GMap2(document.getElementById("topicMap"));
                topics.mapInstance.setCenter(new GLatLng(topics.mapCoordinate.latitude, topics.mapCoordinate.longitude), topics.mapZoomLevel);
                topics.mapInstance.addControl(new GLargeMapControl3D());
                topics.mapInstance.addControl(new GScaleControl());
                topics.initBaseIcons();
                GEvent.addListener(topics.mapInstance, "moveend",  topics.loadMapPins);
                topics.loadMapPins();
            } else {
                topics.mapInstance.clearOverlays();
                topics.mapUpdatesHash.each(function(pair) {
                    topics.mapUpdatesHash.unset(pair.key);
                });
                topics.mapLocationsHash.each(function(pair) {
                    topics.mapLocationsHash.unset(pair.key);
                });
                topics.loadMapPins();
            }
        }
    },
    initBaseIcons: function() {
        topics.mapIconDefault = new GIcon();
        topics.mapIconDefault.image = topics.webBaseUrl + "/images/r2/map_pin2.png";
        topics.mapIconDefault.iconSize = new GSize(27, 48);
        topics.mapIconDefault.iconAnchor = new GPoint(7, 43);
        topics.mapIconDefault.infoWindowAnchor = new GPoint(13, 13);

        topics.mapIconNew = new GIcon(topics.mapIconDefault);
        topics.mapIconNew.image = topics.webBaseUrl + "/images/r2/map_pin_new2.png";

        topics.mapIconNewHasComments = new GIcon(topics.mapIconDefault);
        topics.mapIconNewHasComments.image = topics.webBaseUrl + "/images/r2/map_pin_new_comment2.png";

        topics.mapIconHasComments = new GIcon(topics.mapIconDefault);
        topics.mapIconHasComments.image = topics.webBaseUrl + "/images/r2/map_pin_comment2.png";

        topics.mapIconMulti = new GIcon(topics.mapIconDefault);
        topics.mapIconMulti.image = topics.webBaseUrl + "/images/r2/map_pin_multi.png";
    },
    getUpdatesApiUrl: function() {
        return topics.mapUpdatesApiUrlTemplate.evaluate({ baseUrl: topics.apiBaseUrl, topicName: topics.topicUser });
    },
    loadMapPins: function() {
        var mapBounds = topics.mapInstance.getBounds();
        var mapCenter = topics.mapInstance.getCenter();
        var radiusInMeters = mapCenter.distanceFrom(mapBounds.getNorthEast());
        var radiusInMiles = radiusInMeters * 0.000621371192;
        var offset = 0;
        var length = topics.apiRequestLengthLimit;
        if(topics.mapNumPins < length) {
            length = topics.mapNumPins;
        } 
        while(offset < topics.mapNumPins) {
            topics.requestPins(offset, length, radiusInMiles, mapCenter.lat(), mapCenter.lng());
            offset += length;
        }
    },
    requestPins: function(offset, length, radiusInMiles, lat, lng) {
        $('mapLoading').show();
        var requestParams = '?offset=' + offset;
        requestParams += '&length=' + length;
        requestParams += '&radius=' + radiusInMiles;
        requestParams += '&coord=' + encodeURIComponent(lat + ':' + lng);
        var params = {
            method: 'get',
            postParams: '',
            onSuccess: topics.onUpdatesReceived
        }
        new Ajax.Request(topics.getUpdatesApiUrl() + requestParams, params);
    },
    onUpdatesReceived: function(response) {
        var json = response.responseJSON;
        var updates = json.updates;
        for(i = 0; i < updates.length; i++) {
            var update = updates[i];
            if(topics.mapUpdatesHash.get(update.hashcode) == undefined) {
                topics.addMarker(update);
            }
        }
        Effect.Fade('mapLoading', { duration: 0.5 });
    },
    addMarker: function(updateJson) {
        // check if another update already exists at the same location
        var locHashKey = updateJson.geolocation.latitude + updateJson.geolocation.longitude;
        var locUpdatesArray = topics.mapLocationsHash.get(locHashKey);

        if(locUpdatesArray == undefined) {
            // add update to this location
            var mapValues = topics.createMarker(updateJson, false);
            topics.mapInstance.addOverlay(mapValues.marker);
            locUpdatesArray = new Array();
            locUpdatesArray[0] = updateJson;
            topics.mapLocationsHash.set(locHashKey, locUpdatesArray)
            topics.mapUpdatesHash.set(updateJson.hashcode, mapValues);
        } else  {
            var arraySize = locUpdatesArray.size();
            var mapValues = topics.mapUpdatesHash.get(locUpdatesArray[0].hashcode);
            // if only one other item, update it to be the multi-item pin
            if(arraySize == 1) {
                topics.mapInstance.removeOverlay(mapValues.marker);
                GEvent.removeListener(mapValues.eventListener);
                mapValues = topics.createMarker(mapValues.updateJson, true);
                topics.mapInstance.addOverlay(mapValues.marker);
                topics.mapUpdatesHash.set(locUpdatesArray[0].hashcode, mapValues);
            }
            locUpdatesArray[arraySize] = updateJson; // add to the array of updates at this location
            topics.mapUpdatesHash.set(updateJson.hashcode, { marker: mapValues.marker, eventListener: mapValues.eventListener, updateJson: updateJson }); // add to updates hash, updates at the same location use the same map values
        }
    },
    createMarker: function(updateJson, isMulti) {
        var point = new GLatLng(updateJson.geolocation.latitude, updateJson.geolocation.longitude);
        var iconBase = topics.mapIconDefault;
        var hasComments = (updateJson.collections.comments.total >= topics.mapNumHasComments);

        if(isMulti) {
            iconBase = topics.mapIconMulti;
        } else {
            var currentDate = new Date().getTime();
            var timestamp = Date.parse(updateJson.timestamp);
            var oneDay = 1000*60*60*24;
            var ageInDays = (currentDate - timestamp) / oneDay;
            if(ageInDays <= topics.mapNumDaysNew) {
                if(hasComments) {
                    iconBase = topics.mapIconNewHasComments;
                } else {
                    iconBase = topics.mapIconNew;
                }
            } else if(hasComments) {
                iconBase = topics.mapIconHasComments;
            }
        }

        var icon = new GIcon(iconBase);
        var marker = new GMarker(point, { icon:icon });
        var eventListener = GEvent.addListener(marker, "click", function() {
            topics.openInfoBubble(marker, updateJson, (isMulti ? 0 : null));
        });

        return { marker: marker, eventListener: eventListener, updateJson: updateJson };
    },
    openInfoBubble: function(marker, updateJson, multiIndex) {
        var previewHtml = topics.createPreviewHtml(updateJson, multiIndex);
        marker.openInfoWindowHtml(previewHtml, { maxWidth: 315 });
    },
    createPreviewHtml: function(updateJson, multiIndex) {
        var point = new GLatLng(updateJson.geolocation.latitude, updateJson.geolocation.longitude);
        var hasComments = (updateJson.collections.comments.total >= topics.mapNumHasComments);
        var updateUrl = topics.webBaseUrl + '/viewupdate.htm?id=' + updateJson.hashcode + '&topic=' + topics.topicUser;
        // note: any styles that help determine width and height of the bubble need to be inline
        var previewHtml = '<div class="infoWindow" style="font-family: Arial, Helvetica, sans-serif;">';
        if(updateJson.type == 'IMAGE' || updateJson.type == 'VIDEO') {
            previewHtml += '<div style="float: left; position: relative; width: 100px; height: 75px; border: 1px solid #cbd2d7; margin: 0px 10px 5px 0px;">';
            previewHtml += '<table width="100" height="75" cellspacing="0" cellpadding="0"><tr>';
            previewHtml += '<td align="center" style="vertical-align: middle;"><a href="' + updateUrl + '"><img src="' + topics.webservicesBaseUrl + '/content/' + updateJson.hashcode + '/Image-100x75-JPG-HiQ.jpg' + '" /></a></td>';
            previewHtml += '</tr></table>';
            if(updateJson.type == 'VIDEO') {
                previewHtml += '<a href="' + updateUrl + '" class="playIcon"></a>';
            }
            previewHtml += '</div>';
        }
        var description = updateJson.description;
        if(description.length > 140) {
            description = description.substring(0, 140);
            description += '...';
        }
        var contentWidth = ((updateJson.type == 'TEXT') ? '310' : '198');
        previewHtml += '<div style="float: left; width: ' + contentWidth + 'px; overflow: hidden; font-family: Trebuchet MS; font-size: 14px; line-height: 16p;x color: #000; margin: 0px 5px 5px 0px;">'
        previewHtml += '<a href="' + updateUrl + '" style="color: #000;">';
        previewHtml += description;
        previewHtml += '</a></div>';
        previewHtml += '<div style="float: left; width: 203px; font-size: 11px; line-height: 14px; color: #a2a2a2; overflow: hidden;">';
        previewHtml += 'by <a href="' + updateUrl + '">' + updateJson.user.name + '</a>';

        if(updateJson.collections.comments.total > 0) {
            var commentImage = 'icon_comment_gray_small.gif';
            if(hasComments) {
                commentImage = 'icon_comment_green_small.gif';
            }
            previewHtml += ' | ';
            previewHtml += '<a href="' + updateUrl + '" style="color: #a2a2a2;">';
            previewHtml += updateJson.collections.comments.total;
            previewHtml += '<img src="' + topics.webBaseUrl + '/images/r2/' + commentImage + '" width="9" height="10" alt="" style="margin-left: 4px;" />';
            previewHtml += '</a>';
        }

        previewHtml += '<br/>' + updateJson.timestamp;
        previewHtml += '</div>';

        if(multiIndex != null) {
            previewHtml += '<div class="nav" style="float: left; width: 307px; height: 12px; line-height: 12px; margin-top: 7px; padding: 3px 5px; border: 1px solid #ccc; background-color: #eee;">';
            var locHashKey = point.lat() + '' + point.lng();
            var locationUpdates = topics.mapLocationsHash.get(locHashKey);
            var updateSize = locationUpdates.size();
            var remainingUpdates = (updateSize - (multiIndex + 1));

            previewHtml += '<div class="arrow">';
            if(multiIndex > 0) {
                var prevLink = 'topics.refreshBubble(\'' + locHashKey + '\', ' + (multiIndex - 1)  + '); return false;';
                previewHtml += '<a onclick="' + prevLink + '" class="newer"></a>';
            } else {
                previewHtml += '&nbsp;';
            }
            previewHtml += '</div>';
            previewHtml += '<div class="info" style="width: 289px;">' + (remainingUpdates == 0 ? 'no' : remainingUpdates)  +  ' more update' + (remainingUpdates == 1 ? '' : 's') + ' at this location</div>';
            previewHtml += '<div class="arrow">';
            if(multiIndex < (updateSize - 1)) {
                var nextLink = 'topics.refreshBubble(\'' + locHashKey + '\', ' + (multiIndex + 1)  + '); return false;';
                previewHtml += '<a onclick="' + nextLink + '" class="older"></a>';
            } else {
                previewHtml += '&nbsp;';
            }
            previewHtml += '</div>';
            previewHtml += '</div>';
        }

        previewHtml += '</div>';
        return previewHtml;
    },
    refreshBubble: function(locHashKey, index) {
        var locationUpdates = topics.mapLocationsHash.get(locHashKey);
        var updateJson = locationUpdates[index];
        var mapValues = topics.mapUpdatesHash.get(updateJson.hashcode);
        topics.openInfoBubble(mapValues.marker, updateJson, index);
    },
    checkForPageChange: function(initPage) {
        var hash = window.location.hash.substring(1);
        var params = hash.split('&');
        var pageValue = '';
        var goToTop = false;
        for(var i = 0; i < params.length; i++) {
            var pair = params[i].split('=');
            var name = pair[0];
            var value = pair[1];
            if(name == 'page') {
                pageValue = value;
            } else if(name == 'top') {
                goToTop = value;
            }
        }
        if(initPage && pageValue == '') {
            topics.loadUpdates(topics.pageNum);
        } else if(pageValue != '' && topics.pageNum != pageValue) {
            topics.stopRefresh();
            topics.pageNum = pageValue;
            topics.loadUpdates(pageValue, goToTop); 
        }
    },
    checkForTabChange: function() {
        var hash = window.location.hash;
        if(hash == '#map' && !topics.showingMap) {
            topics.mapTab();
        } else if(hash == '#feed' && topics.showingMap) {
            topics.feedTab();
        }
    }
}
document.observe("dom:loaded", topics.init);