/**
 * Copyright 2009, Res Interactive, LLC. All Rights Reserved.
 */

package com.tootsville;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Vector;
import java.util.Map.Entry;
import java.util.logging.Logger;

import javax.naming.NamingException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import net.authorize.admc.authnet.AimTransaction;
import net.authorize.admc.authnet.AuthNetException;

import org.starhope.appius.except.AlreadyExistsException;
import org.starhope.appius.except.AlreadyUsedException;
import org.starhope.appius.except.DataException;
import org.starhope.appius.except.ForbiddenUserException;
import org.starhope.appius.except.GameLogicException;
import org.starhope.appius.except.NotFoundException;
import org.starhope.appius.except.PrivilegeRequiredException;
import org.starhope.appius.game.AppiusClaudiusCaecus;
import org.starhope.appius.mb.Enrolment;
import org.starhope.appius.mb.Messages;
import org.starhope.appius.mb.Payment;
import org.starhope.appius.mb.PaymentGateway;
import org.starhope.appius.mb.UserAddress;
import org.starhope.appius.mb.UserEnrolment;
import org.starhope.appius.messaging.Mail;
import org.starhope.appius.pay.util.CredentialType;
import org.starhope.appius.pay.util.PaymentCredential;
import org.starhope.appius.pay.util.PaymentGatewayReal;
import org.starhope.appius.pay.util.RetryPaymentException;
import org.starhope.appius.pay.util.UnsupportedCredentialException;
import org.starhope.appius.pay.util.UnsupportedCurrencyException;
import org.starhope.appius.types.AgeBracket;
import org.starhope.appius.types.GameWorldMessage;
import org.starhope.appius.user.AbstractUser;
import org.starhope.appius.user.Parent;
import org.starhope.appius.user.Person;
import org.starhope.appius.user.User;
import org.starhope.appius.util.AppiusConfig;
import org.starhope.util.LibMisc;

import com.tootsville.promo.Promotion;
import com.tootsville.user.Toot;

/**
 * TODO: document this method twheys
 * 
 * @author <a href="mailto:twheys@gmail.com">Tim Heys</a>
 */
public class WebUtil {
	/**
	 * WRITEME
	 */
	private static Logger logger = Logger.getLogger (WebUtil.class
			.getCanonicalName ());
	/**
	 * WRITEME
	 */
	public final static String PARENT = "parent";
	/**
	 * WRITEME
	 */
	public final static String STAFF = "staff";

	/**
	 * WRITEME
	 */
	public final static String USER = "user";

	/**
	 * @param request WRITEME
	 * @param session WRITEME
	 * @param err WRITEME
	 * @return WRITEME
	 */
	public static String afterRulesPage (
			final HttpServletRequest request,
			final HttpSession session, final Map <String, String> err) {
		if (null != request.getParameter ("agree")) {
			WebUtil.log ("A user has agreed to the rules.");
			/*
			 * If the check box to agree to the rules is checked (or
			 * isn't unchecked)
			 */
			if (null != session.getAttribute ("ibc")) {
				session.setAttribute ("register", "paid");
				return "/membership/register/pick-a-toot/";
			}

			if ("paid".equals (session.getAttribute ("register")))
				return "/membership/register/pick-a-toot/";

			return "/membership/register/membership/";
		}
		/*
		 * Show error message:
		 * "You must agree to the rules to play Tootsville."
		 */
		err.put ("agree", LibMisc.getText ("rules_agree"));

		/*
		 * If there was any errors caught, return to last page with the
		 * error message.
		 */
		session.setAttribute ("sError", err);
		System.err
				.println ("Someone doesn't want to agree to the rules.  Ready the lifeguards.");
		return "/membership/register/rules/?register="
				+ session.getAttribute ("register");

	}

