/* REST Object::Post */
function PostHandler()
{
    this.postId = 0;
    this.postBody = "";
    
    /* GET */
    this.getPost = function($divToPopulate, postId)
    {
        var url = 'posts/'+postId+'/';
        $.get(url, function(html)
        {
            $divToPopulate.append(html);
        });
    };
    
    /* POST */
    this.savePost = function()
    {
        var self = this;
        
        var url = 'posts/';
        
        var data = { 
            post_body:this.postBody, 
            eventid:g_eventHandler.eventId 
        }; 

        $.post(url, data, function(json) 
        {
            if (json.status == 'success')
            {
                self.postId = json.id;

                // If the user's logged in, just own the post.
                // Otherwise, show the login dialog.
                if (g_profileHandler.loginStatus)
                {
                    g_postHandler.ownPost(self.postId, function()
                    {
                        // Show the comment inline.                        
                        self.showPostHTML(g_eventHandler.$singleEvent, self.postId);
                    });
                }
                else 
                {
                    // Save the postId for now
                    g_profileHandler.showLoginModalHTML(g_eventHandler.$singleEvent, self.postId);
                }
            }
            else
            {
                alert ('Comment save failed.');
            }
        },
        'json');
    };
    
    /* PUT */
    this.ownPost = function(postId, fnCallback)
    {
        /* Assumes a logged-in user. */
        var url = 'posts/'+postId+'/own_post';
        $.put(url, null ,function(json)
        {
            $('#colorbox_dummy').colorbox.close();
            if (json.success == 'true')
            {
                fnCallback();
            }
            else
            {
                alert('Failed to own post.');
            }
        }, 
        "json");
    };
    
    /* HTML Interactions*/
    this.getPostDataHTML = function(eventId)
    {
        g_eventHandler.eventId = eventId;
        g_eventHandler.$singleEvent = $('#singleCheckin' + eventId);
        this.postBody = g_eventHandler.$singleEvent.find('.checkinCommentInput').val();   
    };
    
    this.showPostHTML = function($singleCheckin, postId)
    {
        $singleCheckin.find('.addCommentPanel').toggle();

        // Populate the div with the html from a single answer.         
        var $divToPopulate = $singleCheckin.find('.checkinPosts');
        this.getPost($divToPopulate, postId);      
    };

    /* Wrappers */
    this.getDataSavePost = function(eventId)
    {
        this.getPostDataHTML(eventId);
        this.savePost();
    };

    this.authenticateFacebookOwnPost = function()
    {
        var self = this;
        
        g_profileHandler.facebookLogin(function(jsonAccountCreation)
        {
            $('#colorbox_dummy').colorbox.close();
            if (jsonAccountCreation.status == 'success')
            {            
                // Show the comment inline.
                var $singleCheckin = $('#singleCheckin' + g_eventHandler.eventId);
                g_postHandler.ownPost(g_postHandler.postId, function() 
                {
                    g_postHandler.showPostHTML($singleCheckin, g_postHandler.postId);
                });
            }
        });

    };
}


