package com.tootsville.tootsbook.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.tootsville.tootsbook.client.exception.SessionTimedOutException;
import com.tootsville.tootsbook.client.exception.TootBookException;
import com.tootsville.tootsbook.client.panel.ErrorMessage;
import com.tootsville.tootsbook.client.util.DisplayText;
import com.tootsville.tootsbook.client.util.LoadingBar;
import com.tootsville.tootsbook.client.util.Message;
import com.tootsville.tootsbook.client.util.UserProfile;
import com.tootsville.tootsbook.client.util.tasks.ClientMetronome;
import com.tootsville.tootsbook.client.util.tasks.Task;

/**
 * Entry point into application: {@link TootsBook#onModuleLoad()}.
 * 
 * @author <a href="mailto:twheys@gmail.com@resinteractive.com">Tim
 *         Heys</a>
 */
public final class TootsBook implements EntryPoint {

	/**
	 * Don't use this anymore.
	 */
	@Deprecated
	public static final String BASE = "tootbook-resource";

	/**
	 * Asynchronous service for receiving callbacks from the servlet
	 */
	private static final BookServiceAsync bookSvc = GWT
	.create (BookService.class);

	/**
	 * Single EcmaShocript timer used for all timed tasks. Contains two
	 * lists of tasks, for page local and global, and handles one-shot tasks as well.
	 */
	public final static ClientMetronome clientMetronome = new ClientMetronome ();

	/**
	 * WRITEME: Document this field. twheys@gmail.com Dec 18, 2009
	 */
	private static final String CSS_TITLE_BOX_STYLES = "boxStyles";

	/**
	 * WRITEME: Document this field. twheys@gmail.com Dec 18, 2009
	 */
	private static final String CSS_TITLE_PAGE_BG = "pageStyles";

	/**
	 * WRITEME: Document this field. twheys@gmail.com Dec 18, 2009
	 */
	private static final String CSS_TITLE_TITLE_BG = "titleStyles";

	/**
	 * Current popup being displayed.
	 */
	private static PopupPanel currentPopup;

	/**
	 * WRITEME
	 */
	private static boolean firstCheck = true;

	/**
	 * Has the advertisement for VIT membership already been shown for
	 * this session?
	 */
	private static boolean isAdShown;

	/**
	 * Loading bar
	 */
	public static final LoadingBar loadingTab = new LoadingBar ();

	/**
	 * Maximum length in characters of … WRITEME …?
	 */
	public static final int MAX_CHAR_LENGTH = 150;

	/**
	 * Maximum number of comments to initially display
	 */
	public static final int MAX_COMMENTS = 3;

	/**
	 * WRITEME
	 */
	private static Message messageToBeDisplayed = null;

	/**
	 * Number of posts to receive to see the "Show More Posts" link on
	 * home and profile.
	 */
	public static final int NUMBER_OF_POSTS = 10;

	/**
	 * <strong>example:</strong>
	 * https://members.tootsville.com/#adminconsole
	 */
	public static final String PAGE_URL_ADMIN = "adminconsole";

	/**
	 * <strong>example:</strong> https://members.tootsville.com/#home
	 */
	public static final String PAGE_URL_HOME = "home";

	/**
	 * <strong>example:</strong>
	 * https://members.tootsville.com/#katootels?id=123456
	 */
	public static final String PAGE_URL_KATOOTEL = "katootels";

	/**
	 * <strong>example:</strong> https://members.tootsville.com/#login
	 */
	public static final String PAGE_URL_LOGIN = "login";

	/**
	 * <strong>example:</strong> https://members.tootsville.com/#logout
	 */
	public static final String PAGE_URL_LOGOUT = "logout";

	/**
	 * <strong>example:</strong>
	 * https://members.tootsville.com/#pivitpals?id=123456
	 */
	public static final String PAGE_URL_PIVIT_PALS = "pivitpals";