	/**
	 * WRITEME
	 * 
	 * @param request WRITEME
	 * @param storeValues WRITEME
	 * @param session WRITEME
	 * @param errorMessages WRITEME
	 * @param successMessages WRITEME
	 * @return WRITEME
	 */
	public static String afterUserDetails (
			final ServletRequest request,
			final Map <String, String> storeValues,
			final HttpSession session,
			final Map <String, String> errorMessages,
			final Map <String, String> successMessages) {
		/* User Details */

		for (final String param : new String [] { "year", "month",
				"day", "username", "password", "passwordConfirm",
				"toot", "securityQuestion", "securityAnswer" }) {
			storeValues.put (param, request.getParameter (param));
		}

		session.setAttribute ("storeValues", storeValues);

		final String registerUsername = request
				.getParameter ("username");
		final String registerPassword = request
				.getParameter ("password");
		final String confirmPassword = request
				.getParameter ("passwordConfirm");
		final String registerToot = (String) session
				.getAttribute ("toot");
		final String question = request
				.getParameter ("securityQuestion");
		final String answer = request.getParameter ("securityAnswer");
		final String register = (String) session
				.getAttribute ("register");

		final String month = request.getParameter ("month");
		final String day = request.getParameter ("day");
		final String year = request.getParameter ("year");

		// Create a string in JDBC timestamp format: yyyy-mm-dd
		final String date = year + "-" + month + "-" + day;

		java.sql.Date dob = null;
		WebUtil.log ("Attempting to construct a new user:"
				+ "\n  Username:   " + registerUsername
				+ "\n  Password:   " + registerPassword
				+ "\n  BirthDate:  " + date + "\n  Question:   "
				+ question + "\n  Answer:     " + answer);

		boolean isAllGood = true;
		if (null != registerUsername && null != registerPassword
				&& null != confirmPassword && null != question
				&& null != answer && registerPassword.length () != 0
				&& date.length () != 0
				&& confirmPassword.length () != 0
				&& question.length () != 0 && answer.length () != 0) {
			Toot sessionUser = null;

			try {
				dob = java.sql.Date.valueOf (date);
			} catch (final IllegalArgumentException e) {
				errorMessages.put ("dob", Messages.dob_invalid ());
				WebUtil
						.log ("User creation failed!  "
								+ "Reason: Date of birth is invalid... User put "
								+ date);
				isAllGood = false;
			}

			if (null == dob) {
				errorMessages.put ("dob", Messages.dob_invalid ());
				WebUtil.log ("User creation failed!  "
						+ "Reason: Date object turned out null... "
						+ "Date string interpretted: " + date);
				isAllGood = false;
			}

			// User must agree to the Ts and Cs
			if (null == request.getParameter ("agree")) {
				errorMessages.put ("agree", LibMisc
						.getText ("agree_terms"));
				WebUtil
						.log ("User creation failed!  "
								+ "Reason: User did not agree to Terms and Conditions.");
				isAllGood = false;
			}

			// User must enter matching passwords
			if (!registerPassword.equals (confirmPassword)) {
				errorMessages.put ("password", LibMisc
						.getText ("password_mismatch"));
				WebUtil
						.log ("User creation failed!  "
								+ "Reason: Password does not match confirmation");
				isAllGood = false;
			}

			// User must enter matching passwords
			if (registerPassword.equals (registerUsername)) {
				errorMessages.put ("password", LibMisc
						.getText ("password_username"));
				WebUtil.log ("User creation failed!  "
						+ "Reason: Password cannot match username");
				isAllGood = false;
			}

			// Password must be a certain length
			if (registerPassword.length () < User.MIN_PW_LENGTH) {
				errorMessages.put ("password", String.format (LibMisc
						.getText ("password_length"),
						User.MIN_PW_LENGTH));
				WebUtil.log ("User creation failed!  "
						+ "Reason: Password too short");
				isAllGood = false;
			}

			// Username must be a certain length
			if (registerUsername.length () < User.MIN_LOGIN_LENGTH) {
				errorMessages.put ("username", String.format (LibMisc
						.getText ("login_length"),
						User.MIN_LOGIN_LENGTH));
				WebUtil.log ("User creation failed!  "
						+ "Reason: Login name too short");
				isAllGood = false;
			}

			// Failsafe check, 'register' cannot be null or something is
			// wrong
			if (null == register) {
				errorMessages.put ("session", LibMisc
						.getText ("login_invalid"));
				WebUtil.log ("User creation failed!  "
						+ "Reason: Register Cookie is null");
				return "/membership/";
			}

			WebUtil
					.log ("Unit Test (All values inputted for user creation): "
							+ isAllGood);

			if (isAllGood) {
				// Create new user account
				try {
					sessionUser = new Toot (dob, registerToot
							.toLowerCase (Locale.ENGLISH),
							registerUsername);
					sessionUser.setPasswordAndPasswordRecovery (
							question, answer, registerPassword);
					WebUtil
							.log ("User Object instantiated and flushed.  Attempting to check for referer.");

					if (null != session.getAttribute ("source")) {
						final String source = (String) session
								.getAttribute ("source");
						sessionUser.setReferer (source);
						session.removeAttribute ("source");
						WebUtil
								.log ("Found a referer cookie!  Referer is set to "
										+ source);
					}

					WebUtil
							.log ("Successfully created user!:"
									+ "\n  ID:          "
									+ sessionUser.getUserID ()
									+ "\n  Username:    "
									+ sessionUser.getUserName ()
									+ "\n  Requested:   "
									+ sessionUser.getRequestedName ()
									+ "\n  Password:    "
									+ sessionUser.getPassword ()
									+ "\n  Basic 8:     "
									+ sessionUser.getBasic8Choice ()
									+ "\n  BirthDate:   "
									+ sessionUser.getBirthDate ()
									+ "\n  Question:    "
									+ sessionUser
											.getForgotPasswordQuestion ()
									+ "\n  Answer:      "
									+ sessionUser
											.getForgotPasswordAnswer ()
									+ "\n  Age Bracket: "
									+ sessionUser.getAgeGroup ()
									+ "\n  Referer:     "
									+ sessionUser.getReferer ()
									+ "\n  Cookie:      "
									+ sessionUser.getApprovalCookie ()
									+ "\n\n");

					if (null != request.getParameter ("code")
							&& !"".equals (request
									.getParameter ("code"))) {
						WebUtil
								.log ("Attempting to redeem peanut code: "
										+ request.getParameter ("code"));
						String pnt = "";
						try {
							pnt = sessionUser.acceptPeanutCode (request
									.getParameter ("code"));
							WebUtil
									.log ("Peanut code accepted with message of "
											+ pnt);
							successMessages.put ("code", pnt);
						} catch (final NotFoundException e) {
							WebUtil.log ("Peanut code denied!");
							errorMessages.put ("code", Messages
									.code_invalid ());
							session.setAttribute ("sError",
									errorMessages);
						} catch (final AlreadyUsedException e) {
							WebUtil.log ("Peanut code denied!");
							errorMessages.put ("code", Messages
									.code_invalid ());
							session.setAttribute ("sError",
									errorMessages);
						}
					}

					if (register.equals ("freeparent")
							|| register.equals ("paidparent")) {
						WebUtil
								.log ("User is being created by a parent.  Setting parent for User.");
						final Parent sessionParent = Parent
								.getByID (Integer.parseInt (session
										.getAttribute ("sUserID")
										.toString ()));

						try {
							sessionUser
									.setParentByParent (sessionParent);
							WebUtil
									.log ("Parent assigned successfully.  Set to Parent ID#"
											+ sessionParent.getID ());
							if (register.equals ("paidparent"))
								return "/membership/register/premium/?toot="
										+ sessionUser.getUserID ();

							return "/membership/register/congrats/?who=parentfreekid&toot="
									+ sessionUser.getUserID ();
						} catch (final GameLogicException e) {
							if ("paid".equals (register
									.substring (0, 3))) {
								successMessages
										.put (
												"username",
												"That user is too old to have a parent account set for them, "
														+ "however we still created the account.  Please continue registering.");
								WebUtil
										.log ("A parent registered a paid adult Toots Account.  "
												+ "Redirecting to billing.");
								return "/membership/register/premium/?toot="
										+ sessionUser.getUserID ();
							}
							successMessages
									.put (
											"username",
											"That user is too old to have a parent account set for them, "
													+ "however we still created the account.  "
													+ "Please enter your child's e-mail.");
							WebUtil
									.log ("A parent registered a free Toots Account.  "
											+ "Redirecting to prompt for e-mail.");
							return "/membership/register/email/";
						}
					}
					// If a user is registering, log them in
					session.setAttribute ("sUserID", sessionUser
							.getUserID ());
					session.setAttribute ("sUserType", WebUtil.USER);
					session.setAttribute ("sUserPassword",
							registerPassword);
					WebUtil
							.log ("Session being assigned to new user ID#"
									+ sessionUser.getUserID ());

					if (null != session.getAttribute ("ibc")) {
						WebUtil.log ("New User ID#"
								+ sessionUser.getUserID ()
								+ " has a Chase-It Cookie.  "
								+ "Redirecting to prompt for e-mail.");
						return "/membership/register/email/";
					}

					if (register.equals ("paid")) {
						WebUtil.log ("New User ID#"
								+ sessionUser.getUserID ()
								+ " selected a paid membership.  "
								+ "Redirecting them to billing.");
						return "/membership/register/premium/?toot="
								+ sessionUser.getUserID ();
					}
					WebUtil.log ("New User ID#"
							+ sessionUser.getUserID ()
							+ " selected a free membership.  "
							+ "Redirecting them to prompt for e-mail.");
					return "/membership/register/email/";

				} catch (final AlreadyUsedException e) {
					WebUtil.log ("User creation failed!  "
							+ "Reason: Username already taken.");
					errorMessages.put ("username", LibMisc
							.getText ("username_unavail"));
				} catch (final ForbiddenUserException e) {
					WebUtil.log ("User creation failed!  "
							+ "Reason: Username is forbidden.");
					errorMessages.put ("username", LibMisc
							.getText ("username_invalid"));
				} catch (final NumberFormatException e) {
					WebUtil.log ("User creation failed!  "
							+ "Reason: Date is invalid.");
					errorMessages.put ("dob", Messages.dob_invalid ());
				} catch (final GameLogicException e) {
					WebUtil
							.log ("User creation failed!  "
									+ "Reason: Password cannot match username.");
					errorMessages.put ("password", LibMisc
							.getText ("password_username"));
				}
			}
		} else {
			if (null == registerUsername
					|| registerUsername.length () == 0) {
				errorMessages.put ("username", Messages
						.blank_field ("username"));
			}
			if (null == registerPassword
					|| registerPassword.length () == 0) {
				errorMessages.put ("password", Messages
						.blank_field ("password"));
			}
			if (date.length () == 0) {
				errorMessages.put ("dob", Messages
						.blank_field ("date of birth"));
			}
			if (null == confirmPassword
					|| confirmPassword.length () == 0) {
				errorMessages.put ("passwordConfirm", Messages
						.blank_field ("password confirmation"));
			}
			if (null == answer || answer.length () == 0) {
				errorMessages.put ("answer", Messages
						.blank_field ("forgotten password answer"));
			}
		}

		if (errorMessages.size () > 0) {
			/*
			 * If there was any errors caught, return to last page with
			 * the error message.
			 */
			session.setAttribute ("sError", errorMessages);
			WebUtil.log ("An error has been made from User-Details."
					+ "  Pushing User back to User Details page.");
			return "/membership/register/user-details/";
		}
		return null;
	}

	/**
	 * <pre>
	 * theys Jan 12, 2010
	 * </pre>
	 * 
	 * TO approveAccount WRITEME...
	 * 
	 * @param memberToApprove WRITEME
	 */
	public static void approveAccount (final Toot memberToApprove) {
		memberToApprove.parentApprovedAccount (true);
		memberToApprove.parentApprovedName (true);
	}

	/**
	 * <pre>
	 * theys Jan 7, 2010
	 * </pre>
	 * 
	 * TO createNewEventPromotion WRITEME...
	 * 
	 * @param prefix WRITEME
	 * @param numberOfCodes WRITEME
	 * @param minValue WRITEME
	 * @param maxValue WRITEME
	 */
	public static void createNewEventPromotion (final String prefix,
			final int numberOfCodes, final int minValue,
			final int maxValue) {
		try {
			final Promotion p = Promotion.createEventPromotion (prefix);
			p.createPeanutCodesForPromotion (numberOfCodes, minValue,
					maxValue);
		} catch (final IndexOutOfBoundsException e) {
			e.printStackTrace ();
		} catch (final DataException e) {
			e.printStackTrace ();
		} catch (final AlreadyExistsException e) {
			e.printStackTrace ();
		}

	}

	/**
	 * WRITEME
	 * 
	 * @param userName WRITEME
	 * @param password WRITEME
	 * @return WRITEME
	 * @throws PrivilegeRequiredException WRITEME
	 */
	public static Parent createParentLogin (final String userName,
			final String password) throws PrivilegeRequiredException {
		Parent parent; // reference returned to web page.
		if (null != userName)
			return null;
		parent = Parent.getByMail (userName);
		if (!parent.checkPassword (password))
			throw new PrivilegeRequiredException (LibMisc
					.getText ("password_invalid"));

		return parent;
	}