/* REST Object::Event */
function EventHandler()
{
    this.eventId = 0;
    this.$singleEvent = {};
    this.shout = "";
    
    /* GET */
    this.getEvents = function(dataType)
    {
        var url = 'events/filter_events/';
        var self = this;
        
        if (dataType == 'html')
        {
            this.hideCheckinsHTML();
        }

        params = {
            start:g_mapHandler.startDate, 
            end:g_mapHandler.endDate, 
            category:g_mapHandler.category,
            city:g_mapHandler.city,
            return_type:dataType
        };
                
        $.get(url, params, function(data){
            if (dataType == 'json')
            {
                g_geoClipHandler.clipEvents = JSON.stringify(data.checkin_list);
                //return JSON.stringify(data['checkin_list']);
            }
            else
            {
                return self.showCheckinsHTML(data);
            }
        }, dataType);
    };
    
    /* PUT */
    this.saveEvent = function()
    {
        var self = this;

        var url = 'events/'+this.eventId+'/';

        $.put(url, { shout: this.shout } , function(json)
        {
            if (json.success)
            {
                self.showEventHTML();
            }
        }, 
        "json");
    };
    
    /* HTML Interactions */
    this.inputEventHTML = function(checkinId)
    {
        this.$singleEvent = $('#singleCheckin' + checkinId);
        this.$singleEvent.find('.addShoutContainer').show();
        this.$singleEvent.find('.shout').hide();
    };

    this.getEventDataHMTL = function(eventId)
    {
        this.eventId = eventId;
        this.$singleEvent = $('#singleCheckin' + eventId);
        this.shout = this.$singleEvent.find('.shoutinput').val();

        if (this.shout == 'Add your description') 
        {
            return false;
        }
    };
    
    this.showEventHTML = function()
    {
        this.$singleEvent.find('.shoutLink').text(this.shout);
        this.$singleEvent.find('.addShoutContainer').hide();
        this.$singleEvent.find('.shout').show();
    };
    
    this.hideCheckinsHTML = function()
    {
        $('#profileData .checkins').hide();
        $('#profileData .activityWaiting').show();
    };
    
    this.showCheckinsHTML = function(html)
    {
        $('#profileData .checkins').html(html);
        $('#profileData .checkins').show();
        $('#profileData .activityWaiting').hide();
    };
    
    /* Wrappers */
    this.getDataSaveEvent = function(eventId)
    {
        if (!this.getEventDataHMTL(eventId))
        {
            this.getEventDataHMTL(eventId);
            this.saveEvent();
        }
    };
}