	/**
	 * <strong>example:</strong>
	 * https://members.tootsville.com/#pivitz?id=123456
	 */
	public static final String PAGE_URL_PIVITZ = "pivitz";

	/**
	 * <strong>example:</strong>
	 * https://members.tootsville.com/#posters?id=123456
	 */
	public static final String PAGE_URL_POSTERS = "posters";

	/**
	 * <strong>example:</strong>
	 * https://members.tootsville.com/#profile?id=123456 <b>OR</b>
	 * https://members.tootsville.com/#profile
	 */
	public static final String PAGE_URL_PROFILE = "profile";

	/**
	 * <strong>example:</strong>
	 * https://members.tootsville.com/#settings
	 */
	public static final String PAGE_URL_SETTINGS = "settings";

	/**
	 * <strong>example:</strong> https://members.tootsville.com/#store
	 */
	public static final String PAGE_URL_STORE = "store";

	/**
	 * <strong>example:</strong>
	 * https://members.tootsville.com/#tootfinds?id=123456
	 */
	public static final String PAGE_URL_TOOT_FINDS = "finds";

	/**
	 * Global timer delay, 1 MINUTE
	 */
	private static final int TIMER_DELAY = 30 * 1000;

	/**
	 * The logged in user record.
	 */
	private static UserProfile user = null;

	/**
	 * Set the user that is logged in.
	 * 
	 * @param newLoggedInUser the user that is now logged in.
	 */
	public static void acceptSuccessfulLogin (
			final UserProfile newLoggedInUser) {
		TootsBook.hideLoadingBar ();
		GWT.log ("Successfully retrieved user from server.", null);
		TootsBook.setUser (newLoggedInUser);
		History.newItem ("home");
	}

	/**
	 * <pre>
	 * twheys@gmail.com Dec 17, 2009
	 * </pre>
	 * 
	 * TO displayLoading WRITEME...
	 */
	public static void displayLoadingBar () {
		System.out.print ("Displaying loading bar");
		TootsBook.loadingTab.setVisibile (true);
	}

	/**
	 * Filter input from users. Returns a boolean to indicate if the
	 * input passed the filters. Typically this method is called by a
	 * key listener and if the boolean is false the listener rejects the
	 * key input.
	 * 
	 * @param charCode Char code of the key event needing to be filtered
	 * @param maxReached Boolean if maximum number of characters for the
	 *            textfield is reached or false if there is no maximum
	 * @return true if input is allowed
	 */
	public static boolean filterKeys (final char charCode,
			final boolean maxReached) {
		if (charCode == '\b' || charCode == KeyCodes.KEY_LEFT
				|| charCode == KeyCodes.KEY_RIGHT
				|| charCode == KeyCodes.KEY_UP
				|| charCode == KeyCodes.KEY_DOWN) return true;
		if (charCode >= 'a' && charCode <= 'z' || charCode >= 'A'
			&& charCode <= 'Z') return true && !maxReached;
		for (final char maybe : new char [] { '.', ',', '!', '?', '-',
				'\'', ' ', '\"', '∑', '™' }) {
			if (maybe == charCode) return true && !maxReached;
		}

		return false;

	}

	/**
	 * Creates a horizontal bar of links to Tootsville sites of interest
	 * 
	 * @return a panel with links
	 */
	public static HTML getLinks () {
		final HTML linkBar = new HTML (
				"<a class=\"secondary-text\" href=\"http://www.tootsville.com/playnow.html\" target=\"_blank\">Play Now</a> | \r\n"
				+ "<a class=\"secondary-text\" href=\"https://members.tootsville.com/shop/\" target=\"_blank\">Shop</a> | \r\n"
				+ "<a class=\"secondary-text\" href=\"https://members.tootsville.com/membership/register/premium\" target=\"_blank\">Membership</a> | \r\n"
				+ "<a class=\"secondary-text\" href=\"http://www.tootsville.com/web/parents-handbook/index.html\" target=\"_blank\">Parents Handbook</a> | \r\n"
				+ "<a class=\"secondary-text\" href=\"http://www.tootsville.com/web/need-help-with-online-game/index.html\" target=\"_blank\">Need Help</a> | \r\n"
				+ "<a class=\"secondary-text\" href=\"http://www.tootsville.com/web/privacy-policy/index.html\" target=\"_blank\">Privacy Policy</a> | \r\n"
				+ "<a class=\"secondary-text\" href=\"http://www.tootsville.com/web/contact-tootsville/index.html\" target=\"_blank\">Contact Us</a>\r\n");
		linkBar.setStyleName ("secondary-text");
		return linkBar;

	}

