package com.tootsville.joshua.client.details;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.tootsville.gwt.joshua.client.Joshua;
import com.tootsville.gwt.joshua.client.service.JoshuaServiceAsync;
import com.tootsville.gwt.joshua.client.util.Enrolment;
import com.tootsville.gwt.joshua.client.util.Payment;
import com.tootsville.gwt.joshua.client.util.User;

/**
 * 
 * @author Tim
 * 
 */
public class UserDetails extends HorizontalPanel {

	/**
	 * WRITEME:
	 */
	VerticalPanel accountDetailsPanel = new VerticalPanel ();

	/**
	 * WRITEME:
	 */
	HorizontalPanel actionsPanel = new HorizontalPanel ();

	/**
	 * WRITEME:
	 */
	Button approveParent = new Button ("Set as Approved");

	/**
	 * WRITEME:
	 */
	Button banOrUnbanUser = new Button ();

	/**
	 * WRITEME:
	 */
	VerticalPanel buddyPanel = new VerticalPanel ();

	/**
	 * WRITEME:
	 */
	Button cancelOrActivateUser = new Button ();

	/**
	 * WRITEME:
	 */
	Button editAccount = new Button ("Edit Account");

	/**
	 * WRITEME:
	 */
	Button giftTime = new Button ("Gift V.I.T. Time");

	/**
	 * WRITEME:
	 */
	Button givePeanuts = new Button ("Give Peanuts");

	/**
	 * WRITEME:
	 */
	ClickHandler goToUser = new ClickHandler () {
		@Override
		public void onClick (final ClickEvent event) {
			final String userID = ((Hyperlink) event.getSource ())
					.getText ();
			main.search (userID);
		}
	};

	/**
	 * WRITEME:
	 */
	VerticalPanel leftPanel = new VerticalPanel ();

	/**
	 * WRITEME:
	 */
	Label mail = new Label ("");

	/**
	 * WRITEME:
	 */
	Joshua main;

	/**
	 * WRITEME:
	 */
	HorizontalPanel miscDetailsPanel = new HorizontalPanel ();

	/**
	 * WRITEME:
	 */
	Label password = new Label ("");

	/**
	 * WRITEME:
	 */
	VerticalPanel paymentRecordPanel = new VerticalPanel ();

	/**
	 * WRITEME:
	 */
	Label peanuts = new Label ("");

	/**
	 * WRITEME:
	 */
	Button remindPassword = new Button ("Remind Password");

	/**
	 * WRITEME:
	 */
	Button resetPassword = new Button ("Reset Password");

	/**
	 * WRITEME:
	 */
	VerticalPanel rightPanel = new VerticalPanel ();

	/**
	 * WRITEME:
	 */
	Button setMail = new Button ("Set Mail");

	/**
	 * WRITEME:
	 */
	Button setParent = new Button ("Set Parent");

	/**
	 * WRITEME:
	 */
	User user;

	/**
	 * WRITEME:
	 */
	Button viewParent = new Button ("View Parent");

	/**
	 * WRITEME: Document this field. theys Dec 11, 2009
	 * 
	 */
	public UserDetails () {
		// Do nothing
	}

	/**
	 * 
	 * @param main1
	 * @param user1
	 */
	public UserDetails (final Joshua main1, final User user1) {
		main = main1;
		user = user1;

		buildAccountDetailsPanel ();
		buildActionsPanel ();
		buildBuddyPanel ();
		buildMiscPanel ();
		buildPaymentRecordPanel ();

		leftPanel.add (accountDetailsPanel);
		leftPanel.add (actionsPanel);
		leftPanel.add (buddyPanel);
		leftPanel.setStyleName ("leftDetails");

		rightPanel.add (miscDetailsPanel);
		rightPanel.add (paymentRecordPanel);
		rightPanel.setStyleName ("rightDetails");

		add (leftPanel);
		add (rightPanel);

		Window.setStatus ("Done");
	}

	/**
	 * WRITEME:
	 */
	protected void approveParent () {

		final JoshuaServiceAsync service = Joshua.initService ();

		final AsyncCallback <Void> callback = new AsyncCallback <Void> () {
			@Override
			public void onFailure (final Throwable caught) {
				Window
						.alert ("Failed to approve account!  Please try again.");
			}

			@Override
			public void onSuccess (final Void result) {
				main.search (String.valueOf (user.getUserID ()));
			}
		};
		service.approve (user.getUserID (), callback);
	}

