(function($){
	
	var defaults = {
		"fb_admins" : "645231933", // Sam Andrews
		"fb_app_id" : "120200301334279", // Snow Valley Ux
		"og_title" : $('meta[property="og:title"]').attr('content'), // get the url from the OpenGraph definition
		"og_url" : $('meta[property="og:url"]').attr('content'), // get the url from the OpenGraph definition
		"og_description" : $('meta[property="og:description"]').attr('content'), // get the url from the OpenGraph definition
		"og_image" : $('meta[property="og:image"]').attr('content'), // get the url from the OpenGraph definition
		"facebook_page" : "http://www.facebook.com/pages/Snow-Valley/105587716144836", // the client's page on Facebook
		/*
			"Like" defaults
		*/
		"like_href" : null,
		"like_layout" : "standard",
		"like_faces" : true,
		"like_width" : 500,
		"like_action" : "like",
		"like_send" : false,
		"like_font" : "arial",
		"like_colourscheme" : "light",
		"like_ref" : null,
		/*
			"Activity box" defaults
		*/
		"activity_width" : 250,
		"activity_height" : 350,
		"activity_header" : true,
		"activity_recommendations" : false,
		"like_box_width" : 250,
		"comments_width" : 500,
		"comments_show_like" : false,
		"comments_posts" : 5,
		"like_box_width" : 250,
		"like_box_height" : 350,
		"like_box_faces" : true,
		"like_box_stream" : true,
		"like_box_header" : true
	};
	
	/*
		Private methods
	*/
	var private_methods = {
		// none at the mo
	}
	
	var methods = {
		init : function(options){
			return this.each(function() {        
				// If options exist, lets merge them with our default settings
				if (options) { 
					$.extend(defaults, options);
				}
				// subscribe to useful events
				FB.Event.subscribe('auth.login', function(response){
					// perform some actions when the user logs out
					// console.log(response);
				});
				FB.Event.subscribe('auth.logout', function(reponse){
					// perform some actions when the user logs in
					// console.log(response);
				});
				FB.Event.subscribe('auth.sessionChange', function(reponse){
					// perform some actions when the user logs in
					// console.log(response);
				});
				FB.Event.subscribe('auth.login', function(href, widget){
					// perform some actions when the user logs out

				});
				FB.Event.subscribe('edge.create', function(href, widget){
					// LIKE something
					// callback from event subscription
					methods['likes'].apply();
				});
				FB.Event.subscribe('edge.remove', function(href, widget) {
					// UNLIKE something
					// callback from event subscription
					methods['likes'].apply();
				});
				FB.Event.subscribe('message.send', function(response) {
					// SEND a message
					/*
					console.log("SENDing message");
					console.log(response);
					*/
				});
			});
		},
		info : function(){
			console.log("Defaults:");
			console.log(defaults);
		},
		/*
			Get available user information from the social graph
			Will only work if a user is logged in to FB
		*/
		get_user : function(options){
			FB.getLoginStatus(function(response){
				if (response.session){
					// get them
					// we're only interested in some of the data
					FB.api('/me?fields=id,username,first_name,last_name,gender,locale,link', function(response) {
						console.log(response);
						// send this to the back-end for processing
						/*
						$.ajax({
							type: "POST",
							url: "facebook_store_process",
							data: response,
							success: function(){
								console.log('User details logged to FB store');
							}
						});
						*/
					});
					// get their friends
					// we'll only grab ID for our purposes
					FB.api('/me/friends?fields=id', function(response) {
						console.log(response);
						$.each(response.data,function(key, value){
							// send this to the back-end for processing
							/*
							$.ajax({
								type: "POST",
								url: "facebook_store_process",
								data: response.data[key]['id'],
								success: function(){
									console.log('User details logged to FB store');
								}
							});
							*/
						});
					});
				} else {
					// console.log("User not logged in to FB");
				}
			})
		},
		/*
			OAuth/connect the user with Facebook with varying permissions
				Do we create a "login" button and append it to selected DOM element?
				Or assume the "login" request has been triggered discreetly?
			Authorise them and/or request perms
		*/
		auth : function(perms,callback){
			FB.login(function(response){
				if (response.session) {
					if (response.perms) {
						callback.call(null,true);
						return true;
					} else {
						// console.log('permissions not granted');
						callback.call(null,false);
					}
				} else {
					// console.log('permissions not granted');
					callback.call(null,false);
				}
			}, {perms:perms});
		},
		has_perms : function(perms, callback){
			FB.getLoginStatus(function(response){
				if (response.session){
					// they're authed
					var query = FB.Data.query('select '+perms+' from permissions where uid=me()');
					// perform query synchronously
					FB.Data.waitOn([query], function(args){
						// are all the requested perms granted?
						perms=perms.split(',');
						granted=0;
						$.each(perms,function(key, value){
							if(args[0][0][value]==1) granted++;
						});
						if(granted==perms.length){
							// perms granted
							callback.call(null,true);
						} else {
							// perms not granted
							callback.call(null,false);
						}
					});
				} else {
					// not even logged in
					// console.log("not even logged in")
					callback.call(null,false);
				}
			});
		},
		/*
			Register FB User With Site
			Auth the user, request some extended permissions and then pass that to an AJAX 
			call to the resistration web method.
			QUERY: Depending on the response of the web method, request a password and some more
			details from the user or OAuth all logins, etc?
		*/
		register_fb_user_with_site : function(options){
			
			// write out the extended login button (this needs to be tied into Auth and thought through)
			/*
			<fb:login-button
			registration-url="http://developers.facebook.com/docs/plugins/registration" />
			*/
			// write out the registration box (this needs to be tied into Auth and thought through)
			/*
			<fb:registration 
			  fields="name,birthday,gender,location,email" 
			  redirect-uri="http://developers.facebook.com/tools/echo/"
			  width="530">
			</fb:registration>
			*/
			
		},
		/*
			Create a paramterised Like button and append it to the selected DOM element
			All Like parameters are (WILL BE!) accepted
			We wrap it in a container with an id/class so that it can be styled easily in the CSS
		*/
		add_activity : function(options){
			var obj = $(this);
			// Parse options
			(options.width) ? width=options.width : width=defaults.activity_width;
			(options.height) ? height=options.height : height=defaults.activity_height;
			(options.recommendations) ? recommendations=options.recommendations : recommendations=defaults.activity_recommendations;
			(options.header) ? header=options.header : header=defaults.activity_header;
			// Build and insert Like button
			html = '<span class="sv-fbactivity"><fb:activity width="'+width+'" height="'+height+'" header="'+header+'" recommendations="'+recommendations+'"></fb:activity></span>';
			obj.append(html);
		},
		add_comments : function(options){
			var obj = $(this);
			// parse options
			(options.comments_posts) ? comments_posts=options.comments_posts : comments_posts=defaults.comments_posts;
			(options.width) ? width=options.width : width=defaults.comments_width;
			//build and insert comments
			html = '<span class="sv-fbcomments"><fb:comments css="http://snowvalley.samandrews.net/fb/sv_fb.css" num_posts="'+comments_posts+'" width="'+width+'"></fb:comments></span>'
			obj.append(html);
		},
		add_facepile : function(options){},
		add_like : function(options){
			var obj = $(this);
			// Parse options
			(options) ? options=options : options="";
			(options.href) ? href=options.href : href=defaults.og_url;
			(options.layout) ? layout=options.layout : layout=defaults.like_layout;
			(options.show_faces) ? show_faces=options.show_faces : show_faces=defaults.like_faces;
			(options.width) ? width=options.width : width=defaults.like_width;
			(options.action) ? action=options.action : action=defaults.like_action;
			(options.send) ? send=options.send : send=defaults.like_send;
			(options.font) ? font=options.font : font=defaults.like_font;
			(options.colourscheme) ? colourscheme=options.colourscheme : colourscheme=defaults.like_colourscheme;
			(options.ref) ? ref=options.ref : ref=defaults.like_ref;
			// Build and insert Like button
			html = '<span class="sv-fblike"><fb:like href="'+href+'" layout="'+layout+'" show_faces="'+show_faces+'" width="'+width+'" action="'+action+'" send="'+send+'" font="'+font+'" colourscheme="'+colourscheme+'" ref="'+ref+'"></fb:like></span>';
			obj.append(html);
		},
		add_send : function(options){
			var obj = $(this);
			html = '<span class="sv-fbsend"><fb:send></fb:send></span>';
			// console.log(html);
			obj.append(html);
		},
		add_like_box : function(options){
			var obj = $(this);
			// Parse options
			(options.facebook_page) ? facebook_page=options.facebook_page : facebook_page=defaults.facebook_page;
			(options.width) ? width=options.width : width=defaults.like_box_width;
			(options.height) ? height=options.height : height=defaults.like_box_height;
			(options.show_faces) ? show_faces=options.show_faces : show_faces=defaults.like_box_faces;
			(options.stream) ? stream=options.stream : stream=defaults.like_box_stream;
			(options.header) ? width=options.header : header=defaults.like_box_header;
			// Build and insert Like button
			html = '<span class="sv-fblikebox"><fb:like-box href="'+facebook_page+'" width="'+width+'" height="'+height+'" show_faces="'+show_faces+'" stream="'+stream+'" header="'+header+'"></fb:like-box></span>';
			obj.append(html);
		},
		add_recommendations : function(options){
			var obj = $(this);
			// Parse options
			(options.width) ? width=options.width : width=defaults.recommendations_width;
			// Build and insert Like button
			html = '<span class="sv-fbrecommendations"><fb:recommendations width="'+width+'"></fb:recommendations></span>';
			obj.append(html);
		},
		/*
			Feed Dialog
			Flexible method that allows the user to write to their feed
			This uses the Facebook Feed dialog to manage the post
			Use this to post non-Like updates or user-defined content to their feed
		*/
		feed_dialog : function(options) {
			// console.log(options);
			(options.name) ? feed_name=options.name : feed_name=defaults.og_title;
			(options.description) ? feed_description=options.description : feed_description=defaults.og_description;
			(options.caption) ? feed_caption=options.caption : feed_caption=defaults.og_url;
			(options.message) ? feed_message=options.message : feed_message="";
			// console.log(defaults.og_url);
			constructor = {
				method: 'feed',
				link: defaults.og_url,
				picture: defaults.og_image
			}
			if (feed_name) constructor.name = feed_name;
			if (feed_description) constructor.description = feed_description;
			if (feed_caption) constructor.caption = feed_caption;
			if (feed_message) constructor.message = feed_message;
			// console.log(constructor);
			FB.ui(
				constructor,
				function(response) {
					if (response && response.post_id) {
						console.log('Post was published.');
					} else {
						console.log('Post was not published.');
					}
				}
			);
		},
		/*
			Feed Direct
			Flexible method that allows us to write to the user's Facebook feed
			This uses the API to talk directly to their feed
			Us this to post non-Like updates directly to the user's feed
			Requires *publish_stream* perms
		*/
		feed_direct : function(options){
			var feed_content = {
				method: 'feed',
				link: defaults.og_url,
				picture: defaults.og_image
			}
			// I dislike that this has to appear after that. why?
			var obj = $(this);
			// Construct the post from the defaults and options
			(options.name) ? feed_content.name=options.name : feed_content.name=defaults.og_title;
			(options.message) ? feed_content.message=options.message : feed_content.message=defaults.og_description;
			(options.caption) ? feed_content.caption=options.caption : feed_content.caption=defaults.og_url;
			// get perms, perform any login/perm auth and set the onclick actions
			methods['has_perms'].apply(null,['publish_stream',function(response){
				if (response) {
					obj.click(function(){
						methods['feed_direct_post'].call(null,feed_content);
						return false;
					});
				} else {
					obj.click(function(){
						// auth dialog to grant permissions
						/*
							This dialog will still fire, and then auto-close if the user subsequently
							fires any associated feed_direct calls.
							I can't seem to capture the authorisation of permissions as an FB subscribe
							event (I was hoping auth.sessionChange would do it).
							There may be an elegant way of handling this in the callback below at some
							point.
						*/
						methods['auth'].apply(null,['publish_stream',function(response){
							if (response) {
								methods['feed_direct_post'].call(null,feed_content);
							} else {
								// tell the user that the post wasn't possible?
								// shell to JQuery UI to display notifications
							}
						}]);
						return false;
					});
				}
			}]);
			
		},
		feed_direct_post : function(feed_content){
			// console.log("posted: "+feed_content)
			FB.api('/me/feed', 'post', feed_content, function(response) {
			  if (!response || response.error) {
			    console.log(response.error);
			  } else {
			    console.log('Post ID: ' + response.id);
			  }
			});
		},
		/*
			Feed Friends
			This is a bespoke interface that allows the user to share content/page/URL/etc
			directly with friends on their social graph
			** Investigate if this is possible to construct using FB tool/dialogs/etc
			   or if this needs to be build entirely within our system **
			CURRENTLY THIS SIMPLY INVITES USERS TO THE APP – DO NOT USE!
		*/
		feed_friends : function(options){
			FB.ui(
				{
					method: 'apprequests', 
					message: 'You should learn more about this delicious wine.', 
					data: 'tracking information for the user'
				}
			);
		},
		/*
			User Invite
			This uses the Request dialog to invite friends to the Canvas application underlying the website
			This is quite a specific use-case, and needs to be further considered
			The application itself needs to perform a discrete function for this to be useful
		*/
		user_invite : function(options){},
		/*
			Likes
			Counts the amount of likes for the current URL by default
			Writes the count to the back end
		*/
		likes : function(options) {
			//var query = FB.Data.query('SELECT share_count, like_count, comment_count, total_count FROM link_stat WHERE url="'+likes_url+'"');
			var query = FB.Data.query('SELECT like_count FROM link_stat WHERE url="'+options.url+'"');
			query.wait(function(rows) {
				// just dump a like_count for now – but this should be a RETURN and switchable
				/* console.log(rows[0]['like_count']); */
				// I'd like some logic to handle returning or storing or whatever
				// send this to the back-end for processing
				/*
				$.ajax({
					type: "POST",
					url: "facebook_store_process",
					data: rows[0]['like_count'],
					success: function(){
						console.log('User details logged to FB store');
					}
				});
				*/
				options.callback.call(null,rows[0]['like_count']);
			});
		},
		/*
			A JS/FB API version of the like count for product list pages, etc
			Ideally we'll probably want to serve this up from our own data store
		*/
		show_likes : function(options){
			obj = $(this);
			methods['likes'].apply(null,[options.url,function(like_count){
				// console.log(like_count);
			}])
		},
		/*
			Purely conceptual inclusion of the Facebook Pay dialog
			No idea if it's going to be possible to actually pay via it, but
			should make for a fun demo!
		*/
		pay : function(options) {
			constructor = {
				method: 'pay',
				order_info: "ORD1234567",
			}
			console.log(constructor);
			FB.ui(
				constructor,
				function(response) {
					if (response && response.order_id) {
						console.log('Paid!');
					} else {
						console.log('No paid!');
					}
				}
			);
		}
		
		
	};
	
	$.fn.sv_fb = function(method) {
	
		// Method calling logic
		if ( methods[method] ) {
			return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof method === 'object' || ! method ) {
			return methods.init.apply( this, arguments );
		} else {
			$.error( 'Method ' +  method + ' does not exist on jQuery.sv_fb' );
		}
	
	}
	
})(jQuery);