	/**
	 * @return any messages queued to be displayed.
	 */
	public static Message getMessage () {
		GWT.log ("Retrieving message and setting it as null", null);
		final Message message = TootsBook.messageToBeDisplayed;
		// Set message to be null since it's a one time thing
		TootsBook.messageToBeDisplayed = null;
		return message;
	}

	/**
	 * Get the user who is currently logged into this instance of
	 * TootBook
	 * 
	 * @return the UserInfo object of the logged in ShadowUser
	 */
	public static UserProfile getUser () {
		return TootsBook.user;
		// return null;
	}

	/**
	 * @return the ID of the logged in ShadowUser
	 */
	public static int getUserID () {
		if (null == TootsBook.user) return -1;
		return TootsBook.user.getUserID ();
	}

	/**
	 * Check and see if there are any messages queued to be displayed.
	 * 
	 * @return true if there is a queued message false if no message is
	 *         queued.
	 */
	public static boolean hasMessage () {
		return null != TootsBook.messageToBeDisplayed;
	}

	/**
	 * WRITEME: Document this method brpocock@star-hope.org
	 */
	public static void hideCurrentPopup () {
		if (null != TootsBook.currentPopup) {
			TootsBook.currentPopup.hide ();
		}

	}

	/**
	 * <pre>
	 * twheys@gmail.com Dec 17, 2009
	 * </pre>
	 *
	 * TO displayLoading WRITEME...
	 */
	public static void hideLoadingBar () {
		System.out.print ("Hiding loading bar");
		TootsBook.loadingTab.setVisibile (false);
	}

	/**
	 * @return if the browser being used is Internet Explorer,
	 *         regardless of version
	 */
	public native static boolean ifIE ()/*-{
		var nAgt = navigator.userAgent;
		return (nAgt.indexOf("MSIE")!=-1)&&!(nAgt.indexOf("Opera")!=-1);
	}-*/;

	/**
	 * Get the Asynchronous RPC service. This will initialize the
	 * service if it has not been already initialized.
	 *
	 * @return The Asynchronous service for TootBook
	 */
	public static BookServiceAsync initService () {
		// Initialize the service proxy.
		// if (null == TootsBook.bookSvc) {
		// TootsBook.bookSvc = GWT.create (BookService.class);
		// }
		return TootsBook.bookSvc;
	}

	/**
	 * If the VIT advertisement has already been displayed, do not
	 * display it again.
	 *
	 * @return the isAdShown true: if the advertisement has already been
	 *         displayed, false: if the advertisement has not been
	 *         displayed.
	 */
	public static boolean isAdShown () {
		return TootsBook.isAdShown;
	}

	/**
	 * @return the firstCheck
	 */
	public static boolean isFirstCheck () {
		return TootsBook.firstCheck;
	}

	/**
	 * Check if there is a ShadowUser currently logged into this instance of
	 * TootBook. This essentially acts as a null check for
	 * {@link TootsBook#getUser()}.
	 *
	 * @return true if a ShadowUser is logged in, false if no user is logged
	 *         in.
	 */
	public static boolean isLoggedIn () {
		return null != TootsBook.getUser ();
	}