	/**
	 * WRITEME
	 * 
	 * @param userName The user name or ID entered to login as a user
	 * @param password The password for user's account
	 * @return a reference to the user's User class
	 * @throws PrivilegeRequiredException if password is invalid
	 */
	public static User createUserLogin (final String userName,
			final String password) throws PrivilegeRequiredException {
		final AbstractUser user // reference returned to web page.
		= User.getByLogin (userName);
		if (null == user) {
			WebUtil.log ("Failed login.  No such user " + userName
					+ "//" + password + " exists!");

			return null;
		}
		if (! (user instanceof User)) {
			WebUtil.log ("Not a User (AbstractUser "
					+ user.getAvatarLabel () + ")");
			throw new PrivilegeRequiredException (LibMisc
					.getText ("password_invalid"));
		}

		if (! ((User) user).checkPassword (password)) {
			WebUtil
					.log ("Failed login.  Password does not match records.");

			throw new PrivilegeRequiredException (LibMisc
					.getText ("password_invalid"));
		}

		return (User) user;
	}

	/**
	 * WRITEME
	 * 
	 * @param request WRITEME
	 * @param storeValues WRITEME
	 * @param session WRITEME
	 * @param err WRITEME
	 * @return WRITEME
	 */
	public static String doAfterParent (final ServletRequest request,
			final Map <String, String> storeValues,
			final HttpSession session, final Map <String, String> err) {
		Parent sessionUser = null;
		String registerEmail = "";
		String confirmEmail = "";
		String registerPassword = "";
		String confirmPassword = "";
		String givenName = "";
		String question = "";
		String answer = "";
		if (null != request.getParameter ("email")
				&& null != request.getParameter ("emailConfirm")
				&& null != request.getParameter ("password")
				&& null != request.getParameter ("passwordConfirm")
				&& null != request.getParameter ("securityAnswer")
				&& !"".equals (request.getParameter ("email"))
				&& !"".equals (request.getParameter ("emailConfirm"))
				&& !"".equals (request.getParameter ("password"))
				&& !""
						.equals (request
								.getParameter ("passwordConfirm"))
				&& !"".equals (request.getParameter ("securityAnswer"))) {
			registerEmail = request.getParameter ("email");
			storeValues.put ("email", registerEmail);
			confirmEmail = request.getParameter ("emailConfirm");
			storeValues.put ("emailConfirm", confirmEmail);
			registerPassword = request.getParameter ("password");
			confirmPassword = request.getParameter ("passwordConfirm");
			if (null != request.getParameter ("givenName")
					&& !"".equals (request.getParameter ("givenName"))) {
				givenName = request.getParameter ("givenName");
				storeValues.put ("givenName", givenName);
			}
			question = request.getParameter ("securityQuestion");
			storeValues.put ("securityQuestion", question);
			answer = request.getParameter ("securityAnswer");
			storeValues.put ("securityAnswer", answer);

			session.setAttribute ("storeValues", storeValues);
			boolean isAllGood = true;
			WebUtil.log ("Attempting to construct a new Parent:"
					+ "\n  Mail:       " + registerEmail
					+ "\n  Password:   " + registerPassword
					+ "\n  Question:   " + question
					+ "\n  Answer:     " + answer);

			try {
				Mail.validateMail (registerEmail);
			} catch (final DataException e1) {
				err.put ("email", LibMisc.getText ("mail_invalid"));
				WebUtil.log ("Parent creation failed!  Email address "
						+ registerEmail + " is invalid.");
				isAllGood = false;
			} catch (final NamingException e1) {
				err.put ("email", LibMisc.getText ("mail_invalid"));
				WebUtil
						.log ("Parent creation failed!  Email address "
								+ registerEmail
								+ " might be valid or invalid (can't be determined).");
				isAllGood = false;
			} catch (final RuntimeException e) {
				err.put ("email", LibMisc.getText ("mail_invalid"));
				WebUtil.log ("Parent creation failed!  Email address "
						+ registerEmail + " is invalid.");
				isAllGood = false;
			}

			if (!registerEmail.equals (confirmEmail)) {
				err.put ("email", LibMisc.getText ("mail_mismatch"));
				WebUtil
						.log ("Parent creation failed!  Email addresses inputted do not match.");
				isAllGood = false;
			}

			if (!registerPassword.equals (confirmPassword)) {
				err.put ("password", LibMisc
						.getText ("password_mismatch"));
				WebUtil
						.log ("Parent creation failed!  Passwords inputted do not match.");
				isAllGood = false;
			}

			WebUtil
					.log ("Unit Test: (Parent registration input verified) "
							+ isAllGood);

			if (isAllGood) {
				sessionUser = Parent.getOrCreateByMail (registerEmail);
				WebUtil
						.log ("Parent creation success!  New parent created with e-mail "
								+ registerEmail
								+ " has been assigned ID# "
								+ sessionUser.getID ());

				WebUtil.log ("Sending confirmation to parent ID#"
						+ sessionUser.getID ());
				// Send confirmation of new account to user
				sessionUser.sendConfirmationMail ();

				try {
					if (!sessionUser.isRegistered ()) {

						// throws gamelogicexception
						sessionUser.setPasswordAndPasswordRecovery (
								question, answer, registerPassword);

						WebUtil.log ("Set password to "
								+ registerPassword);
						WebUtil.log ("Set Q and A to: " + "\n      "
								+ question + "  " + answer);

						if (null != givenName && !givenName.equals ("")) {
							sessionUser.setGivenName (givenName);
							WebUtil.log ("Set given name to "
									+ givenName);
						}

						// Create session for user
						session.setAttribute ("sUserID", sessionUser
								.getID ());
						session.setAttribute ("sUserType",
								WebUtil.PARENT);
						session.setAttribute ("sUserPassword",
								registerPassword);
						WebUtil
								.log ("Session created for registered parent.  Redirecting to confirm mail.");

						return "/membership/register/parent/check-email.jsp?id="
								+ (0 + sessionUser.getID ());
					}
					err
							.put (
									"username",
									LibMisc
											.getText ("parent_account_already_exists.html"));

					WebUtil
							.log ("Parent "
									+ registerEmail
									+ " tried to re-register.  Account already exists with ID "
									+ sessionUser.getID ());
				} catch (final GameLogicException e) {
					WebUtil
							.log ("User creation failed!  "
									+ "Reason: Password cannot match username.");
					err.put ("password", LibMisc
							.getText ("password_username"));
				}
			}
		} else {
			if (null == request.getParameter ("email")
					|| "".equals (request.getParameter ("email"))) {
				err.put ("email", Messages.blank_field ("e-mail"));
			} else {
				registerEmail = request.getParameter ("email");
				storeValues.put ("email", registerEmail);
			}
			if (null == request.getParameter ("emailConfirm")
					|| ""
							.equals (request
									.getParameter ("emailConfirm"))) {
				err.put ("emailConfirm", Messages
						.blank_field ("e-mail confirmation"));
			} else {
				confirmEmail = request.getParameter ("emailConfirm");
				storeValues.put ("emailConfirm", confirmEmail);
			}
			if (null == request.getParameter ("password")
					|| "".equals (request.getParameter ("password"))) {
				err.put ("password", Messages.blank_field ("password"));
			} else {
				// registerPassword = request.getParameter ("password");
				// confirmPassword = request
				// .getParameter ("passwordConfirm");
			}
			if (null == request.getParameter ("passwordConfirm")
					|| "".equals (request
							.getParameter ("passwordConfirm"))) {
				err.put ("passwordConfirm", Messages
						.blank_field ("password confirmation"));
			}
			if (null == request.getParameter ("securityAnswer")
					|| "".equals (request
							.getParameter ("securityAnswer"))) {
				err.put ("answer", Messages
						.blank_field ("forgotten password answer"));
			} else {
				answer = request.getParameter ("securityAnswer");
				storeValues.put ("securityAnswer", answer);

			}
			if (null != request.getParameter ("givenName")
					&& !"".equals (request.getParameter ("givenName"))) {
				givenName = request.getParameter ("givenName");
				storeValues.put ("givenName", givenName);
			}
			question = request.getParameter ("securityQuestion");
			storeValues.put ("securityQuestion", question);

			session.setAttribute ("storeValues", storeValues);
		}

		if (err.size () > 0) {
			/*
			 * If there was any errors caught, return to last page with
			 * the error message.
			 */
			session.setAttribute ("sError", err);
			WebUtil.log ("An error has been made from Parent-Details."
					+ "  Pushing User back to Parent Details page.");

			return "/membership/register/parent/";
		}
		return null;
	}

