// Custom functions and helpers for use with Facebook JavaScript SDK.
// Dependencies: BBQ - http://benalman.com/projects/jquery-bbq-plugin/
// USAGE:
// 1. fbAsyncInit is called by Facebook SDK when loaded, we need to init our own Facebook module
// window.fbAsyncInit = function() {
//     EB.Facebook.init();
// };
// 
// 2. Load the FB SDK into the fb-root div
// EB.Facebook.asyncLoadSDK('fb-root');     

EB.Facebook = (function($, EB){
    
    var asyncLoadSettings = {
        root: 'fb-root',
        timeoutMilliseconds: 1000
    };
        
    var isSDKLoaded = false;
    
    var requiredPermsArray = [];
    // ['read_stream', 'publish_stream', 'offline_access', 'read_friendlists']
    var requiredPerms = requiredPermsArray.join(',') ;
    
    // Has the user granted all the required Facebook permissions.
    function hasRequiredPerms() {
        var currentPerms = EB.Facebook.loginStatus['perms'];

        // Search for each required permission
        for (var i = requiredPermsArray.length - 1; i >= 0; i--) {
            // if the perm is not found, fails test
            if (currentPerms.search(requiredPermsArray[i]) < 0) {
                return false;
            }
        };
        return true;
    };
    
    // Return a function to generate action objects mutating a baseAction
    // baseAction is of the form  {name: '', category: '', pageModule: ''}
    // pageModule is optional, and is prepended to the action name.
    // an example pageModule is 'lightbox'
    function actionGenerator(baseAction){
        // The return function takes a subAction
        // subAction is also optional and is appended to the action name.
        // this allows us to track the different interactions with a particular widget
        // for example: 'click' or 'error' or 'cancel'
        return function(subAction){
            var actionName = baseAction.name;
            if (!!baseAction.pageModule && typeof(baseAction.pageModule === 'string')){
                actionName = baseAction.pageModule + '_' + baseAction.name;
            }
            if (!!subAction && typeof(subAction === 'string')){
                actionName = actionName + '_' + subAction;
            }
            return $.extend({}, baseAction, {name: actionName});
        };
    };
    
    return {
        
        // Cached copy of Facebook login status.
        loginStatus: {
            session: null,
            status: 'unknown',
            perms: ''
        },
        
        // Array of functions to call when Facebook has initialized
        initCallbacks: [],
      
        // Initialize Facebook SDK and cache loginStatus
        init: function() {
            EB.log('FB init...');
            // once we call init, assume the SDK is loaded
            // used for the timeout in asyncLoadSDK
            isSDKLoaded = true;
            
            //NOTE: SSL stream.publish breaks in IE when initializing with apiKey.
            FB.init({
                // apiKey: '4395093c0ee84afb03427ba33818fb1e',
                appId: '28218816837',                    
                status : true, // check login status
                cookie: true,
                xfbml: true
            });                  
            
            // Cache current loginStatus
            FB.getLoginStatus(function(response) {
                this.loginStatus = response;
            });
        
            // Cache changes to loginStatus
            FB.Event.subscribe('auth.sessionChange',
            function(response) {
                this.loginStatus = response;
            });
            
            FB.Event.subscribe('edge.create', function(href, widget) {
                EB.Analytics.recordAction({name: 'like', category: 'facebook'});
            });
            
            $.each(EB.Facebook.initCallbacks, function(index, cb) { 
                cb();
            });            
        },
        
        // Asynchronously load Facebook JavaScript SDK.
        // Settings:
        // root - a div to append the javascript to
        // timeoutCallback - function to call if the loading takes too long
        // timeoutMilliseconds - 
        asyncLoadSDK: function(settings) {
            var s = $.extend(true, asyncLoadSettings, settings || {});
            
            // call our timeout callback if we haven't loaded SDK in time.
            if (s.timeoutCallback && typeof(s.timeoutCallback) == 'function'){
                setTimeout(function(){
                    if (!isSDKLoaded){
                        EB.log('Facebook SDK not loaded in time.');
                        s.timeoutCallback();
                    } else{
                        EB.log('Facebook SDK has been loaded in time!');
                    }
                }, s.timeoutMilliseconds);
            }
            
            var e = document.createElement('script');
            e.async = true;
            e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
            document.getElementById(s.root).appendChild(e);
         },

        // Ensure the user has logged in and granted permissions then show the Facebook share dialog.
        // Settings params:
        // *event
        // success
        // error
        streamPublish: function(settings) {
            if (typeof(settings) !== 'object'){
                EB.log('Settings object required.');
                return;
            }
            if (typeof(settings.event) !== 'object'){
                EB.log('Event required to share event.');
                return;
            }
            var event = settings.event;
            
            var getAction = actionGenerator({name: 'streampublish', category: 'facebook', pageModule: settings.pageModule});
            
            EB.Analytics.recordAction(getAction('click'));
            
            this.loginRequired(function(){
                var properties = {};
                
                if (event.location) {
                    properties['Location'] = EB.util.truncate(event.location, 70); 
                }
                if (event.time) {
                    properties['Time'] = EB.util.truncate(event.time, 70);
                }
                if (event.host && event.host_href){
                    properties['Hosted By'] = {
                        text: EB.util.truncate(event.host, 50),
                        href: event.host_href
                    };
                }
                
                // var linebreak_regex = /(\s|\u00A0)+/g;
                // NOTE: We need to keep our attachments short.
                // Long attachments switch to HTTP POST, and there is a Facebook bug with the encoding POST data.
                // See: http://bugs.developers.facebook.com/show_bug.cgi?id=10439
                var attachment = {
                    name: 'Eventbrite - ' + event.name,
                    caption: '{*actor*} registered for ' + event.name + ' at Eventbrite!',
                    properties: properties,
                    // NOTE: It seems the attachment description should be 300 characters or less
                    // The documentation says it accepts upto 1000 characters though...
                    // See: http://wiki.developers.facebook.com/index.php/Attachment_(Streams)
                    // description: EB.util.truncate(event.description, 50),
                    href: event.href,
                    media: [{
                        'type': 'image',
                        'src': event.image,
                        'href': event.href
                    }]
                };
                
                FB.ui(
                {
                    method: 'stream.publish',
                    display: 'dialog',
                    attachment: attachment,
                    action_links: [{
                        'text': event.action_text,
                        'href': event.action_href
                    }]
                },
                function(response) {
                    EB.log(response);
                    if (response && response.post_id) {
                        EB.log('Post was published.');
                        // success action has no subAction currently.
                        EB.Analytics.recordAction($.extend({}, getAction(), {id: response.post_id}));
                        if (typeof(settings.success) === 'function') {
                            settings.success();
                        }
                    } else {
                        if (response && response.error) {
                            EB.log('Error stream.publishing event: ' + response.error);
                            EB.Analytics.recordAction(getAction('error'));
                            
                        } else {
                            EB.log('Post was not published.');
                            EB.Analytics.recordAction(getAction('cancel'));
                        }  
                        if (typeof(settings.error) === 'function'){
                            settings.error();
                        }
                    } 
                }
                );    
            }, settings.error, getAction('cancel_connect'))();
        },
        
        streamShare: function(settings){
            var s = $.extend(true, {method:'stream.share'}, settings || {});
            EB.log(s);
            FB.ui(
                s,
                function(response){
                    if (response && response.post_id) {
                        EB.log('Post was published.');
                        EB.Analytics.recordAction({name: 'share', category: 'facebook'});
                    } else {
                        if (response && response.error) {
                            EB.log('Error stream.sharing event: ' + response.error);
                        } else {
                            EB.log('Post was not shared.');
                        }  
                    }
                }
            );
        },
        
        // Ensure user has granted Facebook permissions, then show friend selector to send invites to friends.
        // required settings:
        // event - info about the event
        // target - div to inject invite friends fbml into
        // optional settings:
        // error - this is the callback when an error occurs
        inviteFriends: function(settings){
            var event = settings.event;
            var target = settings.target;
            
            var getAction = actionGenerator({name: 'invite', category: 'facebook', pageModule: settings.pageModule});
            EB.Analytics.recordAction(getAction('click'));
            
            return this.loginRequired(function() {
                // Show multifriend selector to invite friends
                // Root for facebook server side FBML iframe
                var server_fbml = '<fb:serverFbml id="inviteserver"></fb:serverFbml>';

                // The FBML for the request that gets sent to friends
                var invite_content = "I just got my tickets for '" + event.name + "', check it out. " +
                    "<fb:req-choice url='" + event.action_href + "' label='" + event.action_text +"' />";
                    
                
                var post_back_url = $.param.querystring(window.location.href, 'facebook_invite=1');
                
                // FBML for multifriend selector
                // post back to current url with param facebook_invite=1
                var invite_fbml = '<script type="text/fbml">'
                                       + '<fb:fbml>'
                                            // the 168 left padding moves the invite form to the center of the iframe.
                                           + '<style> div {background-color:#F4F6F7;} .findfriends, .platform_ci_msg {padding-left:20px;} .platform_ci_msg {padding-top:14px;}</style>'
                                            + '<fb:request-form style="padding-left:168px;" action="' + post_back_url + '" '
                                                                    + 'method="POST" invite="true" type="event" content="' + invite_content + '" >'
                                                + '<fb:multi-friend-selector import_external_friends="false" bypass="cancel" cols="5" showborder="false" email_invite="false"'
                                                                                        + 'actiontext="Invite your friends to this event."/>'
                                            + '</fb:request-form>'
                                        + '</fb:fbml>'
                                    + '</script>';
                                        
                $(target).empty().append(server_fbml);
                $('#inviteserver').append(invite_fbml);
                FB.XFBML.parse();
            }, settings.error, getAction('cancel_connect'))();
        }, 
        
        // Wrap a function to ensure user has granted all Facebook perms, then yield to original function.
        loginRequired: function(fn, error, cancelAction) {
            return function() {
                EB.log("Check if user is connected and has required permissions.");
                FB.login(
                function(response) { 
                    EB.log("Login response:");
                    EB.log(response);
                    EB.Facebook.loginStatus = response;
                    if (response.session) {
                        if (hasRequiredPerms()) {
                            EB.log("Has perms...");
                            fn.apply(this, arguments);
                        } else {
                            EB.log('User did not grant all permissions, cancel.');
                            if (typeof(error) === 'function'){
                                error();
                            }
                            if (!!cancelAction){
                                 EB.Analytics.recordAction(cancelAction); 
                            }
                        }
                    } else {
                        EB.log('User did not login.');
                        if (typeof(error) === 'function'){
                            error();
                        }
                        if (!!cancelAction){
                              EB.Analytics.recordAction(cancelAction); 
                         }
                    }
                },
                {
                    perms: requiredPerms
                });   
            };
        }
     };
}(jQuery, EB));