	/**
	 * <pre>
	 * twheys@gmail.com Dec 18, 2009
	 * </pre>
	 *
	 * TO loadBackgroundStyleSheet WRITEME...
	 *
	 * @param cssURL WRITEME twheys@gmail.com
	 */
	public static void loadBoxStylesStyleSheet (final String cssURL) {
		System.out.println ("Loading style sheet at: " + cssURL);
		TootsBook.removeBoxStylesStyleSheets ();
		TootsBook.loadStyleSheetImpl (cssURL,
				TootsBook.CSS_TITLE_BOX_STYLES);
	}

	/**
	 * <pre>
	 * twheys@gmail.com Dec 18, 2009
	 * </pre>
	 *
	 * TO loadBackgroundStyleSheet WRITEME...
	 *
	 * @param cssURL WRITEME twheys@gmail.com
	 */
	public static void loadPageBGStyleSheet (final String cssURL) {
		System.out.println ("Loading style sheet at: " + cssURL);
		TootsBook.removePageBGStyleSheets ();
		TootsBook.loadStyleSheetImpl (cssURL,
				TootsBook.CSS_TITLE_PAGE_BG);
	}

	/**
	 * Load a style sheet from a relative URL. Deprecated. Load style
	 * sheets with their appropriate methods.
	 *
	 * @param cssURL the (relative or absolute) URL to a css file.
	 */
	@Deprecated
	public static void loadStyleSheet (final String cssURL) {
		System.out.println ("Loading style sheet at: " + cssURL);
		TootsBook.loadStyleSheetImpl (cssURL);
	}

	/**
	 * Called by {@link #loadStyleSheet(String)} to natively import a
	 * style sheet.
	 *
	 * @param cssURL the (relative or absolute) URL to a css file.
	 */
	@Deprecated
	protected static native void loadStyleSheetImpl (String cssURL)/*-{
		var fileref=document.createElement("link");
		fileref.setAttribute("rel", "stylesheet");
		fileref.setAttribute("type", "text/css");
		fileref.setAttribute("href", cssURL);
		fileref.setAttribute("title", "theme14");
		$doc.getElementsByTagName("head")[0].appendChild(fileref);
	}-*/;

	/**
	 * Called by {@link #loadStyleSheet(String)} to natively import a
	 * style sheet.
	 *
	 * @param cssURL the (relative or absolute) URL to a css file.
	 * @param theTitle WRITEME twheys@gmail.com
	 */
	protected static native void loadStyleSheetImpl (String cssURL,
			String theTitle)/*-{
		var head=$doc.getElementsByTagName("head")[0];
		var fileref=$doc.createElement("link");
		fileref.setAttribute("rel", "stylesheet");
		fileref.setAttribute("type", "text/css");
		fileref.setAttribute("href", cssURL);
		fileref.setAttribute("id", theTitle);
		head.appendChild(fileref);
	}-*/;

	/**
	 * <pre>
	 * twheys@gmail.com Dec 18, 2009
	 * </pre>
	 *
	 * TO loadBackgroundStyleSheet WRITEME...
	 *
	 * @param cssURL WRITEME twheys@gmail.com
	 */
	public static void loadTitleBGStyleSheet (final String cssURL) {
		System.out.println ("Loading style sheet at: " + cssURL);
		TootsBook.removetitleBGStyleSheets ();
		TootsBook.loadStyleSheetImpl (cssURL,
				TootsBook.CSS_TITLE_TITLE_BG);
	}

	/**
	 * Login gateway from login page or otherwise anywhere a login can
	 * be initiated.
	 *
	 * @param username WRITEME twheys@gmail.com
	 * @param password WRITEME twheys@gmail.com
	 */
	public static void login (final String username,
			final String password) {
		final BookServiceAsync service = TootsBook.initService ();

		final AsyncCallback <UserProfile> callback = new AsyncCallback <UserProfile> () {

			@Override
			public void onFailure (final Throwable caught) {
				TootsBook.showFailedLogin (caught);
			}

			@Override
			public void onSuccess (final UserProfile result) {
				TootsBook.acceptSuccessfulLogin (result);
			}
		};
		// Make the call to the search service.
		service.login (username, password, callback);
	}