	/**
	 * WRITEME
	 * 
	 * @param request WRITEME
	 * @param storeValues WRITEME
	 * @param session WRITEME
	 * @param err WRITEME
	 * @return WRITEME
	 */
	public static String fromMail (final HttpServletRequest request,
			final HashMap <String, String> storeValues,
			final HttpSession session,
			final HashMap <String, String> err) {
		Toot sessionUser = null;
		if (null != request.getParameter ("email")
				&& !request.getParameter ("email").equals ("")
				&& null != request.getParameter ("emailConfirm")
				&& !request.getParameter ("emailConfirm").equals ("")) {

			final String registerEmail = request.getParameter ("email");
			final String confirmEmail = request
					.getParameter ("emailConfirm");
			final Integer userID = (Integer) session
					.getAttribute ("sUserID");
			final String userType = session.getAttribute ("sUserType")
					.toString ();

			if (userType.equals (WebUtil.USER)) {
				sessionUser = (Toot) User.getByID (userID);
				if (null == sessionUser) {
					err.put ("username", LibMisc
							.getText ("login_invalid"));
					WebUtil
							.log ("User:  ("
									+ userID
									+ ") failed to set up their email.  They have timed out.");
					session.setAttribute ("sError", err);
					return "/membership/";
				}
				try {
					Mail.validateMail (registerEmail);

					if (registerEmail.equals (confirmEmail)) {
						if (AgeBracket.Kid == sessionUser
								.getAgeGroup ()) {
							final Parent sessionParent = Parent
									.getOrCreateByMail (registerEmail);
							try {
								sessionUser.setParent (sessionParent);
								WebUtil
										.log ("User:  ("
												+ userID
												+ ") has been associated with Parent ID#"
												+ sessionParent
														.getID ()
												+ " with the mail address "
												+ sessionParent
														.getMail ());
							} catch (final GameLogicException e) {
								// Default catch action, report bug
								// (theys, Sep 11, 2009)
								AppiusClaudiusCaecus.reportBug (e);
							} catch (final ForbiddenUserException e) {
								// Default catch action, report bug
								// (theys, Sep 11, 2009)
								AppiusClaudiusCaecus.reportBug (e);
							}
							sessionParent
									.sendNotificationForChild (sessionUser);
							if (null != session.getAttribute ("ibc")) {
								final String ecode = (String) session
										.getAttribute ("ibc");
								try {
									WebUtil
											.log ("Applying Chase-It eCode ("
													+ ecode
													+ ") to User ID: "
													+ sessionUser
															.getUserID ());
									IBCUtil.redeemCode (ecode,
											sessionUser);
									WebUtil
											.log ("Chase-It eCode applied successfully to User ID: "
													+ sessionUser
															.getUserID ());
								} catch (final DataException e) {
									// Default catch action, report bug
									// (theys,
									// Sep 29, 2009)
									AppiusClaudiusCaecus.reportBug (e);
								}
								session.removeAttribute ("ibc");
								return "/membership/register/thankyou/?who=chase";
							}
							return "/membership/register/congrats/?who=freechild";
						}
						try {
							sessionUser.setMail (registerEmail);
							WebUtil
									.log ("User:  ("
											+ userID
											+ ") has registered with the mail address "
											+ sessionUser.getMail ());
						} catch (final GameLogicException e) {
							// Default catch action, report bug
							// (theys, Sep 11, 2009)
							AppiusClaudiusCaecus.reportBug (e);
						}
						if (null != request.getParameter ("canContact")) {
							sessionUser.setCanContact (true);
							WebUtil
									.log ("User ID#"
											+ sessionUser.getUserID ()
											+ " has agreed to recieve promotions.");
						}
						if (null != session.getAttribute ("ibc")) {
							final String ecode = (String) session
									.getAttribute ("ibc");
							try {
								WebUtil
										.log ("User ID#"
												+ sessionUser
														.getUserID ()
												+ " is attempting to apply Chase-It eCode: "
												+ ecode);
								IBCUtil.redeemCode (ecode, sessionUser);
								WebUtil
										.log ("User ID#"
												+ sessionUser
														.getUserID ()
												+ " has applied Chase-It eCode: "
												+ ecode);
							} catch (final DataException e) {
								// Default catch action, report bug
								// (theys,
								// Sep 29, 2009)
								AppiusClaudiusCaecus.reportBug (e);
							}
							session.removeAttribute ("ibc");
							return "/membership/register/thankyou/?who=chase";
						}
						return "/membership/register/congrats/?who=freeuser";
					}
					err
							.put ("email", LibMisc
									.getText ("mail_mismatch"));

				} catch (final DataException e) {
					err.put ("mail", LibMisc.getText ("mail_invalid"));
				} catch (final NamingException e) {
					err.put ("mail", LibMisc.getText ("mail_invalid"));
				}
			} else {
				err.put ("username", LibMisc.getText ("login_invalid"));
				WebUtil
						.log ("Failed to assign e-mail address.  Session stored is not a User object.");
				return "/membership/";
			}
		} else {
			err.put ("username", LibMisc.getText ("mail_invalid"));
		}

		if (err.size () > 0) {
			/*
			 * If there was any errors caught, return to last page with
			 * the error message.
			 */
			session.setAttribute ("sError", err);
			WebUtil.log ("Bad input for e-mail: ("
					+ request.getParameter ("email")
					+ ").  Redirecting user to e-mail page.");
			return "/membership/register/email/";
		}
		return "/membership/"; // default fall-back
	}

	/**
	 * <pre>
	 * theys Jan 20, 2010
	 * </pre>
	 * 
	 * TO getRecentTootbookPosts WRITEME...
	 * 
	 * @param offset
	 * @param limit
	 * @return
	 */
	public static Vector <GameWorldMessage> getRecentTootbookPosts (
			final int offset, final int limit) {
		Vector <GameWorldMessage> messages = new Vector <GameWorldMessage> ();
		Connection con = null;
		PreparedStatement st = null;
		try {
			con = AppiusConfig.getDatabaseConnection ();
			st = con
					.prepareStatement ("SELECT * FROM messages WHERE fromUserID=toUserID AND isDeleted='W' AND inReplyTo IS NULL AND body<>'' ORDER BY messages.sentTime DESC LIMIT ? OFFSET ?");
			st.setInt (1, limit);
			st.setInt (2, offset);
			messages = AppiusConfig.newGameWorldMessage ()
					.getMessagesFrom (st);
		} catch (final SQLException e) {
			AppiusClaudiusCaecus.reportBug (e);
		} finally {
			if (null != st) {
				try {
					st.close ();
				} catch (final SQLException e) { /* No Op */
				}
			}
			if (null != con) {
				try {
					con.close ();
				} catch (final SQLException e) { /* No Op */
				}
			}
		}
		return messages;
	}

	/**
	 * WRITEME
	 * 
	 * @param logMessage WRITEME
	 */
	public static void log (final boolean logMessage) {
		WebUtil.log (String.valueOf (logMessage));
	}

	/**
	 * WRITEME
	 * 
	 * @param logMessage WRITEME
	 */
	public static void log (final char logMessage) {
		WebUtil.log (String.valueOf (logMessage));
	}

	/**
	 * WRITEME
	 * 
	 * @param logMessage WRITEME
	 */
	public static void log (final char [] logMessage) {
		WebUtil.log (String.valueOf (logMessage));
	}

	/**
	 * WRITEME
	 * 
	 * @param logMessage WRITEME
	 */
	public static void log (final double logMessage) {
		WebUtil.log (String.valueOf (logMessage));
	}

	/**
	 * WRITEME
	 * 
	 * @param logMessage WRITEME
	 */
	public static void log (final float logMessage) {
		WebUtil.log (String.valueOf (logMessage));
	}

	/**
	 * WRITEME
	 * 
	 * @param logMessage WRITEME
	 */
	public static void log (final int logMessage) {
		WebUtil.log (String.valueOf (logMessage));
	}

	/**
	 * WRITEME
	 * 
	 * @param logMessage WRITEME
	 */
	public static void log (final long logMessage) {
		WebUtil.log (String.valueOf (logMessage));
	}

	/**
	 * WRITEME
	 * 
	 * @param logMessage WRITEME
	 */
	public static void log (final short logMessage) {
		WebUtil.log (String.valueOf (logMessage));
	}

	/**
	 * WRITEME
	 * 
	 * @param logMessage WRITEME
	 */
	public static void log (final String logMessage) {
		WebUtil.logger.info (logMessage);
	}