	/**
	 * WRITEME:
	 */
	protected void banOrUnbanUser () {

		final String reason = Window.prompt (
				"Please enter a reason for banning.", "");

		if (null == reason)
			return;

		final JoshuaServiceAsync service = Joshua.initService ();

		final AsyncCallback <Void> callback = new AsyncCallback <Void> () {
			@Override
			public void onFailure (final Throwable caught) {
				Window.alert (caught.getMessage ());
			}

			@Override
			public void onSuccess (final Void result) {
				main.search (String.valueOf (user.getUserID ()));
			}
		};
		service.banOrUnban (user.getUserID (), main.getLifeguard ()
				.getUserID (), reason, callback);
	}

	/**
	 * WRITEME:
	 */
	private void buildAccountDetailsPanel () {
		Window.setStatus ("Building account details");

		accountDetailsPanel.add (new Label ("User Name: "
				+ user.getUserName ()));
		accountDetailsPanel.add (new Label ("User ID: "
				+ user.getUserID ()));
		accountDetailsPanel.add (new Label ("eMail:    "
				+ user.getMail ()));
		accountDetailsPanel.add (new Label ("Birth Date: "
				+ user.getBirthDate ()));
		accountDetailsPanel.add (new Label ("Registration Date: "
				+ user.getRegisteredAt ()));
		if (0 == user.getStaffLevel ())
			accountDetailsPanel.add (new Label ("Password:    "
					+ user.getPassword ()));

		final Label paidOrFree = new Label ("");
		paidOrFree.setStyleName ("paidOrFree");
		if (user.isPaid ()) {
			paidOrFree.addStyleName ("paid");
			paidOrFree.setText ("V.I.T. User");
		} else
			paidOrFree.setText ("Free User");
		accountDetailsPanel.add (paidOrFree);

		accountDetailsPanel.setStyleName ("detailsBox");
	}

	/**
	 * WRITEME:
	 */
	private void buildActionsPanel () {

		viewParent.addClickHandler (new ClickHandler () {
			@Override
			public void onClick (final ClickEvent event) {
				viewParent ();
			}
		});

		editAccount.addClickHandler (new ClickHandler () {
			@Override
			public void onClick (final ClickEvent event) {
				editAccount ();
			}
		});

		resetPassword.addClickHandler (new ClickHandler () {
			@Override
			public void onClick (final ClickEvent event) {
				resetPassword ();
			}
		});

		remindPassword.addClickHandler (new ClickHandler () {
			@Override
			public void onClick (final ClickEvent event) {
				remindPassword ();
			}
		});

		approveParent.addClickHandler (new ClickHandler () {
			@Override
			public void onClick (final ClickEvent event) {
				approveParent ();
			}
		});

		setParent.addClickHandler (new ClickHandler () {
			@Override
			public void onClick (final ClickEvent event) {
				setParent ();
			}
		});

		setMail.addClickHandler (new ClickHandler () {
			@Override
			public void onClick (final ClickEvent event) {
				setMail ();
			}
		});

		givePeanuts.addClickHandler (new ClickHandler () {
			@Override
			public void onClick (final ClickEvent event) {
				givePeanuts ();
			}
		});

		giftTime.addClickHandler (new ClickHandler () {
			@Override
			public void onClick (final ClickEvent event) {
				giftTime ();
			}
		});

		banOrUnbanUser.addClickHandler (new ClickHandler () {
			@Override
			public void onClick (final ClickEvent event) {
				banOrUnbanUser ();
			}
		});

		cancelOrActivateUser.addClickHandler (new ClickHandler () {
			@Override
			public void onClick (final ClickEvent event) {
				cancelOrActivateUser ();
			}
		});

		if ("Banned".equals (user.getStatus ()))
			banOrUnbanUser.setText ("Unban " + user.getUserName ());
		else
			banOrUnbanUser.setText ("Ban " + user.getUserName ());

		if ("Canceled".equals (user.getStatus ()))
			cancelOrActivateUser.setText ("Activate Account");
		else
			cancelOrActivateUser.setText ("Cancel Account");

		final VerticalPanel leftSide = new VerticalPanel ();
		final VerticalPanel rightSide = new VerticalPanel ();
		leftSide.add (viewParent);
		rightSide.add (editAccount);
		leftSide.add (approveParent);
		if ("Kid".equals (user.getAgeGroup ()))
			rightSide.add (setParent);
		else
			rightSide.add (setMail);
		leftSide.add (resetPassword);
		rightSide.add (remindPassword);
		leftSide.add (givePeanuts);
		rightSide.add (giftTime);
		leftSide.add (cancelOrActivateUser);
		rightSide.add (banOrUnbanUser);
		actionsPanel.add (leftSide);
		actionsPanel.add (rightSide);
		actionsPanel.setStyleName ("detailsBox");
	}