	/**
	 * Generic login procedure with provided username and password. To
	 * use the login with the user's cookie, use
	 * {@link #login(String, String)} instead.
	 *
	 * @param loginUserName ShadowUser name to use for logging in.
	 * @param loginPassword Password to use for logging in.
	 * @param callback Callback handler to respond to action. Use
	 *            {@link TootsBook#acceptSuccessfulLogin(UserProfile)}
	 *            to set login and your
	 *            {@link TootsBook#showFailedLogin(Throwable)} to handle
	 *            failed logins.
	 */
	public static void login (final String loginUserName,
			final String loginPassword,
			final AsyncCallback <UserProfile> callback) {
		System.out.println ("Attempting to login with info u("
				+ loginUserName + ") and p(" + loginPassword + ")");
		final BookServiceAsync service = TootsBook.initService ();

		// Make the call to the search service.
		service.login (loginUserName, loginPassword, callback);
	}

	/**
	 * Log the user out. This does NOT delete cookies. If the user has a
	 * cookie and logs out, they will still be logged in automatically
	 * next time they hit the page.
	 *
	 * @param displayMessage Display a message to confirm a successful
	 *            logout.
	 */
	public static void logout (final Boolean displayMessage) {
		System.out.println ("Logging out");
		TootsBook.setUser (null);
		if (displayMessage.booleanValue ()) {
			TootsBook.setToDisplayMessage (new Message (
					"You have successfully logged out.",
					Message.SUCCESS_COLOR));
		}

		final BookServiceAsync service = TootsBook.initService ();

		// Set up the callback object.
		final AsyncCallback <Void> callback = new AsyncCallback <Void> () {
			@Override
			public void onFailure (final Throwable caught) {
				System.out.println ("Session not deleted");
				History.newItem (TootsBook.PAGE_URL_LOGIN);
			}

			@Override
			public void onSuccess (final Void result) {
				System.out.println ("Session deleted");
				History.newItem (TootsBook.PAGE_URL_LOGIN);
			}
		};

		// Make the call to the search service.
		service.logout (callback);
	}

	/**
	 * Parse a URL for a particular parameter or null if the parameter
	 * does not exist or has no value.
	 *
	 * @param param The parameter which a value is needed for.
	 * @param url The url to parse
	 * @return returns parameter value in the url or null if the
	 *         parameter does not exist.
	 */
	public static String parseURL (final String param, final String url) {
		if ( !url.contains (param)) return null;
		final int paramBegin = url.indexOf ('?') + 1;
		try {
			final String [] params = url.substring (paramBegin).split (
			"&");
			for (final String getParam : params) {
				final String [] paramAndValues = getParam.split ("=");
				if (param.equals (paramAndValues [0])) {
					try {
						return URL.decodeComponent (paramAndValues [1]);
					} catch (final NullPointerException e) {
						return null;
					}
				}
			}
		} catch (final IndexOutOfBoundsException e) {
			return null;
		}
		return null;
	}

	/**
	 * This doesn't work Remove all style sheets added via
	 * {@link TootsBook#loadStyleSheet(String)}
	 */
	@Deprecated
	public static void removeAllStyleSheets () {
		System.out.println ("Removing theme style sheets");
		TootsBook.removeAllStyleSheetsImpl ();
	}

	/**
	 * This doesn't work
	 */
	@Deprecated
	protected static native void removeAllStyleSheetsImpl ()/*-{
		var headID = document.getElementsByTagName('head')[0];
		var allsuspects=$doc.getElementsByTagName("link");
		for (var i=allsuspects.length; i>=0; i--) {
		if (null!=allsuspects[i] && allsuspects[i].getAttribute("title") && allsuspects[i].getAttribute("title").indexOf("theme14")!=-1) {
		allsuspects[i].parentNode.removeChild(allsuspects[i]);
		}
		}
	}-*/;