	/**
	 * WRITEME: Document this field. theys Dec 9, 2009
	 * 
	 * @param session WRITEME
	 * @param request WRITEME
	 * @param err WRITEME
	 * @param storeValues WRITEME
	 * @return WRITEME
	 */
	public static String processCC (final HttpSession session,
			final ServletRequest request,
			final HashMap <String, String> err,
			final HashMap <String, String> storeValues) {
		/*
		 * Parent/User object. On myAccount this should be declared User
		 * and on parent this should be declared Parent
		 */
		Person pageVisitor = null;
		Toot memberBeingSubscribed = null;
		String membershipRequested = null;
		String subscribeUserID = "FIXME";

		if (null != session.getAttribute ("mem")
				&& !session.getAttribute ("mem").equals ("")) {
			membershipRequested = session.getAttribute ("mem")
					.toString ();
		} else {
			err.put ("username", LibMisc.getText ("login_invalid"));
			session.setAttribute ("sError", err);
			return "/membership/register/premium/";
		}

		if (null != session.getAttribute ("id")
				&& !session.getAttribute ("id").equals ("")) {
			subscribeUserID = session.getAttribute ("id").toString ();
		} else {
			err.put ("username", LibMisc.getText ("login_invalid"));
			session.setAttribute ("sError", err);
			return "/membership/register/premium/";
		}

		String ccType = "";
		String ccNum = "";
		String ccExpMonth = "";
		String ccExpYear = "";
		String firstName = "";
		String lastName = "";
		String email = "";
		String country = "";
		String address = "";
		String zip = "";
		String phoneNumber = "";
		String state = "";
		String locality = "";
		String province = "";
		String city = "";
		if (null != request.getParameter ("ccType")
				&& null != request.getParameter ("ccNum")
				&& null != request.getParameter ("ccExpMonth")
				&& null != request.getParameter ("ccExpYear")
				&& null != request.getParameter ("ccv")
				&& null != request.getParameter ("email")
				&& null != request.getParameter ("firstName")
				&& null != request.getParameter ("lastName")
				&& null != request.getParameter ("email")
				&& null != request.getParameter ("country")
				&& null != request.getParameter ("address")
				&& null != request.getParameter ("zip")
				&& !"".equals (request.getParameter ("ccType"))
				&& !"".equals (request.getParameter ("ccNum"))
				&& !"".equals (request.getParameter ("ccExpMonth"))
				&& !"".equals (request.getParameter ("ccExpYear"))
				&& !"".equals (request.getParameter ("ccv"))
				&& !"".equals (request.getParameter ("email"))
				&& !"".equals (request.getParameter ("firstName"))
				&& !"".equals (request.getParameter ("lastName"))
				&& !"".equals (request.getParameter ("email"))
				&& !"".equals (request.getParameter ("country"))
				&& !"".equals (request.getParameter ("address"))
				&& !"".equals (request.getParameter ("zip"))) {

			// Collect credit-card information.
			ccType = request.getParameter ("ccType");
			storeValues.put ("ccType", ccType);
			ccNum = request.getParameter ("ccNum");
			ccExpMonth = request.getParameter ("ccExpMonth");
			ccExpYear = request.getParameter ("ccExpYear");
			final String ccv = request.getParameter ("ccv");
			firstName = request.getParameter ("firstName");
			storeValues.put ("firstName", firstName);
			lastName = request.getParameter ("lastName");
			storeValues.put ("lastName", lastName);
			email = request.getParameter ("email");
			storeValues.put ("email", email);
			country = request.getParameter ("country");
			storeValues.put ("country", country);
			address = request.getParameter ("address");
			storeValues.put ("address", address);
			zip = request.getParameter ("zip");
			storeValues.put ("zip", zip);
			WebUtil
					.log ("Unit Test (AuthNet Test Mode): "
							+ AppiusConfig
									.getConfigBoolOrFalse ("net.authorize.testMode"));
			if (country.equals ("eu")) {
				country = request.getParameter ("eu_country")
						.substring (1);
				WebUtil.log ("Eu checkout");
				storeValues.put ("country", "." + country);
			}

			if (null != request.getParameter ("phoneNumber")
					&& !request.getParameter ("phoneNumber")
							.equals ("")) {
				phoneNumber = request.getParameter ("phoneNumber");
				storeValues.put ("phoneNumber", phoneNumber);
			}
			if (null != request.getParameter ("state")
					&& !request.getParameter ("state").equals ("")) {
				state = request.getParameter ("state");
				storeValues.put ("state", state);
			}
			if (null != request.getParameter ("locality")
					&& !request.getParameter ("locality").equals ("")) {
				locality = request.getParameter ("locality");
				storeValues.put ("state", locality);
			}
			if (null != request.getParameter ("province")
					&& !request.getParameter ("province").equals ("")) {
				province = request.getParameter ("province");
				storeValues.put ("province", province);
			}
			if (null != request.getParameter ("city")
					&& !request.getParameter ("city").equals ("")) {
				city = request.getParameter ("city");
				storeValues.put ("city", city);
			}

			WebUtil
					.log ("\n********************************************************************************"
							+ "\n********************************************************************************"
							+ "\n*************     A Credit Card Transaction Is Being Processed     *************"
							+ "\n********************************************************************************"
							+ "\n********************************************************************************");

			if (null != session.getAttribute ("sUserID")
					&& null != session.getAttribute ("sUserPassword")
					&& null != session.getAttribute ("sUserType")) {
				final String userOrParentID = session.getAttribute (
						"sUserID").toString ();
				final String pageVisitorType = session.getAttribute (
						"sUserType").toString ();

				if (pageVisitorType.equals (WebUtil.USER)) {
					final AbstractUser pageUser = User.getByID (Integer
							.parseInt (userOrParentID));
					if (! (pageUser instanceof Person))
						throw AppiusClaudiusCaecus
								.fatalBug ("session user type is out of sync");
					pageVisitor = (Person) pageUser;
					if ( ((Toot) pageVisitor).needsParent ()) {
						try {
							try {
								((Toot) pageVisitor).setParent (Parent
										.getOrCreateByMail (email));
							} catch (final ForbiddenUserException e) {
								// Attempting to set Mail for parent
								AppiusClaudiusCaecus
										.reportBug (
												"Unable to set parent in process.jsp",
												e);
							}
						} catch (final GameLogicException e) {
							// Default catch action, report bug
							// (theys, Sep 11, 2009)
							AppiusClaudiusCaecus
									.reportBug (
											"User needs parent but one cannot be set",
											e);
						}
					} else if (null == pageVisitor.getMail ()
							&& AgeBracket.Kid != ((Toot) pageVisitor)
									.getAgeGroup ()) {
						try {
							pageVisitor.setMail (email);
							WebUtil.log ("Updated "
									+ pageVisitor.getDisplayName ()
									+ "'s e-mail to " + email + ".");
						} catch (final RuntimeException e) {
							// Do nothing
						} catch (final GameLogicException e) {
							// Default catch action, report bug
							// (theys, Nov 3, 2009)
							AppiusClaudiusCaecus.reportBug (e);
						}
					}
					memberBeingSubscribed = (Toot) User
							.getByID (Integer
									.parseInt (subscribeUserID));
					WebUtil.log ("User ID#"
							+ ((User) pageVisitor).getUserID ()
							+ " is attempting to check out.");

				} else if (pageVisitorType.equals (WebUtil.PARENT)) {
					pageVisitor = Parent.getByID (Integer
							.parseInt (userOrParentID));
					memberBeingSubscribed = (Toot) User
							.getByID (Integer
									.parseInt (subscribeUserID));
					if (null == pageVisitor.getMail ()) {
						try {
							pageVisitor.setMail (email);
						} catch (final GameLogicException e) {
							// Default catch action, report bug (theys,
							// Oct 1, 2009)
							AppiusClaudiusCaecus.reportBug (
									"Mail not being set for user", e);
						}

						WebUtil.log ("Parent ID#"
								+ ((Parent) pageVisitor).getID ()
								+ " is attempting to check out.");
					}
				}

				if (null != memberBeingSubscribed) {
					WebUtil
							.log ("AuthNet Transaction is being made to upgrade User ID#"
									+ memberBeingSubscribed
											.getUserID () + ".");

					Enrolment enrolmentChosen = null;
					try {
						try {
							enrolmentChosen = Enrolment
									.getByID (Integer
											.parseInt (membershipRequested));
						} catch (final NotFoundException caught) {
							err.put ("membership", LibMisc
									.getText ("subscription_invalid"));
							AppiusClaudiusCaecus
									.reportBug ("Enrolment not found!  We don't have enrolment ID#"
											+ membershipRequested);
							return "/membership/register/premium/billing.jsp";
						}

						if (null == enrolmentChosen)
							throw new NotFoundException (
									membershipRequested);
						WebUtil.log ("User ID#"
								+ memberBeingSubscribed.getUserID ()
								+ " is purchasing product: "
								+ enrolmentChosen.getTitle ());
					} catch (final NotFoundException e) {
						AppiusClaudiusCaecus.reportBug ("Product for "
								+ membershipRequested
								+ " is not successful.", e);
						err.put ("subscription", LibMisc
								.getText ("subscription_invalid"));
						return "/membership/register/premium/billing.jsp";
					}

					final PaymentCredential credentials = new PaymentCredential ();
					try {
						credentials.setCardNumber (ccNum);
					} catch (final NumberFormatException e) {
						WebUtil
								.log ("Credit card not being set.  Contains chars other than digits.");
						err.put ("ccNum", LibMisc
								.getText ("cc_invalid"));
						return "/membership/register/premium/billing.jsp";
					}
					if ("visa".equals (ccType)) {
						credentials
								.setCredentialType (CredentialType.VISA);
						WebUtil.log ("CC: "
								+ credentials.getCredentialType ());
					} else if ("mastercard".equals (ccType)) {
						credentials
								.setCredentialType (CredentialType.MC);
						WebUtil.log ("CC: "
								+ credentials.getCredentialType ());
					} else {
						WebUtil.log ("cc is not being set.");
						err.put ("ccNum", LibMisc
								.getText ("onlyVisaOrMC"));
						return "/membership/register/premium/billing.jsp";
					}
					WebUtil.log ("Transaction for User ID#"
							+ memberBeingSubscribed.getUserID ()
							+ " is being made with a "
							+ credentials.getCredentialType ()
									.toString () + " card.");

					try {
						credentials.setCardCodeAsString (ccv);
					} catch (final NumberFormatException e) {
						err
								.put ("ccv", LibMisc
										.getText ("ccv_invalid"));
						return "/membership/register/premium/billing.jsp";
					}

					try {
						credentials.verifyCredentials ();
					} catch (final DataException e1) {
						WebUtil
								.log ("DataException thrown on verifying credentials!"
										+ "  Complaint: "
										+ e1.getComplaint ());
						return "/membership/register/premium/billing.jsp";
					}

					Date expDate = null;
					try {
						// Create a string in JDBC timestamp format:
						// yyyy-mm-dd
						final String date = ccExpYear + "-"
								+ ccExpMonth + "-" + 1;

						expDate = java.sql.Date.valueOf (date);
						if (expDate.getTime () < System
								.currentTimeMillis ()) {
							WebUtil
									.log ("Transaction Failed!  CC Expiration Date is invalid: "
											+ expDate);
							err.put ("ccExpYear", Messages
									.exp_invalid ());
							return "/membership/register/premium/billing.jsp";
						}
					} catch (final NumberFormatException e) {
						WebUtil
								.log ("Transaction Failed!  Input for Expiration year is invalid: "
										+ ccExpYear);
						err.put ("ccExpYear", Messages.exp_invalid ());
						return "/membership/register/premium/billing.jsp";
					}

					credentials.setExpiry (expDate);

					final UserAddress addy = new UserAddress ();
					addy.setAddress (address, "");
					addy.setCity (city);
					addy.setProvince ("");
					addy.setPhone (phoneNumber);
					if (state.length () > 0) {
						addy.setProvince (state);
					}
					if (province.length () > 0) {
						addy.setProvince (province);
					} else if (locality.length () > 0) {
						addy.setProvince (locality);
					}
					addy.setCountry (country);
					addy.setPostalCode (zip);
					addy.setMail (email);
					if (!addy.validate ()) {
						err.put ("address", LibMisc
								.getText ("cc_invalid"));
						return "/membership/register/premium/billing.jsp";
					}

					credentials
							.setBuyerInfo (firstName, lastName, addy);

					UserEnrolment subscription = null;

					try {

						subscription = new UserEnrolment ("auth",
								enrolmentChosen.getProductID (),
								memberBeingSubscribed.getUserID ());
						WebUtil.log ("Enrolment Created Successfully!"
								+ "\n    Product ID: "
								+ subscription.getProductID ()
								+ "\n    User ID:    "
								+ subscription.getUserID ()
								+ "\n    Price:      "
								+ subscription.getEnrolment ()
										.getPrice ()
								+ "\n    VIT Time:   "
								+ subscription.getEnrolment ()
										.getPrivilegeDays ()
								+ "\n    Product:    "
								+ subscription.getEnrolment ()
										.getProductCode ()
								+ "\n    Begin Date: "
								+ Messages.prettyDate (subscription
										.getBegins ()));

					} catch (final NotFoundException e) {
						AppiusClaudiusCaecus
								.reportBug (
										"Enrolment Not Found for an Enrolment that already exists!",
										e);
						err.put ("membership", LibMisc
								.getText ("subscription_unavailable"));
						return "/membership/register/premium/billing.jsp";
					}

					Payment payment = null;

					try {
						payment = new Payment (subscription);
						WebUtil.log ("Payment Created Successfully!");
					} catch (final NotFoundException e) {
						AppiusClaudiusCaecus.reportBug (
								"Can't create a payment object for subscription ID#"
										+ subscription.getInvoiceID (),
								e);
					}

					try {
						if (null != payment) {
							payment.setCredentials (credentials);
							WebUtil.log ("Credentials set in Payment!");
							payment
									.setPayer (credentials
											.getBuyerGivenName ()
											+ " "
											+ credentials
													.getBuyerFamilyName ());
							WebUtil.log ("Payer is set to "
									+ payment.getPayer ());
						}
					} catch (final AlreadyUsedException e) {
						WebUtil
								.log ("Transaction failed!  Payment already exists.");
						err.put ("payment", LibMisc
								.getText ("retry_payment"));
						return "/membership/register/premium/billing.jsp";
					}

					PaymentGatewayReal gateway = null;
					try {
						WebUtil.log ("Setting Gateway");
						gateway = PaymentGateway
								.getByClass (PaymentGateway
										.get (subscription
												.getOrderSource ()));
						WebUtil.log ("Gateway Set as "
								+ gateway.getClass ()
										.getCanonicalName ());

						try {
							gateway.startTransaction (payment);
						} catch (final UnsupportedCurrencyException e) {
							err.put ("", LibMisc
									.getText ("unsupported_currency"));
							return "/membership/register/premium/billing.jsp";

						} catch (final NotFoundException e) {
							WebUtil
									.log ("Transaction Failed! Exception thrown: "
											+ e
													.getClass ()
													.getCanonicalName ());
							err
									.put (
											"subscription",
											LibMisc
													.getText ("subscription_unavailable"));
							return "/membership/register/premium/billing.jsp";

						} catch (final UnsupportedCredentialException e) {
							WebUtil
									.log ("Transaction Failed! Exception thrown: "
											+ e
													.getClass ()
													.getCanonicalName ());
							err.put ("ccNum", LibMisc
									.getText ("cc_invalid"));
							return "/membership/register/premium/billing.jsp";

						} catch (final RetryPaymentException e) {
							WebUtil
									.log ("Transaction Failed! Exception thrown: "
											+ e
													.getClass ()
													.getCanonicalName ());
							err.put ("retry", LibMisc
									.getText ("retry_payment"));
							return "/membership/register/premium/billing.jsp";

						} catch (final GameLogicException e) {
							WebUtil
									.log ("Transaction Failed! Exception thrown: "
											+ e
													.getClass ()
													.getCanonicalName ());
							err.put ("payment", LibMisc
									.getText ("payment_already_made"));
							return "/membership/register/premium/billing.jsp";
						} catch (final IOException e) {
							WebUtil
									.log ("Transaction Failed! Exception thrown: "
											+ e
													.getClass ()
													.getCanonicalName ());
							err.put ("gateway",
									"Payment Gateway Offline...");
							return "/membership/register/premium/billing.jsp";
						} catch (final AlreadyUsedException e) {
							WebUtil
									.log ("Transaction Failed! Exception thrown: "
											+ e
													.getClass ()
													.getCanonicalName ());
							err.put ("payment", LibMisc
									.getText ("payment_already_made"));
							return "/membership/register/premium/billing.jsp";
						} catch (final DataException e) {
							WebUtil
									.log ("Transaction Failed! Exception thrown: "
											+ e
													.getClass ()
													.getCanonicalName ());
							err.put ("payment", e.getComplaint ());
							return "/membership/register/premium/billing.jsp";
						} catch (final Exception e) {
							WebUtil
									.log ("Transaction Failed! Exception thrown: "
											+ e
													.getClass ()
													.getCanonicalName ());
							AppiusClaudiusCaecus.reportBug (e);
							err.put ("ccbad", LibMisc
									.getText ("cc_invalid"));
							return "/membership/register/premium/billing.jsp";
						}

					} catch (final NotFoundException e) {
						err.put ("", LibMisc.getText ("retry_payment"));
						return "/membership/register/premium/billing.jsp";
					}
					if (null != payment) {
						WebUtil.log ("Transaction Completed!"
								+ "\n    Result Reason:        "
								+ payment.getResultReason ()
								+ "\n    Sequence:             "
								+ payment.getSequence ()
								+ "\n    Stamp:                "
								+ payment.getStamp ()
								+ "\n    Transaction Code:     "
								+ payment.getGatewayTransactionCode ()
								+ "\n    Enrolment Expiration: "
								+ payment.getUserEnrolment ()
										.getExpires ().toString ());
					} else {
						AppiusClaudiusCaecus
								.reportBug ("Transaction finished with a null payment");
					}

					if (null != payment) {
						if (payment.isSuccess ()) {
							WebUtil
									.log ("Transaction successful!  Checking for promotions.");
							WebUtil
									.approveAccount (memberBeingSubscribed);
							try {
								memberBeingSubscribed.setParent (Parent
										.getOrCreateByMail (email));
							} catch (final GameLogicException e1) {
								AppiusClaudiusCaecus
										.fatalBug (
												"Caught a GameLogicException in processCC",
												e1);
							} catch (final ForbiddenUserException e1) {
								AppiusClaudiusCaecus
										.fatalBug (
												"Caught a ForbiddenUserException in processCC",
												e1);
							}
							if (AppiusConfig
									.getConfigBoolOrFalse ("com.tootsville.coupons.plushToot")
									&& "us".equalsIgnoreCase (country)) {
								WebUtil
										.log ("Sending Code for free plush toot promotion.");

								final Coupon coupon = new Coupon ("("
										+ memberBeingSubscribed
												.getUserID ()
										+ ") "
										+ memberBeingSubscribed
												.getUserName ());
								coupon.sendCouponCode (pageVisitor);
								try {
									payment
											.addAnnotation (
													"com.tootsville.coupon.annotation",
													coupon
															.getCouponName ()
															+ ": "
															+ coupon
																	.getCouponCode ());
								} catch (final AlreadyUsedException e) {
									AppiusClaudiusCaecus
											.reportBug (
													"Coupon Code annotation already used",
													e);
								}
							}
							WebUtil.log ("Redirection User ID#"
									+ memberBeingSubscribed
											.getUserID ()
									+ " to the thankyou page.");
							return "/membership/register/thankyou/?who=paid";
						}
						WebUtil
								.log ("Transaction was not successful.  Collecting result data.");
						if (null != payment.getResultReason ()
								&& !"".equals (payment
										.getResultReason ())) {
							WebUtil
									.log ("Result Reason for failed transaction: "
											+ payment
													.getResultReason ());
							err.put ("transactFail", payment
									.getResultReason ());
						} else {
							err.put ("transactFail", LibMisc
									.getText ("unexpected"));
							AppiusClaudiusCaecus
									.reportBug ("Transaction completed and returned a <null> or empty ResultReason.");
						}
					}

				} else {
					err.put ("username", LibMisc
							.getText ("login_invalid"));
					return "/membership/register/premium/billing.jsp";
				}
			} else {
				err.put ("username", LibMisc.getText ("login_invalid"));
				return "/membership/register/premium/billing.jsp?";
			}
		} else {
			if (null == request.getParameter ("ccType")
					|| request.getParameter ("ccType").equals ("")) {
				err.put ("ccType", Messages
						.blank_field ("Credit Card Type select"));
			} else {
				ccType = request.getParameter ("ccType");
				storeValues.put ("ccType", ccType);
			}
			if (null == request.getParameter ("ccNum")
					|| request.getParameter ("ccNum").equals ("")) {
				err.put ("ccNum", Messages
						.blank_field ("Credit Card Number"));
			}
			if (null == request.getParameter ("ccExpMonth")
					|| request.getParameter ("ccExpMonth").equals ("")) {
				err.put ("ccExpMonth", Messages
						.blank_field ("Credit Card Expiration Month"));
			} else {
				ccExpMonth = request.getParameter ("ccExpMonth");
				storeValues.put ("ccExpMonth", ccExpMonth);
			}
			if (null == request.getParameter ("ccExpYear")
					|| request.getParameter ("ccExpYear").equals ("")) {
				err.put ("ccExpYear", Messages
						.blank_field ("Credit Card Expiration Year"));
			} else {
				ccExpYear = request.getParameter ("ccExpYear");
				storeValues.put ("ccExpYear", ccExpYear);
			}

			if (null == request.getParameter ("ccv")
					|| request.getParameter ("ccv").equals ("")) {
				err.put ("ccv", Messages.blank_field ("CCV"));
			}

			if (null == request.getParameter ("firstName")
					|| request.getParameter ("firstName").equals ("")) {
				err.put ("firstName", Messages
						.blank_field ("first name"));
			} else {
				firstName = request.getParameter ("firstName");
				storeValues.put ("firstName", firstName);
			}

			if (null == request.getParameter ("lastName")
					|| request.getParameter ("lastName").equals ("")) {
				err
						.put ("lastName", Messages
								.blank_field ("last name"));
			} else {
				lastName = request.getParameter ("lastName");
				storeValues.put ("lastName", lastName);
			}

			if (null == request.getParameter ("email")
					|| request.getParameter ("email").equals ("")) {
				err.put ("email", Messages.blank_field ("e-mail"));
			} else {
				email = request.getParameter ("email");
				storeValues.put ("email", email);
			}

			if (null == request.getParameter ("country")
					|| request.getParameter ("country").equals ("")) {
				err.put ("country", Messages.blank_field ("country"));
			} else {
				country = request.getParameter ("country");
				storeValues.put ("country", country);
				if (country.equals ("eu")) {
					country = request.getParameter ("eu_country")
							.substring (1);
					WebUtil.log ("Eu checkout");
					storeValues.put ("country", "." + country);
				}
			}
			if (null == request.getParameter ("address")
					|| request.getParameter ("country").equals ("")) {
				err.put ("address", Messages.blank_field ("address"));
			} else {
				address = request.getParameter ("address");
				storeValues.put ("address", address);
			}

			if (null == request.getParameter ("zip")
					|| request.getParameter ("country").equals ("")) {
				err.put ("zip", Messages.blank_field ("zip code"));
			} else {
				zip = request.getParameter ("zip");
				storeValues.put ("zip", zip);
			}
			if (null != request.getParameter ("phoneNumber")
					&& !request.getParameter ("phoneNumber")
							.equals ("")) {
				phoneNumber = request.getParameter ("phoneNumber");
				storeValues.put ("phoneNumber", phoneNumber);
			}
			if (null != request.getParameter ("state")
					&& !request.getParameter ("state").equals ("")) {
				state = request.getParameter ("state");
				storeValues.put ("state", state);
			}
			if (null != request.getParameter ("locality")
					&& !request.getParameter ("locality").equals ("")) {
				locality = request.getParameter ("locality");
				storeValues.put ("state", locality);
			}
			if (null != request.getParameter ("province")
					&& !request.getParameter ("province").equals ("")) {
				province = request.getParameter ("province");
				storeValues.put ("province", province);
			}
			if (null != request.getParameter ("city")
					&& !request.getParameter ("city").equals ("")) {
				city = request.getParameter ("city");
				storeValues.put ("city", city);
			}

			session.setAttribute ("storeValues", storeValues);
		}
		return "/membership/register/premium/billing.jsp";
	}

