// Copyright 2010 OverInteractive Media Inc. All rights reserved.

/*global $, DR, FB, window */

/**
 * Communication with Facebook.
 */
DR.extend('Facebook', {

    initialized: false,
    userInfo: {},
    loadedUsernames: {},
    _callbacks: [],
    _appUrl: '',
    _infoSentToGame: false,

    /**
     * Initialize.
     *
     * @param {Object}  initData    Information to initialize Facebook with.
     */
    init: function(initData) {
        var _this = this;

        // Calling Facebook's auto resize instantly causes it to fail
        // occasionally, so trigger it after a brief pause
        window.setTimeout(function() {
            FB.Canvas.setAutoResize();
        }, 250);

        FB.init({
            appId: initData.appId,
            status: true,
            cookie: true,
            xfbml:  true,
            oauth : true
        });
        
        
        $('.i-permissions').click(function() {
            FB.login( function(response) {
                DR.log(response);
            }, {scope : 'read_stream, offline_access, read_insights, user_likes, manage_pages, create_note, user_videos'});

        });
        
        $('.i-facebook-login').click( function() {
			DR.Facebook.login();
			return false; // Required because KHV's button function adds a href="#" to the anchor
        });

        // Initialize the JS SDK's access to Graph
        FB.getLoginStatus(function(response) {

            DR.log(response);
            if (response.authResponse) {
                
                //window.Arcade.user.signed_request = response.authResponse.signedRequest;
                window.Arcade.user.expires        = response.authResponse.expiresIn;
                window.Arcade.user.access_token   = response.authResponse.accessToken;

                // Run any callbacks that were defined
                DR.Facebook.loadUserInfo(window.Arcade.user.fbid, DR.Facebook.setLocalUser);
                //DR.SvaApi.setAuthToken(response.authResponse.accessToken);
                
                DR.log('Running Facebook callbacks');
                _this.initialized = true;
                _this.checkDevPermissions();
            
                if(window.Arcade.user.fbid == '' && window.Arcade.reload === true) {
                    DR.log('Redirecting');
                //    redirectToAuth();
                }
            } else {
                DR.log('Not logged in');
                // No user session available; this shouldn't happen
            }
        });
		
		FB.Event.subscribe('edge.create',
		            function(response) {
		                // if the achievement-related like button (determined by url), call event in sva-api
						if(response == 'http://www.facebook.com/apps/application.php?id=' + window.Arcade.appId) {
							DR.Sva.like(response);
						}
		            }
		        );

        this._appUrl = initData.appUrl;
        this.setAppLinkHandlers();
    },
	
	login : function() {
	    FB.login(function() {
            DR.Facebook.checkStatus();
        }, {scope: 'email, read_stream, offline_access'});//NB: Duplicated in khv.js
    },
	
	checkStatus : function() {
	  FB.getLoginStatus(function(response) {
		  if (response.authResponse) {
			  // if a query string i.e. '?' is present in the URL, cut all proceding characters off
			  // and add the '?signed_request=..&login=1' string to the URL in its place
			  var queryPosition = window.location.toString().indexOf('?', 0);
			  var hashPosition = window.location.toString().indexOf('#', 0);
			  if(queryPosition != -1){
				newLocation = window.location.toString().substr(0, queryPosition)+'?signed_request='+response.authResponse.signedRequest;
			  }
			  else if(hashPosition != -1){
				newLocation = window.location.toString().substr(0, hashPosition)+'?signed_request='+response.authResponse.signedRequest;
			  }
			  else{
				newLocation = window.location+'?signed_request='+response.authResponse.signedRequest;
			  }
		  }
		  
		  $('#i-form-fblogin').attr('action', newLocation);
		  $('#i-form-fblogin').submit();
		  
	  });
	},
		
	setLocalUser : function(data) {
        DR.log("Facebook::Set Local User", data);
        window.Arcade.user.first_name = data.first_name;
        window.Arcade.user.last_name  = data.last_name;
        window.Arcade.user.name       = data.name;
        
       // DR.SvaApi.setName(window.Arcade.user.name, window.Arcade.user.first_name);
    },

    checkDevPermissions: function() {
        var _this = this;

        FB.api({
            method: 'fql.query',
            query: 'SELECT uid FROM permissions WHERE email = 1 AND uid = me()'
        },
        function(response) {
            if (response[0] == undefined) {
                //redirectToAuth();
            } else {
                _this.runCallbacks();
            }
        });
    },

    /**
     * Called when Facebook has been loaded/initialized in the client JS.
     * If Facebook Connect-JS is ready run the callback immediately.
     *
     * @param {Function}    cb  Callback to run when Facebook is ready.
     */
    onReady: function(cb) {
        if (typeof cb === 'function') {
            if (this.initialized) {
                cb();
            } else {
                this._callbacks.push(cb);
            }
        }
    },

    /**
     * Runs the callbacks.
     */
    runCallbacks: function() {
        for (var cb in this._callbacks) {
            if (this._callbacks.hasOwnProperty(cb)) {
                this._callbacks[cb]();
            }
        }
    },

    /**
     * Sets custom handler on a.fb-app-link links to always reload top frame.
     */
    setAppLinkHandlers: function() {
		if (window.Arcade.layout == 'connect') {
			$('a.fb-app-link').each(function(){
				$(this).attr('href','/'+ window.Arcade.layout +'/'+ $(this).attr('href') + "/?signed_request="+window.Arcade.user.signed_request);
			});
		} else {
			$('a.fb-app-link').live('click', function() {
				var url = $(this).attr('href');
				DR.Util.loadUrl(url);
				return false;
			});
		}
    }, 

    /**
     * Loads Graph data from Facebook for the logged in user and sends it to
     * the game.
     */
    sendUserInfoToGame: function() {
        var _this = this;

        function send() {
            // Don't bother trying to talk to the game if it's not ready
            if (DR.Comm.gameReady && !_this._infoSentToGame) {
                var userInfoJson = JSON.stringify(_this.userInfo);
                DR.log('Sending info to game', userInfoJson);
                DR.Comm.gameCall('setUserInfo', userInfoJson);
                _this._infoSentToGame = true;
            }
        }

        if (!this.isUserInfoSet()) {
            var info;
            var friends;
            var gameFriends;

            // Once both friends and user info are loaded, combine the returned
            // info and send it to the game
            function setUserInfo() {
                _this.userInfo = info;
                _this.userInfo.friends = friends;
                _this.userInfo.gameFriends = gameFriends;
                send();
            }

            // Fetch user info
            this.loadUserInfo('/me', function(response) {
                DR.log("here");
                info = response;

                // Only store the user info if friend info has been loaded
                if (friends && gameFriends) {
                    setUserInfo();
                }
            });

            // Fetch friends info
            this.loadFriends(function(response) {
                friends = response;

                // Fetch game friends
                _this.loadGameFriends(friends, function(gameFriendsResponse) {
                    gameFriends = [];

                    // Fill the appFriends array using info from the already
                    // fetched friend info
                    for (var i = 0; i < gameFriendsResponse.length; i++) {
                        var id = gameFriendsResponse[i];

                        for (var j = 0; j < friends.length; j++) {
                            var friend = friends[j];

                            if (id == friend.id) {
                                gameFriends.push(friend);
                                break;
                            }
                        }
                    }

                    // Only store friend info if user info has been loaded
                    if (info) {
                        setUserInfo();
                    }
                });
            });
        } else {
            send();
        }
    },

    /**
     * Loads usernames from an array of Facebook IDs.
     *
     * @param {Array.<String>}  ids Facebook IDs.
     * @param {Function}        cb  Callback to run when information is fetched.
     */
    loadUsernames: function(ids, cb) {
        if (!ids || ids.length === 0) {
            cb();
            return;
        }

        var _this = this;

        this.onReady(function() {
            var query = FB.Data.query('SELECT name, uid FROM user WHERE uid ' +
                'IN ({0})', ids);
            query.wait(function(rows) {
                // Cache the fetched usernames
                $.each(rows, function(i, row) {
                    var key = 'id' + row.uid;
                    _this.loadedUsernames[key] = row;
                });

                cb(_this.loadedUsernames);
            });
        });
    },

    /**
     * Loads Facebook Graph info for the specified user.
     *
     * @param {String}      facebookId  Facebook ID.
     * @param {Function}    cb          Callback to run after information fetch.
     */
    loadUserInfo: function(facebookId, cb) {
        FB.api(facebookId, function(info) {
            // Add the URL to the user's profile picture
            info.picture = '//graph.facebook.com/' + info.id +
                '/picture';
            cb(info);
        });
    },

    /**
     * Loads the current user's friends info.
     *
     * @param {Function}    cb  Callback to run on successful fetch.
     */
    loadFriends: function(cb) {
        this.onReady(function() {
            FB.api('/me/friends', function(response) {
                var friends = response.data;

                // Add the URL to the friend's profile picture
                for (var i = 0; i < friends.length; i++) {
                    var friend = friends[i];

                    friend.picture = '//graph.facebook.com/' +
                        friend.id + '/picture';
                }
                DR.log('App friends', friends);
                if (cb) {cb(friends);}
            });
        });
    },

    /**
     * Loads the current user's app friends.
     *
     * @param {Function}    cb  Callback to run on successful fetch.
     */
    loadAppFriends: function(cb) {
        this.onReady(function() {
            FB.api({
                method: 'friends.getAppUsers'
            }, function(friends) {
                DR.log('App friends', friends);
                if (cb) {cb(friends);}
            });
        });
    },

    /**
     * Loads the current user's game friends.
     *
     * @param {Array.<Object>}  friends The user's friends.
     * @param {Function}        cb      Callback to run on successful fetch.
     */
    loadGameFriends: function(friends, cb) {
        // Create comma-separated list of friends
        var ids = [];

        for (var i = 0; i < friends.length; i++) {
            var id = friends[i].id;
            ids.push(id);
        }

        var idsStr = ids.join(',');

        DR.Comm.getRequest(DR.APIControllers.profile.getGameFriends,
            {friends: idsStr},
            function(response) {
                cb(response);
            });
    },

    /**
     * Checks whether user info has been loaded from Facebook.
     *
     * @return {Boolean} True if the info has indeed been loaded.
     */
    isUserInfoSet: function() {
        return !$.isEmptyObject(this.userInfo);
    },

    /**
     * Gets the full URL for the Facebook app.
     *
     * @param {String}  url The URL fragment.
     * @return {String} The full URL.
     */
    getFullPath: function(url) {
        return (url.substr(0, 1) == '/') ?
            this._appUrl + url.substr(1) :
            this._appUrl + url;
    },

    /**
     * Posts a message to the user's wall.
     *
     * @param {String}          userMessagePrompt   A prompt message.
     * @param {Object}          attachment          Additional info to include.
     * @param {Array.<Object>}  actionLinks         Links to include at bottom.
     */
    publishWallPost: function(userMessagePrompt, attachment, actionLinks) {
        if (!userMessagePrompt) {
            userMessagePrompt = 'Share';
        }

        if (!attachment) {
            attachment = {};
        }

        if (!actionLinks) {
            actionLinks = [];
        }

        this.onReady(function() {
             FB.ui({
                method: 'stream.publish',
                message: '',
                attachment: attachment,
                action_links: actionLinks,
                user_message_prompt: userMessagePrompt
            }, function(response) {
                if (response && response.post_id) {
                    DR.log('Stream story published');
                } else {
                    DR.log('Stream story not published');
                }
            });
        });
    },

    /**
     * Creates a wall post prepopulated with activity feed information.
     *
     * @param {Object}  item    The activity feed item information.
     */
    publishActivityFeedWallPost: function(item) {
        var url = '//apps.facebook.com/dimerocker/play/' + item.shortname;

        var attachment = {
            name: item.name,
            caption: 'On the dimeRocker Arcade.',
            description: item.message,
            href: url,
            media: [
                {
                    type: 'image',
                    src: item.icon,
                    href: url
                }
            ]
        };

        var actionLinks = [
            {text: 'Play', href: url}
        ];

        this.publishWallPost(
            'Share your progress in ' + item.name,
            attachment,
            actionLinks);
    },

    /**
     * Checks if the supplied Facebook ID matches the current player's.
     *
     * @param {String}  facebookId  The Facebook ID to check.
     * @return {Boolean} True if Facebook ID is the same as the loggin in user.
     */
    isCurrentUser: function(facebookId) {
        return facebookId === window.Arcade.user.fbid;
    },


    api: function(call, cb) {
        var url = (call.url) ? call.url + '?access_token='+window.Arcade.user.access_token : null;

        var params = (call.params) ? call.params : null;

        DR.log('NO URL');

        /** Determine which API to call **/
        if(url && params) {
            DR.log('Url and Params');
            FB.api(url, params,
                function(response) {
                    return DR.Facebook.apiResponse(response, cb);
                });
        } else if(url) {
            DR.log('Url Only');
            FB.api(url,
                function(response) {
                    return DR.Facebook.apiResponse(response, cb);
                });

        } else if(params) {
            DR.log('Params Only');
            FB.api(params,
                   function(response) {
                    return DR.Facebook.apiResponse(response, cb);
                });
        }

    },

    apiResponse : function(response, cb) {
        DR.log('FB:', response);
        if(!response.error) {
            var result = (response.data != undefined) ? response.data : response;
            if(cb) {
                cb(result, response);
            }
        } else {
            DR.log(response.error.message);
        }
    }

});