	/**
	 * <pre>
	 * twheys@gmail.com Dec 18, 2009
	 * </pre>
	 *
	 * TO removePageBGStyleSheets WRITEME...
	 */
	public static void removeBoxStylesStyleSheets () {
		TootsBook
		.removeStyleSheetByTitleImpl (TootsBook.CSS_TITLE_BOX_STYLES);
	}

	/**
	 * <pre>
	 * twheys@gmail.com Dec 18, 2009
	 * </pre>
	 *
	 * TO removePageBGStyleSheets WRITEME...
	 */
	public static void removePageBGStyleSheets () {
		TootsBook
		.removeStyleSheetByTitleImpl (TootsBook.CSS_TITLE_PAGE_BG);
	}

	/**
	 * <pre>
	 * twheys@gmail.com Dec 18, 2009
	 * </pre>
	 *
	 * TO removeAllStyleSheetsImpl WRITEME...
	 *
	 * @param title WRITEME twheys@gmail.com
	 */
	protected static native void removeStyleSheetByTitleImpl (
			String title)/*-{
		var headID = document.getElementsByTagName('head')[0];
		var allsuspects=$doc.getElementsByTagName("link");
		for (var i=allsuspects.length; i>=0; i--) {
		if (null!=allsuspects[i] && allsuspects[i].getAttribute("id") && allsuspects[i].getAttribute("id").indexOf(title)!=-1) {
		allsuspects[i].parentNode.removeChild(allsuspects[i]);
		}
		}
	}-*/;

	/**
	 * <pre>
	 * twheys@gmail.com Dec 18, 2009
	 * </pre>
	 *
	 * TO removePageBGStyleSheets WRITEME...
	 */
	public static void removetitleBGStyleSheets () {
		TootsBook
		.removeStyleSheetByTitleImpl (TootsBook.CSS_TITLE_TITLE_BG);
	}

	/**
	 * <pre>
	 * twheys@gmail.com Feb 10, 2010
	 * </pre>
	 *
	 * TO reportBug WRITEME...
	 *
	 * @param string WRITEME twheys@gmail.com
	 * @param e WRITEME twheys@gmail.com
	 */
	public static void reportBug (final String string, final Exception e) {
		// TODO Auto-generated method stub
		// TOOTSBOOK
	}

	/**
	 * @param newAdShown the isAdShown to set
	 */
	public static void setAdShown (final boolean newAdShown) {
		TootsBook.isAdShown = newAdShown;
	}

	/**
	 * @param isFirstCheck the firstCheck to set
	 */
	public static void setFirstCheck (final boolean isFirstCheck) {
		TootsBook.firstCheck = isFirstCheck;
	}

	/**
	 * @param message WRITEME twheys@gmail.com
	 */
	public static void setToDisplayMessage (final Message message) {
		TootsBook.messageToBeDisplayed = message;
	}

	/**
	 * @param newUser the user to set
	 */
	public static void setUser (final UserProfile newUser) {
		TootsBook.user = newUser;
	}

	/**
	 * <pre>
	 * twheys@gmail.com Jan 26, 2010
	 * </pre>
	 *
	 * TO showError WRITEME...
	 *
	 * @param caught WRITEME twheys@gmail.com
	 */
	public static void showError (final Throwable caught) {
		if (caught instanceof TootBookException) {
			if (caught instanceof SessionTimedOutException) {
				History.newItem (TootsBook.PAGE_URL_LOGIN);
				return;
			}
			TootsBook.showPopup (new ErrorMessage (
					DisplayText.ERROR_HEADER, caught.getMessage ()));
			return;
		}
		TootsBook.showPopup (new ErrorMessage (
				DisplayText.ERROR_HEADER, DisplayText.SERVER_ERROR));
	}

	/**
	 * Handle a failed login appropriately. This method centralizes the
	 * code for this event since it can occur in multiple places.
	 *
	 * @param caught The throwable thrown by the servlet when attempting
	 *            to login.
	 */
	public static void showFailedLogin (final Throwable caught) {
		TootsBook.hideLoadingBar ();
		TootsBook.showError (caught);

		System.out.println ("Loading login page from failed login.");
		TootsBook.logout (Boolean.FALSE);
	}