	/**
	 * WRITEME:
	 */
	private void buildBuddyPanel () {
		Window.setStatus ("Building buddy list");
		final FlexTable buddyListTable = new FlexTable ();
		int i = 0;
		buddyListTable.setText (i++ , 0, "Buddy List:");
		for (final String buddy : user.getBuddyList ()) {
			final Hyperlink buddyLink = new Hyperlink (buddy, "");
			buddyLink.addClickHandler (goToUser);
			buddyListTable.setWidget (i++ , 0, buddyLink);
		}
		buddyListTable.setStyleName ("buddyListTable");
		buddyListTable.setCellPadding (0);
		buddyListTable.setCellSpacing (0);
		buddyListTable.setHeight ("auto");

		buddyPanel.add (buddyListTable);
		buddyPanel.setStyleName ("detailsBox buddyListTable");
	}

	/**
	 * WRITEME:
	 */
	private void buildMiscPanel () {
		Window.setStatus ("Building user properties");
		final FlexTable miscTable = new FlexTable ();

		try {
			miscTable.setText (0, 0, "Display Name: ");
			miscTable.setWidget (0, 1, new Label (user
					.getDisplayName ()));
			miscTable.setText (0, 2, "Staff: ");
			miscTable.setWidget (0, 3, new Label (user
					.getStaffLevelTitle ()));
			miscTable.setText (0, 4, "Account Status: ");
			miscTable.setWidget (0, 5, new Label (user.getStatus ()));

			miscTable.setText (1, 0, "Avatar: ");
			miscTable.setWidget (1, 1, new Label (""
					+ user.getBasic8 ()));
			miscTable.setText (1, 2, "Approved On: ");
			miscTable.setWidget (1, 3, new Label (user
					.getApprovedDate ()));
			miscTable.setText (1, 4, "Peanuts: ");
			peanuts.setText (user.getNuts ());
			miscTable.setWidget (1, 5, peanuts);

			miscTable.setText (2, 0, "Age Group: ");
			miscTable.setWidget (2, 1, new Label (user.getAgeGroup ()));
			miscTable.setText (2, 2, "Last Active: ");
			miscTable.setWidget (2, 3,
					new Label (user.getLastActive ()));
			miscTable.setText (2, 4, "Password Q: ");
			miscTable.setWidget (2, 5, new Label (user.getQuestion ()));

			miscTable.setText (3, 0, "Referer: ");
			miscTable.setWidget (3, 1, new Label (user.getReferer ()));
			miscTable.setText (3, 2, "Last Zone: ");
			miscTable.setWidget (3, 3, new Label (user.getLastZone ()));
			miscTable.setText (3, 4, "Password A: ");
			miscTable.setWidget (3, 5, new Label (user.getAnswer ()));
			miscTable.setCellPadding (5);
			miscTable.setCellSpacing (0);
			miscTable.setWidth ("100%");
		} catch (final IndexOutOfBoundsException e) {
			GWT.log ("miscTable out of bounds", e);
		}

		for (int x = 0; x <= 3; x++ )
			for (int y = 1; y <= 5; y = y + 2)
				miscTable.getWidget (x, y).setStyleName ("whiteText");

		miscDetailsPanel.add (miscTable);
		miscDetailsPanel.setStyleName ("detailsBox");
	}