function MapHandler()
{
    this.cities = {};
    this.categories = {};
    
    this.cityDisplayData = {};
    
    this.startDate = "";
    this.endDate = "";
    
    this.category = "";
    this.city = "";
    this.state = "";
    
    /*  Map HTML Interaction Layout */
    this.updateMapSizeHTML = function()
    {
        // Resize the map if the window size changes
        // The width should match the viewport, minus a little buffer, and max at 1400 pixels.
        var newWidth = Math.max(Math.min($(window).width() - 60, 1400), 600);

        // Now we can set the width on each element.
        $('#profileHeader .contain').width(newWidth);
        $('#profileInfoContain').width(newWidth);
        $('#profileDataContain').width(newWidth);

        // We also need to set a fluid width on the Activity tab.
        // This should take the right panel and some buffer into account.
        var newWidthActivity = newWidth - $('#profileFriends').width() - /*buffer*/20;
        $('#profileData').width(newWidthActivity);

        // this is to make the add comment text field also fluid
        var commentInputWidth = newWidthActivity - $('.singlePost .submit').width() - /*buffer*/200;
        $('.singlePost .checkinCommentInput').width(commentInputWidth);


        // Map height should match the viewport, minus the header, minus a little below the fold.
        // Use a minimum height; for larger screens, leave a little space at the bottom for comments.
        var newHeight = Math.max($(window).height() - $('#profileInfoContain').offset().top - /*below-the-fold*/35, /*minheight*/300);  
        $('#profileInfoContain').height(newHeight);   

        // Unfortunately, since CSS doesn't provide a 'fill 100% of all available space' instead of 'fill 100% of your container's space',
        // we have to change the flash container as well.
        $('#profileMap').width(newWidth - /*border*/16);

		// Map's top relative to its container.  Can't use position() for some reason. 
        var profileMapPositionTop = $('#profileMap').offset().top - $('#profileInfoContain').offset().top;  
        $('#profileMap').height(newHeight - profileMapPositionTop - 20 - 40);
    };
 
    /*  Map HTML Interaction */
	// sets the city and calls the function on the flash map
    this.updateCity = function(selectedCity)
    {
        var values = selectedCity.split(', ');
        document.getElementById('flashCanvas').switchCity(values[0], values[1]);
        
		this.updateSelectedCityHTML(values[0]);

        this.updateCityCountsHTML();

        mpmetrics.track("Click on Map City", {"city" : values[0], "state" : values[1], "count" : this.cities[values[0]] });
        _gaq.push(['_trackEvent', 'HTML Interaction', 'Click on Map City', values[0], this.cities[values[0]] ]);
    };

	// updates the counts next to the city names
    this.updateCityCountsHTML = function() 
    {
        var self = this;

        $('.cityDropdownOption').each(function(index, element) {
            // current text
            var current = element.innerHTML;

            // grab the city name, kind of dumb way to do it
            current = current.split(' (').shift();

            // add the number of checkins if we have them
            if (self.cities[current]) {
                element.innerHTML = current + ' (' + self.cities[current] + ')';
            }
            else {
                element.innerHTML = current;
            }
        });
    };
    
	// updates the selected city text
    this.updateSelectedCityHTML = function(selectedCity)
    {
        document.getElementById('selectedCityLink').innerHTML = selectedCity;
        this.city = selectedCity;
    };
    
	// adds a city to the dropdown
    this.addCityHTML = function(city, cityListHTML)
    {
        if (!this.cities[city] && city.length)
        {
            // add a list item to the dropdown
            // <li onclick="updateCity('San Francisco, CA');"><span>San Francisco</span></li>
            $("#cityDropdownOptions").append(cityListHTML);
        }
    };

	// sets the category and calls the function on the flash map
	this.updateCategory = function(category)
	{
        document.getElementById('flashCanvas').setCategory(category);
		
		this.updateSelectedCategoryHTML(category);

        mpmetrics.track("Click on Category", {"category" : category});
        _gaq.push(['_trackEvent', 'HTML Interaction', 'Click on Map Category', category]);
	};
	
	this.addDropdownItemHTML = function(dropdownID, name, callbackFunction)
	{
		var html = "<li onclick=\"" + callbackFunction + "\"><span class=\"dropdownOption\">" + name + "</span></li>";
		$(dropdownID).append(html);
	};
    
    this.addCategoryHTML = function(category)
    {
		if (!this.categories[category] && category.length)
		{
			var html = "<li onclick=\"g_mapHandler.updateCategory('" + category + "');\"><span class=\"categoryDropdownOption\">" + category + "</span></li>";
			$("#categoryDropdownOptions").append(html);
		}
    };
    
    this.updateSelectedCategoryHTML = function(selectedCategory)
    {
		document.getElementById('selectedCategoryLink').innerHTML = selectedCategory;
		this.category = selectedCategory;
    };
    
    /* Map Flash Interaction - Data */
    this.getMapFlash = function()
    {
        return $('#flashCanvas')[0];
    };
    
    this.getCategoryFlash = function(category)
    {
        this.category = category;
    };
    
    this.getTimeRangeFlash = function(startEndString)
    {
        this.startDate = parseInt(startEndString.split(',')[0], 10);
        this.endDate = parseInt(startEndString.split(',')[1], 10);
    };
    
    this.getCityStateFlash = function(selectedCity, selectedState)
    {
        this.city = selectedCity;
        this.state = selectedState;
    };
    
    this.getParamsFlash = function(startEndString, category, city, state)
    {
        this.getTimeRangeFlash(startEndString);
        this.getCategoryFlash(category);
        this.getCityStateFlash(city, state);
    };
    
    /* Map Flash Interaction - User */
    this.clickedOnVenueFlash = function(name, city)
    {
        mpmetrics.track("Click on Venue", {"name" : name, "city" : city });
        _gaq.push(['_trackEvent', 'Flash Interaction', 'Click on Venue', name+' in '+city]);    
    };

    this.clickedOnFriendFlash = function(name)
    {
        mpmetrics.track("Click on Friend", {"name" : name });
        _gaq.push(['_trackEvent', 'Flash Interaction', 'Click on Friend', name]);         
    };
    
    this.finishedAnimationFlash = function()
    {
        mpmetrics.track("Animation", {"action" : "end", "city" : $('#selectedCityLink').html() });
        _gaq.push(['_trackEvent', 'Flash Animation', 'End', $('#selectedCityLink').html()]);     
    };
    
    this.loadedMapFlash = function()
    {
        mpmetrics.track("Loaded Map", {"city" : $('#selectedCityLink').html() });
        _gaq.push(['_trackEvent', 'Flash Animation', 'Load', $('#selectedCityLink').html()]);     
    };

    this.startedAnimationFlash = function()
    {
        mpmetrics.track("Animation", {"action" : "start", "city" : $('#selectedCityLink').html() });
        _gaq.push(['_trackEvent', 'Flash Animation', 'End', $('#selectedCityLink').html()]);
    };

    /* Utils */
    this.formatTimeRange = function()
    {
        return {'start': new Date(this.startDate).toString("MM/dd/yy"), 'end': new Date(this.endDate).toString("MM/dd/yy")};
    };
    
    /* Wrappers */    
    this.getParamsGetCheckins = function(startEndString, category, city, state, reload)
    {
        this.getParamsFlash(startEndString, category, city, state);

        if(reload != "false")
        {            
            g_eventHandler.getEvents('html');
            g_geoClipHandler.getEventListView();
        }

        g_profileHandler.updateFilterDateHTML();
    };

    this.getCityUpdateCityCounts = function(cityState, count)
    {
        // Strip stray quotes
        cityState = stripQuotes(cityState);

        var city = cityState.split(', ').shift();
		var html = "<li onclick=\"g_mapHandler.updateCity('" + cityState + "');\"><span class=\"cityDropdownOption\">" + city + "</span></li>";

        this.addCityHTML(city, html);        
        this.cities[city] = count;

        // refresh the divs
        this.updateCityCountsHTML();
    };
}