	/**
	 * Verifies POST data to ensure ... WRITEME
	 * 
	 * @param request WRITEME
	 * @throws DataException WRITEME
	 * @throws UnsupportedEncodingException WRITEME
	 */
	@SuppressWarnings ("unchecked")
	public static void renewSubscription (final ServletRequest request)
			throws DataException, UnsupportedEncodingException {
		if (null == request.getParameter ("x_subscription_id")
				|| null == request
						.getParameter ("x_subscription_paynum"))
			throw new DataException (
					"HTTP Post does not contain required values to be verified as a subscription transaction");

		// System.out.println (URLDecoder.decode (
		// request.getParameter (
		// "x_amount")
		// .getClass ().getCanonicalName (), "UTF-8"));
		final BigDecimal paid = new BigDecimal (URLDecoder.decode (
				request.getParameter ("x_amount"), "UTF-8"));
		final BigDecimal transID = new BigDecimal (URLDecoder.decode (
				request.getParameter ("x_trans_id"), "UTF-8"));
		final String md5hash = URLDecoder.decode (request
				.getParameter ("x_MD5_Hash"), "UTF-8");
		final String resultReason = URLDecoder.decode (request
				.getParameter ("x_response_reason_text"), "UTF-8");
		final boolean testMode = "true".equals (URLDecoder.decode (
				request.getParameter ("x_test_request"), "UTF-8"));
		final String invoiceID = URLDecoder.decode (request
				.getParameter ("x_invoice_num"), "UTF-8");
		final String [] invoice = invoiceID.split (new String (
				new char [] { '-' }));
		final String payer = URLDecoder.decode (request
				.getParameter ("x_first_name"), "UTF-8")
				+ " "
				+ URLDecoder.decode (request
						.getParameter ("x_last_name"), "UTF-8");
		String orderSource = "";
		String orderCode = "";
		int sequence = 0;
		try {
			orderSource = invoice [0];
			orderCode = invoice [1];
			sequence = Integer.parseInt (URLDecoder.decode (request
					.getParameter ("x_subscription_paynum"), "UTF-8"));
		} catch (final IndexOutOfBoundsException e) {
			AppiusClaudiusCaecus.reportBug (
					"Invoice ID does not contain order source or order code: "
							+ invoiceID, e);
			throw new DataException (
					"HTTP Post does not contain required values to be verified as a subscription transaction");
		} catch (final NumberFormatException e) {
			AppiusClaudiusCaecus
					.reportBug (
							"Payment Number is not abled to be parsed to int: "
									+ request
											.getParameter ("x_subscription_paynum"),
							e);
			throw new DataException (
					"HTTP Post does not contain required values to be verified as a subscription transaction");
		}

		UserEnrolment subscription = null;
		Payment payment = null;
		try {
			subscription = UserEnrolment.getBySourceAndCode (
					orderSource, orderCode);
			payment = new Payment (subscription);
		} catch (final Exception e) {
			AppiusClaudiusCaecus.fatalBug (e);
		}

		if (null == payment || null == subscription)
			throw new DataException (
					"HTTP Post does not contain required values to be verified as a subscription transaction");

		try {
			payment.setGatewayTransactionCode (transID);
			payment.setTest (testMode);
			payment.addAnnotation ("net.authorize.arb.subscriptionID",
					request.getParameter ("x_subscription_id"));
			payment.addAnnotation ("net.authorize.arb.reason.code",
					request.getParameter ("x_response_reason_code"));
			payment.addAnnotation ("net.authorize.arb.reason.text",
					request.getParameter ("x_response_reason_text"));
			payment.addAnnotation ("com.tootsville.user.id", request
					.getParameter ("x_cust_id"));
			payment.addAnnotation ("net.authorize.arb.type", request
					.getParameter ("x_type"));
			payment.addAnnotation ("net.authorize.arb.code", request
					.getParameter ("x_code"));
			payment.addAnnotation ("net.authorize.arb.description",
					request.getParameter ("x_description"));
		} catch (final AlreadyUsedException e) {
			AppiusClaudiusCaecus.reportBug ("Payment already made", e);
			throw new DataException (
					"HTTP Post does not contain required values to be verified as a subscription transaction");
		}

		final StringBuilder message = new StringBuilder ();
		message.append ("Servlet Request Parameters");
		final Map <Object, Object> names = request.getParameterMap ();
		for (final Entry entry : names.entrySet ()) {
			message.append ("\n\tName: ");
			message.append (entry.getKey ());
			message.append ("\n\tName: ");
			message.append (entry.getValue ());
			message.append ("\n\tName: ");
			message.append (entry.getValue ().getClass ()
					.getCanonicalName ());
		}
		System.out.println (message.toString ());

		try {
			AimTransaction.checkMd5Hash (md5hash, "", transID
					.toPlainString (), paid.toPlainString ());
			payment.setVerified (true);
		} catch (final AuthNetException e) {
			AppiusClaudiusCaecus
					.reportBug ("Possible attempt to bypass security!"
							+ "\n\n" + "I'm allowing this transaction "
							+ "to continue, and entering it "
							+ "into the database, but the MD5 "
							+ "checksum returned from the "
							+ "Authorize.Net servers "
							+ "*** DOES NOT VALIDATE. ***" + "\n\n"
							+ "This is likely to indicate an "
							+ "attempt to forge a response, "
							+ "possibly violating the "
							+ "integrity of customer data. " + "\n\n"
							+ "**********************************\n"
							+ "* THIS IS A VERY, VERY BIG DEAL. *\n"
							+ "**********************************\n", e);
			throw new DataException (
					"HTTP Post does not contain required values to be verified as a subscription transaction");
		}

		payment.setResultReason (resultReason);
		payment.setSequence (sequence);
		payment.setPrice (subscription.getEnrolment ().getPrice ());
		payment.setPayer (payer);
		payment.setPaymentFor ("ENROL");
		payment.setPaid (paid);
		final String responseCode = URLDecoder.decode (request
				.getParameter ("x_response_code"), "UTF-8");
		try {
			payment.setSuccess (1 == Integer.parseInt (responseCode));
		} catch (final NumberFormatException e) {
			AppiusClaudiusCaecus.reportBug (
					"ARB Response Code is not being sent as a number.  Response Code: "
							+ responseCode, e);
			payment.setSuccess (false);
		}
		payment.shredCredentials ();

		try {
			payment.close ();
		} catch (final SQLException e) {
			AppiusClaudiusCaecus.fatalBug (e);
		}

		if (!"auth".equalsIgnoreCase (orderSource)) {
			AppiusClaudiusCaecus
					.reportBug ("LEGACY AUTHORIZE.NET TRANSACTION DETAILS:\n"
							+ LibMisc.stringify (request
									.getParameterMap ()));
		}
	}