	/**
	 * Display a popup window on the root element so that it can center
	 * correctly.
	 *
	 * @param popup The popup to be shown.
	 */
	public static void showPopup (final PopupPanel popup) {
		TootsBook.currentPopup = popup;
		popup.center ();
	}

	/**
	 * <pre>
	 * twheys@gmail.com Feb 10, 2010
	 * </pre>
	 *
	 * TO trackPage WRITEME...
	 *
	 * @param pageURL WRITEME twheys@gmail.com
	 */
	public static native void trackPage (String pageURL)/*-{
		$wnd._gat._getTracker("UA-10367408-3")._trackPageview(pageURL);
	}-*/;

	/**
	 * <pre>
	 * twheys@gmail.com Mar 1, 2010
	 * </pre>
	 *
	 * TO updatePeanuts WRITEME...
	 */
	public static void updatePeanuts () {
		if (TootsBook.isLoggedIn ()) return;
		final BookServiceAsync service = TootsBook.initService ();

		final AsyncCallback <Integer> callback = new AsyncCallback <Integer> () {
			/**
			 * @see com.google.gwt.user.client.rpc.AsyncCallback#onFailure(java.lang.Throwable)
			 */
			@Override
			public void onFailure (final Throwable caught) {
				// no op
			}

			/**
			 * @see com.google.gwt.user.client.rpc.AsyncCallback#onSuccess(java.lang.Object)
			 */
			@Override
			public void onSuccess (final Integer peanuts) {
				TootsBook.getUser ().setPeanuts (peanuts.intValue ());
			}
		};

		service.getPeanutsForUser (TootsBook.getUserID (), callback);
	}

	/**
	 * Verify if an object is a Widget or one of its subclasses
	 *
	 * @param source The object in question
	 * @return The object if it is a widget
	 * @throws ClassCastException if the object is not a widget
	 */
	public static Widget verifiyIsWidget (final Object source)
	throws ClassCastException {
		if (source instanceof Widget) return (Widget) source;
		throw new ClassCastException ("Event source is not a widget!");
	}

	/**
	 * WRITEME
	 */
	private MainPanel panel;

	/**
	 * WRITEME
	 */
	protected void checkSession () {
		final BookServiceAsync service = TootsBook.initService ();

		final AsyncCallback <UserProfile> callback = new AsyncCallback <UserProfile> () {

			@Override
			public void onFailure (final Throwable caught) {
				if (caught instanceof SessionTimedOutException) {
					if (TootsBook.isFirstCheck ()) {
						TootsBook.this.init ();
						TootsBook.setFirstCheck (false);
					}
				}
			}

			@Override
			public void onSuccess (final UserProfile result) {
				// wrapReportBugImage ();
				if (TootsBook.isFirstCheck ()) {
					TootsBook.setUser (result);
					TootsBook.this.init ();
					TootsBook.setFirstCheck (false);
				} else {
					TootsBook.setUser (result);
				}
			}
		};
		// Make the call to the search service.
		service.checkSession (callback);
	}

	/**
	 * <pre>
	 * twheys@gmail.com Feb 2, 2010
	 * </pre>
	 *
	 * TO getBrowserInfo WRITEME...
	 *
	 * @return Browser and OS info
	 */
	protected native String getBrowserInfo ()/*-{
		return "Browser: " + navigator.userAgent + "%0AVendor: " + navigator.vendor + "%0AVersion: " + navigator.appVersion + "%0AOperating System: " + navigator.platform + "%0A";
	}-*/;

	/**
	 * <pre>
	 * twheys@gmail.com Feb 2, 2010
	 * </pre>
	 *
	 * TO getReportBugAnchor WRITEME...
	 *
	 * @return element of the report bug object
	 */
	protected native JavaScriptObject getReportBugAnchor ()/*-{
		return $doc.getElementById ('report-bug');
	}-*/;