function GeoClipHandler()
{
    this.clipTitle = "";
    this.clipDescription = "";
    
    this.clipEvents = [];
    
    this.clipParams = "";
    
    /* POST */
    this.saveGeoClip = function(fnCallback)
    {
        var self = this;
        
        var url = 'geoclips/';
        
        var data = { 
            name: this.clipTitle,
            description: this.clipDescription,
            event_list: this.clipEvents,
            params: this.clipParams
        }; 

        $.post(url, data, function(json) 
        {
            if (json.success == true)
            {
                if (fnCallback)
                {
                    $("#colorbox_shareclip").colorbox.close();
                    fnCallback();
                }
            }
            else
            {
                alert ('GeoClip save failed.');
            }
        },
        'json');
    };
    
    /* HTML Interactions*/
    this.getGeoClipParamsHTML = function()
    {
        this.clipTitle = $('#clipTitle').attr('value');
        this.clipDescription = $('#clipDescription').attr('value');
        this.clipParams = JSON.stringify({
            start_date: g_mapHandler.startDate,
            end_date: g_mapHandler.endDate,

            category: g_mapHandler.category,
            city: g_mapHandler.city,
            state: g_mapHandler.state
        });
    };
    
    this.getEventListView = function()
    {
        g_eventHandler.getEvents('json'); 
    };
    
    
    
    /* Wrappers */
    this.getDataSaveGeoClip = function(fnCallback)
    {
        this.getGeoClipParamsHTML();
        
        this.saveGeoClip(fnCallback);
    };
    
    
}