	/**
	 * WRITEME
	 * 
	 * @param searchParams WRITEME
	 * @return WRITEME
	 */
	public static Vector <Person> searchUsers (final String searchParams) {
		final Vector <Person> results = new Vector <Person> ();
		Toot u = null;
		Parent p = null;

		if (null == searchParams || "".equals (searchParams))
			return null;

		try {
			u = (Toot) User.getByID (Integer.parseInt (searchParams));
			if (null != u) {
				results.add (u);
			}
			u = null;
		} catch (final NumberFormatException e) {
			// do nothing
		}

		try {
			p = Parent.getByID (Integer.parseInt (searchParams));
			if (null != p) {
				results.add (p);
			}
			p = null;
		} catch (final NumberFormatException e) {
			// do nothing
		}

		{
			u = (Toot) User.getByLogin (searchParams);
			if (null != u) {
				results.add (u);
			}
			u = null;
		}

		{
			p = Parent.getByMail (searchParams);
			if (null != p) {
				results.add (p);
			}
			p = null;
		}

		{
			final AbstractUser [] users = User.getByMail (searchParams);
			if (null != users) {
				for (final AbstractUser user : users) {
					if (user instanceof Person) {
						results.add ((Person) user);
					}
				}
			}
		}

		return results;
	}

	/**
	 * set AppiusConfig to connect by itself.
	 */
	public static void useAppiusDB () {
		AppiusConfig.setConfig ("org.starhope.appius.jdbc.useTomcat",
				"false");
		AppiusConfig.configChanged ();
	}