	/**
	 * <pre>
	 * twheys@gmail.com Feb 2, 2010
	 * </pre>
	 *
	 * TO getReportBugForm WRITEME...
	 *
	 * @return the template for a bug report
	 */
	protected String getReportBugForm () {
		return "Thank you for beta testing TootsBook, we sincerely "
		+ "appreciate your contributions to our testing procedures."
		+ "%0A%0AThe following information will be used to test "
		+ "and eliminate the software bug you are reporting.  Any "
		+ "and all information you provide will be helpful to our "
		+ "engineers in resolving the problem.  Please answer each "
		+ "question as thoroughly as possible.%0A%0A1. Please "
		+ "describe the problem.%0A%0A%0A%0A2. Were you "
		+ "logged in to TootsBook when you saw this problem occur?%0A"
		+ "%0A%0A%0A3. Which Page were you viewing when you "
		+ "saw this problem?  Home page, My Profile Page, Someone "
		+ "Else's Profile Page, Settings Page, Login Page%0A%0A"
		+ "%0A%0A4. If you wanted to make this problem happen "
		+ "again, what steps would you follow?%0A%0A%0A%0A5. "
		+ "Did you find a way to get around the problem?  If so, how "
		+ "did you do it?%0A%0A%0A%0A%0AAfter answering "
		+ "the questions above, please send this in an e-mail to "
		+ "TootReport@resinteractive.com so we can begin working "
		+ "to resolve the problem.  Thank you for being a Toots™ "
		+ "Beta Tester.";
	}

	/**
	 * <pre>
	 * twheys@gmail.com Feb 2, 2010
	 * </pre>
	 *
	 * TO getReportBugBody WRITEME...
	 *
	 * @return HREF value for the report bug mailto
	 */
	protected String getReportBugHref () {
		final StringBuilder mailAddress = new StringBuilder ();
		mailAddress.append ("mailto:tootreport@resinteractive.com?");
		mailAddress.append ("subject=Bug Report");
		if (TootsBook.isLoggedIn ()) {
			mailAddress.append (" From "
					+ TootsBook.getUser ().getUserName () + " ("
					+ TootsBook.getUser ().getUserID () + ")");
		}
		mailAddress.append ("&body=" + getBrowserInfo ()
				+ getReportBugForm ());
		return mailAddress.toString ();
	}

	/**
	 * WRITEME: Document this field. twheys@gmail.com Dec 14, 2009
	 */
	protected void init () {
		// create the main panel for the application
		panel = new MainPanel ();

		// initialize history recording
		panel.initHistorySupport ();

		RootPanel.get ("main").add (panel);

		// finally, remove the splash screen/loading msg
		RootPanel.get ("loading").setVisible (false);

		System.out.println ("Firing current history state");
		History.fireCurrentHistoryState ();
	}

	/**
	 * This is the entry point to the application
	 */
	@Override
	public void onModuleLoad () {
		System.out
		.println ("\n\nLoading new instance of application.\n\n");
		startMasterTimer ();

		TootsBook.clientMetronome.addGlobalTask (new Task () {
			@Override
			public void execute () {
				checkSession ();
			}
		});

		checkSession ();
	}

	/**
	 * <pre>
	 * twheys@gmail.com Mar 9, 2010
	 * </pre>
	 *
	 * TO startMasterTimer WRITEME...
	 */
	private void startMasterTimer () {
		TootsBook.clientMetronome
		.scheduleRepeating (TootsBook.TIMER_DELAY);
	}

	/**
	 * <pre>
	 * twheys@gmail.com Feb 2, 2010
	 * </pre>
	 *
	 * TO wrapReportBugImage WRITEME...
	 */
	protected void wrapReportBugImage () {
		final Anchor mailToWrapper = Anchor.wrap (RootPanel.get (
		"report-bug-anchor").getElement ());
		mailToWrapper.setHref (getReportBugHref ());
	}
}