function ProfileHandler()
{
    this.userSlug = "";
    this.firstName = "";

    this.loginStatus = false;
    this.facebookUid = 0;
        
    /* Geo Profile HTML Interaction */
    this.getSharingUrlHTML = function()
    {
        var userSlugs = g_mapHandler.getMapFlash().getUsers(); 
        var url = window.location.href;
        if (userSlugs)
        {
            url += '?u=' + userSlugs; 
        }

        return url;
    };
    
    this.updateShareButtonHTML = function()
    {   
        var buttonHTML = "Share " + g_mapHandler.formatTimeRange().start +" to "+g_mapHandler.formatTimeRange().end;
        $('#shareLink').html(buttonHTML);
    };

	this.updateFilterDateHTML = function()
	{
        var buttonHTML = "from " + g_mapHandler.formatTimeRange().start +" to "+g_mapHandler.formatTimeRange().end;
		$('#mapFilterTimeStamp').html(buttonHTML);
	};
    
    this.shareTwitterLinkHTML = function()
    {
        window.open('http://twitter.com/home?status=Check out where I\'ve been: ' + 
            this.getSharingUrlHTML(), 'twitterwindow');
        
        mpmetrics.track("Click share", {'service' : 'Twitter' });
        _gaq.push(['_trackEvent', 'Share', 'Twitter']);
    };

    this.shareFacebookLinkHTML = function()
    {
        window.open('http://www.facebook.com/sharer.php?u=' + this.getSharingUrlHTML(), 'facebookwindow', 'width=500,height=350');
        
        mpmetrics.track("Click share", {'service' : 'Facebook' });
        _gaq.push(['_trackEvent', 'Share', 'Facebook']);
    };

    this.shareFacebookMapHTML = function()
    {  
        g_mapHandler.getTimeRangeFlash($('#flashCanvas')[0].getTimeRange());
        var userName = this.firstName;
        var baseURL = window.location.href.match(/:\/\/(.[^/]+)/)[1];
        
        var returnURL = 'http://'+baseURL + '/'+this.userSlug + '/?' + 'start='+g_mapHandler.startDate + '&end='+g_mapHandler.endDate + 
            '&city='+g_mapHandler.city + '&state='+g_mapHandler.state + '&category='+g_mapHandler.category;
        var returnURLText = g_geoClipHandler.clipDescription + " - <br/> www.weeplaces.com/" + this.userSlug;

        var postBody = "";
        if (g_geoClipHandler.clipTitle.length > 0)
        {
            postBody = g_geoClipHandler.clipTitle + " [" + g_mapHandler.formatTimeRange().start + " - "+g_mapHandler.formatTimeRange().end + "]";
        }
        else
        {
            postBody = "My life visualized from "+g_mapHandler.formatTimeRange().start +" to "+g_mapHandler.formatTimeRange().end;
        }
        
        var swfURL = 'http://'+baseURL + '/media/swf/checkinhistory.swf?user=' + this.userSlug + '&mode=embed&json_parser=flash'+ 
            '&start='+g_mapHandler.startDate + '&end='+g_mapHandler.endDate + 
            '&city='+g_mapHandler.city + '&state='+g_mapHandler.state + '&category='+g_mapHandler.category;
            
        var imgURL = 'http://www.weeplaces.com/media/images/fbbackdrop.png';
        
         FB.ui(
            {
              display: 'popup',
              method: 'stream.publish',
              message: 'Dude, check out these check ins! ',
              attachment: {
                  name: postBody,
                  caption: returnURLText,
                  href: returnURL,
                  'media': [{
                      'type': 'flash', 
                      'swfsrc': swfURL,
                      'expanded_width': '500', 
                      'expanded_height': '400', 
                      'imgsrc': imgURL, 
                      'allowscriptaccess':'always',
                      'width': '175', 
                      'height': '140' 
                    }]
                  
            },
            action_links: [
                { text: 'weeplaces.com', href: returnURL }
            ],
                user_message_prompt: 'Share your clip with friends:'
            },
            function(response) 
            {
                if (response && response.post_id) 
                {
                    // alert('Post was published.');
                } 
                else 
                {
                    // alert('Post was not published.');
                }
            }
        );
    };
    
    this.showShareModalHTML = function()
    {
        $("#colorbox_shareclip").colorbox({
            width:"600px",
            height:"400px",
            inline:true,
            scrolling:false,
            href:"#profileShareModal"

        });

        $("#colorbox_shareclip").click();
    };
    
    this.showLoginModalHTML = function($singleEvent, postId)
    {
        $("#colorbox_dummy").colorbox({
            width:"400px",
            height:"220px",
            inline:true,
            scrolling:false,
            href:"#profileLoginModal"

        });

        $("#colorbox_dummy").click();

        $('div#profileLoginModal .noLogin a').click(function() 
        {
            $('#colorbox_dummy').colorbox.close();
        });
    };
    
    /* Authentication */
    this.bindFoursquareButton = function(userSlug)
    {
        $('div#profileLoginModal .foursquareButton').bind('click', function()
        {
            var returnUrl = '/' + userSlug + '/' + '?postId=' + g_postHandler.postId;  
            window.location.href = '/fsq/auth/?returnUrl=' + returnUrl;                        
        });
    };

    this.facebookLogin = function(fnCallback)
    {
        var self = this;
        
        FB.login(function(response)
        {
            if (response.session) 
            {
                g_profileHandler.loginStatus = true;
                
                // First we need to create an account for this user.
                self.authenticateFbcInline(function(json)
                {
                    if (fnCallback)
                    {
                        fnCallback(json); // Callback with the results of the FB creation/auth
                    }
                    
                });
                
            } 
            else 
            {
                alert('Problem Logging Into Facebook');
            }
          
        }, { perms:'user_checkins, offline_access, publish_stream, email' });
        
    };

    this.authenticateFbcInline = function(fnCallback) 
    {
        // at this point, the user is successfully logged in to FBC, but not our site.

        // Create the account on our end.
        $.post('/fb/authfbaccount/', function(json)
        {
            if (json.status == 'success') 
            {
                // alert ('successful FB auth');
                if (fnCallback)
                {
                    fnCallback(json);
                }
            }
            else 
            {
                alert(json.message);        
            }
        },
        "json");

    };
    
    /* Wrappers */
    this.loginUser = function(loginType, oauthUrl, makePrivate)
    {
        // If we're using facebook, log the user in inline and send them directly to the map. 
        if (loginType == 'facebook')
        {
            this.createGeoProfileFb(makePrivate);
        }
        else if (loginType == 'foursquare' || loginType == 'gowalla')
        {
            // If we're using foursquare, send the user to the oauthUrl, which will later redirect to the map. 
            if (makePrivate)
            {
                window.location = oauthUrl + '?make_private=yes';
            }
            else
            {
                window.location = oauthUrl;
            }
        }
    };
    
    this.createGeoProfileFb = function(makePrivate)
    {
        // Login the user to facebook, then get their data.
        this.facebookLogin(function(jsonAccountCreation)
        {
            if (jsonAccountCreation.status == 'success')
            {
                // send the user to their new map page.  This will also refresh the profile (flag set in the auth view)
                window.location.href = jsonAccountCreation.usergeoprofile;
            }
            else
            {
                alert('Error creating map.');
            }
        }, 
        'json');
    };
}