	/**
	 * capture a connection from Tomcat for Tootsville and Store and set
	 * AppiusConfig to use it instead of connecting by itself. WRITEME
	 */
	public static void useTomcatDB () {
		AppiusConfig.setConfig ("org.starhope.appius.jdbc.useTomcat",
				"true");
		AppiusConfig.configChanged ();
	}

	/**
	 * WRITEME
	 * 
	 * @param userID WRITEME
	 * @param password WRITEME
	 * @return WRITEME
	 */
	public static Parent verifyParentLogin (final String userID,
			final String password) {
		Parent parent;
		if (null == userID || null == password)
			return null;
		try {
			parent = Parent.getByID (Integer.parseInt (userID));
		} catch (final NumberFormatException e) {
			return null;
		}
		if (null == parent) {
			WebUtil.log ("Parent: " + userID
					+ "  Failed attempt to retrieve a parent account.");
		}
		return parent;
	}

	/**
	 * WRITEME
	 * 
	 * @param userID WRITEME
	 * @param password WRITEME
	 * @return WRITEME
	 */
	public static Toot verifyUserLogin (final String userID,
			final String password) {
		Toot user;
		if (null == userID || null == password)
			return null;
		try {
			user = (Toot) User.getByID (Integer.parseInt (userID));
		} catch (final NumberFormatException e) {
			return null;
		}
		if (null == user) {
			WebUtil.log ("User: " + userID
					+ "  Failed attempt to retrieve a parent account.");
		}
		return user;
	}

}