	/**
	 * WRITEME:
	 */
	private void buildPaymentRecordPanel () {
		Window.setStatus ("Building payment table");

		paymentRecordPanel.add (new Label (
				"Enrolments (Authorize.Net/Chase-It)"));
		paymentRecordPanel.add (new HTML ("<br />"));

		for (final Enrolment enrol : user.getUserEnrolments ()) {
			final FlexTable enrolmentBox = new FlexTable ();
			enrolmentBox.setStyleName ("enrolmentBox");
			try {
				enrolmentBox.setText (0, 0, "Enrolment Details");

				enrolmentBox.setText (1, 0, "Code: ");
				enrolmentBox.setWidget (1, 1, new Label (enrol
						.getOrder_source ()
						+ "-" + enrol.getOrder_code ()));
				enrolmentBox.setText (1, 2, "Enrolment Type:  ");
				enrolmentBox.setWidget (1, 3, new Label (enrol
						.getProduct_title ()));

				enrolmentBox.setText (2, 0, "Start Date:  ");
				enrolmentBox.setWidget (2, 1, new Label (enrol
						.getBegins_at ()));
				enrolmentBox.setText (2, 2, "End Date:  ");
				enrolmentBox.setWidget (2, 3, new Label (enrol
						.getExpires_at ()));

				enrolmentBox.setText (3, 0, "Payment Details");

				if (enrol.hasPayment ()) {
					enrolmentBox.setText (4, 0, "Timestamp: ");
					final Payment payment = enrol.getPayment ();
					enrolmentBox.setWidget (4, 1, new Label (payment
							.getStamp ()));
					enrolmentBox.setText (4, 2, "Payer:  ");
					enrolmentBox.setWidget (4, 3, new Label (payment
							.getPayer ()));

					enrolmentBox.setText (5, 0, "Result: ");
					enrolmentBox.setWidget (5, 1, new Label (payment
							.getResultReason ()));
					enrolmentBox.setText (5, 2, "For:  ");
					enrolmentBox.setWidget (5, 3, new Label (payment
							.getPaymentFor ()));

					for (final String annotation : payment
							.getAnnotations ()) {
						final int row = enrolmentBox.getRowCount ();
						enrolmentBox.insertRow (row);
						final Label annotationLabel = new Label (
								annotation);
						enrolmentBox.setWidget (row, 0, new Label (
								"Annotation:"));
						enrolmentBox
								.setWidget (row, 1, annotationLabel);
						enrolmentBox.getFlexCellFormatter ()
								.setColSpan (row, 2, 3);
					}
				} else
					enrolmentBox.setText (4, 0,
							"No payments found for this enrolment.");

				final int rows = enrolmentBox.getRowCount ();

				if (!enrol.isExpired ())
					for (int x = 0; x <= 1; x++ )
						for (int y = 1; y <= rows; y = y + 2)
							enrolmentBox.getWidget (x, y).setStyleName (
									"whiteText");
				else
					for (int x = 0; x <= 1; x++ )
						for (int y = 1; y <= rows; y = y + 2)
							enrolmentBox.getWidget (x, y).setStyleName (
									"redText");

			} catch (final IndexOutOfBoundsException e) {
				GWT.log ("enrolmentBox out of bounds", e);
			}

			paymentRecordPanel.add (enrolmentBox);
			paymentRecordPanel.add (new HTML ("<br /><br />"));
		}

		paymentRecordPanel.setHeight ("auto");
		paymentRecordPanel.setStyleName ("detailsBox");

	}

	/**
	 * WRITEME:
	 */
	protected void cancelOrActivateUser () {
		final JoshuaServiceAsync service = Joshua.initService ();

		final AsyncCallback <Void> callback = new AsyncCallback <Void> () {
			@Override
			public void onFailure (final Throwable caught) {
				Window.alert (caught.getMessage ());
			}

			@Override
			public void onSuccess (final Void result) {
				main.search (String.valueOf (user.getUserID ()));
			}
		};
		service.cancelUser (user.getUserID (), callback);
	}

	/**
	 * WRITEME:
	 */
	protected void editAccount () {
		Window.alert ("This feature is not supported yet!");
		// main.changePage (new CreateUser (main, user));
	}