// Replace the 'checkins' div with the activity contents.
// Tries recursively (with stack reset) until there's no more to refresh.
// Note: had to use recursion since blocking sleep/wait in JS isn't available.

// The function waits for checkins to stabilize or to reach more than 20, then calls inline_checkin to populate the div.
function getCheckinsDelayed(userSlug, tryIndex, refreshTarget, lastKnownCheckinServiceId)
{
    // We won't try forever.
    if (tryIndex > 6)
    {
        return;
    }

    
    var url = '/' + userSlug + '/check_refresh_state/?refreshtarget=' + refreshTarget;
    
    $.get(url, function(json) 
    {
        // Wait for a checkin with a higher number - then refresh.
        if (json.currentcheckinid == 0 || 
            json.currentcheckinid == lastKnownCheckinServiceId)
        {
            // The checkins aren't done yet.
            
            // Try again with a stack reset.
            var timeout = (Math.pow(tryIndex, 2) * 1000) + 2000; // Exponentially add timeout
            setTimeout(function() 
            {
                getCheckinsDelayed(userSlug, ++tryIndex, refreshTarget, lastKnownCheckinServiceId);        
            }, 
            timeout);
        }
        else
        {
            // Ok, time to refresh the checkins inline!
            var urlData = '/' + userSlug + '/inline_checkins/'; 
            $.get(urlData, function(html)
            {
                $('#profileActivity').html(html);
                $('#profileData .activityWaiting').hide();
            }); 
            
        }
        
    },
    'json');
}



$(document).ready(function() 
{
    g_mapHandler = new MapHandler();
    
    g_profileHandler = new ProfileHandler();
    g_postHandler = new PostHandler();
    g_eventHandler = new EventHandler();
    g_geoClipHandler = new GeoClipHandler();
    
});

