import java.io.*;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;

import com.facebook.api.*;

/**
 * Basic login servlet for Facebook, perfect for use as the Callback URL of your Facebook App.
 * <P>
 * With the "settings.conf" file I have used this here because Facebook's only example
 * code for using their java API uses this approach, and a file of that name, so this should be
 * instantly familiar to anyone who's tried using that code. You may want to change that to use
 * your J2EE implementation's preferred method of configuring servlets.
 * <P>
 * NOTE: you will have to extend this class and override the postSuccessfulFacebookLogin
 * method to do something more intelligent than just redirecting to another servlet; I currently
 * have this configured to integrate with my own SQL database of users of my app, and to perform
 * an automatic login to that database as well as to the Facebook servers.
 * 
 * @see #postSuccessfulFacebookLogin(HttpServletRequest, HttpServletResponse)
 * 
 * @author Adam Martin, amartin @ ncsoft.com, http://tmachine1.dh.bytemark.co.uk/blog/
 */
public abstract class FacebookLoginServlet extends HttpServlet
{
	public static final boolean fakingFacebooksPresence = true;
	
	protected String CONFIG_FILE = "settings.conf";
	protected String REPLACE_MESSAGE = "Please enter both your API key and secret in the "
			+ CONFIG_FILE
			+ " configuration file. Your API key and secret can be found at "
			+ "http://developers.facebook.com/account.php";
	protected Properties faceBookAppLoginCredentials = null;
	
	/**
	 * Loads the Facebook authentication config file
	 * 
	 * @see #CONFIG_FILE
	 */
	public FacebookLoginServlet()
	{
		try
		{
			FileInputStream fis = new FileInputStream(CONFIG_FILE);
			faceBookAppLoginCredentials = new Properties();
			faceBookAppLoginCredentials.load(fis);
		}
		catch( Exception e )
		{
			logger.error("trying to load config for FB from file "+CONFIG_FILE, e );
		}

		String api_key = faceBookAppLoginCredentials.getProperty("api_key");
		String secret = faceBookAppLoginCredentials.getProperty("secret");
		if( "<your_api_key>".equals(api_key) || "<your_secret>".equals(secret) )
		{
			logger.error(REPLACE_MESSAGE);
		}
	}
	
	/**
	 * Automatically logs the user in to Facebook, and then sends them to the front page of your application.
	 * 
	 * @param req provided by your J2EE container
	 * @param resp provided by your J2EE container
	 * @throws ServletException provided by your J2EE container
	 * @throws IOException if the redirect fails, or if the attempt to authenticate with Facebook fails
	 */
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
	{
		logger.info( "Requested URL: "+req.getRequestURL()+" --- with query string: "+req.getQueryString());
		
		String defaultLoginPage = "http://www.facebook.com/login.php?api_key="+faceBookAppLoginCredentials.getProperty("api_key")+"&v=1.0";
		String authToken = req.getParameter("auth_token");
		
		try
		{
			if( fakingFacebooksPresence )
			{
				FakeFacebookRestClient authenticatedClient = new FakeFacebookRestClient(faceBookAppLoginCredentials.getProperty("api_key"), faceBookAppLoginCredentials.getProperty("secret"));
				authenticatedClient.setIsDesktop(false);
				
				logger.warn( "FAKING our facebook client connection...");
				
				req.getSession().setAttribute( "facebookClient", authenticatedClient );

				postSuccessfulFacebookLogin( authenticatedClient, req, resp );
			}
			else
			{
				if( authToken == null || authToken.length() < 1 )
				{
					logger.info( "User is not logged in; redirecting them to Facebook's login page = "+defaultLoginPage );
					resp.sendRedirect(defaultLoginPage);
				}
				else
				{
					FacebookRestClient authenticatedClient = new FacebookRestClient(faceBookAppLoginCredentials.getProperty("api_key"), faceBookAppLoginCredentials.getProperty("secret"));
					authenticatedClient.setIsDesktop(false);

					logger.info( "Authenticating our facebook client connection using authToken from user...");
					authenticatedClient.auth_getSession( authToken );

					req.getSession().setAttribute( "facebookClient", authenticatedClient );

					postSuccessfulFacebookLogin( authenticatedClient, req, resp );
				}
			}
		}
		catch( FacebookException e )
		{
			logger.error( "Error trying to authenticate with facebook", e );
		}
	}
	
	/**
	 * Invoked as soon as this servlet has successfully authenticated the current Facebook user and stored the
	 * authenticated connection in the J2EE Session
	 * 
	 * @param authenticatedClient the just-authenticated client object, for your convenience (has already been added to the J2EE session)
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	protected abstract void postSuccessfulFacebookLogin( FacebookRestClient authenticatedClient, HttpServletRequest request, HttpServletResponse response ) throws IOException;
}