	/**
	 * WRITEME:
	 */
	protected void giftTime () {
		int numOfMonths;
		do {
			final String promptMonths = Window
					.prompt (
							"Enter number of months to gift. You can also enter 'life'"
									+ " for a lifetime subscription or 'staff' for a staff account.",
							"1");
			if (null == promptMonths)
				return;
			try {
				numOfMonths = Integer.parseInt (promptMonths);
				if (1 > numOfMonths)
					Window
							.alert ("You cannot give zero or negative months!");
				else
					break;
			} catch (final NumberFormatException e) {
				if ("life".equals (promptMonths)) {
					numOfMonths = -1;
					break;
				} else if ("staff".equals (promptMonths)) {
					numOfMonths = -2;
					break;
				}
				Window
						.alert ("Please enter a numeric value or the word 'life'.");
			}
		} while (true);

		final JoshuaServiceAsync service = Joshua.initService ();

		final AsyncCallback <Void> callback = new AsyncCallback <Void> () {
			@Override
			public void onFailure (final Throwable caught) {
				Window
						.alert ("Failed to gift time!  Please try again.");
			}

			@Override
			public void onSuccess (final Void result) {
				main.search (String.valueOf (user.getUserID ()));
			}
		};
		service.giftTime (user.getUserID (), numOfMonths, callback);

	}

	/**
	 * WRITEME:
	 */
	protected void givePeanuts () {
		do {
			final String howMany = Window.prompt (
					"Enter an amount of peanuts to gift.", "2000");
			if (null == howMany)
				return;

			try {
				final long giveNuts = Integer.parseInt (howMany);

				final JoshuaServiceAsync service = Joshua
						.initService ();

				final AsyncCallback <String> callback = new AsyncCallback <String> () {
					@Override
					public void onFailure (final Throwable caught) {
						Window
								.alert ("Failed to give peanuts!  Please try again.");
					}

					@Override
					public void onSuccess (final String result) {
						peanuts.setText (result);
					}
				};
				service.givePeanuts (giveNuts, user.getUserID (),
						callback);

				break;
			} catch (final NumberFormatException e) {
				Window
						.alert ("You must enter a numeric value less than 2,147,483,647!");
			}
		} while (true);

	}

	/**
	 * WRITEME:
	 */
	protected void remindPassword () {
		final JoshuaServiceAsync service = Joshua.initService ();

		// Set up the callback object.
		final AsyncCallback <Void> callback = new AsyncCallback <Void> () {
			@Override
			public void onFailure (final Throwable caught) {
				Window
						.alert ("Unable to send user's password, please retry your last action.");
			}

			@Override
			public void onSuccess (final Void result) {
				Window
						.alert ("The user's password has been e-mailed to them.");
			}
		};

		// Make the call to the search service.
		service.remindPassword (user.getUserID (), true, callback);
	}

	/**
	 * WRITEME:
	 */
	protected void resetPassword () {
		Window.alert ("This feature is not supported yet!");
	}

	/**
	 * WRITEME:
	 */
	protected void setMail () {
		final String newMail = Window.prompt (
				"Please enter an e-mail address.", "");

		if (null == newMail)
			return;

		final JoshuaServiceAsync service = Joshua.initService ();

		// Set up the callback object.
		final AsyncCallback <Void> callback = new AsyncCallback <Void> () {
			@Override
			public void onFailure (final Throwable caught) {
				Window.alert (caught.getMessage ());
			}

			@Override
			public void onSuccess (final Void result) {
				Window.alert ("Mail has been set.");
				main.search (String.valueOf (user.getUserID ()));
			}
		};

		// Make the call to the search service.
		service.setMail (user.getUserID (), newMail, callback);

	}

	/**
	 * WRITEME:
	 */
	protected void setParent () {
		final String newMail = Window.prompt (
				"Please enter an e-mail address.", "");

		if (null == newMail)
			return;

		final JoshuaServiceAsync service = Joshua.initService ();

		// Set up the callback object.
		final AsyncCallback <Void> callback = new AsyncCallback <Void> () {
			@Override
			public void onFailure (final Throwable caught) {
				Window.alert (caught.getMessage ());
			}

			@Override
			public void onSuccess (final Void result) {
				Window.alert ("Parent has been set.");
				main.search (String.valueOf (user.getUserID ()));
			}
		};

		// Make the call to the search service.
		service.setParent (user.getUserID (), newMail, callback);
	}

	/**
	 * WRITEME:
	 */
	protected void viewParent () {
		main.search (user.getMail ());
	}
}
