/**
 * 
 */
package com.tootsville.tootsbook.client.panel.wallobjects;

import java.util.Iterator;
import java.util.LinkedList;

import org.gwtwidgets.client.style.Color;
import org.gwtwidgets.client.wrap.Callback;
import org.gwtwidgets.client.wrap.Effect;
import org.gwtwidgets.client.wrap.EffectOption;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
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.Button;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.tootsville.tootsbook.client.BookServiceAsync;
import com.tootsville.tootsbook.client.TootsBook;
import com.tootsville.tootsbook.client.exception.PrivilegeRequiredException;
import com.tootsville.tootsbook.client.panel.ErrorMessage;
import com.tootsville.tootsbook.client.util.DisplayText;
import com.tootsville.tootsbook.client.util.Post;
import com.tootsville.tootsbook.client.util.TimeStampLabel;

/**
 * WRITEME: Document this type. twheys@gmail.com Jan 19, 2010
 * 
 * @author <a href="mailto:twheys@gmail.com@resinteractive.com">Tim
 *         Heys</a>
 * 
 */
public class CommentPanel extends VerticalPanel {

	/**
	 * 
	 */
	protected final TextArea addCommentField;

	/**
	 * 
	 */
	private final Anchor addCommentLink = new Anchor ("",
	"javascript:;");

	/**
	 * 
	 */
	private final BlurHandler comemntBlur = new BlurHandler () {
		/**
		 * @see com.google.gwt.event.dom.client.BlurHandler#onBlur(com.google.gwt.event.dom.client.BlurEvent)
		 */
		@Override
		public void onBlur (final BlurEvent event) {
			if ("".equals (addCommentField.getText ())) {
				addCommentField
				.setText (DisplayText.COMMENT_FIELD_DEFAULT_TEXT);
				addCommentField.addStyleName ("greyed-text");
			}
		}
	};

	/**
	 * 
	 */
	private final FocusHandler commentFocus = new FocusHandler () {
		/**
		 * @see com.google.gwt.event.dom.client.FocusHandler#onFocus(com.google.gwt.event.dom.client.FocusEvent)
		 */
		@Override
		public void onFocus (final FocusEvent event) {
			if (DisplayText.COMMENT_FIELD_DEFAULT_TEXT
					.equals (addCommentField.getText ())) {
				addCommentField.setText ("");
				addCommentField.removeStyleName ("greyed-text");
			}
		}
	};

	/**
	 * 
	 */
	private boolean isCommenting = false;

	/**
	 * 
	 */
	private final Post postParent;

	/**
	 * 
	 */
	private final LinkedList <Post> posts = new LinkedList <Post> ();

	/**
	 * 
	 */
	private final Anchor showAllComments = new Anchor (
			"Show 0 more posts", "javascript:;");

	/**
	 * <pre>
	 * twheys@gmail.com Jan 18, 2010
	 * </pre>
	 * 
	 * A CommentPanel WRITEME...
	 * 
	 * @param parent WRITEME
	 */
	public CommentPanel (final Post parent) {
		postParent = parent;

		final TimeStampLabel postTimeStamp = new TimeStampLabel (
				parent.getTimeStamp ());
		postTimeStamp.setStyleName ("post-timestamp add-comment-link");

		addCommentLink.setStyleName ("add-comment-link");
		if (TootsBook.isLoggedIn ()) {
			addCommentLink.setText (DisplayText.ADD_COMMENT);
			addCommentLink.addClickHandler (new ClickHandler () {
				@Override
				public void onClick (final ClickEvent event) {
					CommentPanel.this.setToAddComment ();
				}
			});
		} else {
			addCommentLink.setText (DisplayText.LOG_IN_FOR_COMMENT);
			addCommentLink.addClickHandler (new ClickHandler () {
				@Override
				public void onClick (final ClickEvent event) {
					History.newItem (TootsBook.PAGE_URL_LOGIN);
				}
			});
		}

		final HorizontalPanel commentPanelSubText = new HorizontalPanel ();
		commentPanelSubText.setWidth ("100%");
		commentPanelSubText.add (postTimeStamp);
		commentPanelSubText.add (addCommentLink);
		add (commentPanelSubText);

		showAllComments.setStyleName ("show-comment-link");
		showAllComments.addClickHandler (new ClickHandler () {
			@Override
			public void onClick (final ClickEvent event) {
				showAllComments ();
			}
		});
		showAllComments.setText (hiddenPostsText (0));
		showAllComments.setVisible (false);
		add (showAllComments);

		addCommentField = new TextArea ();
		addCommentField
		.setText (DisplayText.COMMENT_FIELD_DEFAULT_TEXT);
		addCommentField.getElement ().setAttribute ("wrap", "hard");
		addCommentField.getElement ().setAttribute ("maxlength", "100");
		addCommentField.setStyleName ("text-area greyed-text");
		addCommentField.addFocusHandler (commentFocus);
		addCommentField.addBlurHandler (comemntBlur);

		setSpacing (0);
	}

	/**
	 * 
	 * <pre>
	 * twheys@gmail.com Jan 13, 2010
	 * </pre>
	 * 
	 * TO addComment WRITEME...
	 * 
	 * @param post WRITEME
	 * @param hideOldPosts WRITEME
	 */
	public void addComment (final Post post, final boolean hideOldPosts) {
		posts.add (post);
		// final HorizontalPanel commentBox = getCommentBox(post);
		final Comment commentBox = new Comment (post);
		// commentBoxContainer.add(commentBox);
		post.setContainingPanel (commentBox);

		if ( !hideOldPosts) {
			commentBox.getElement ().setAttribute ("style",
			"display: none; z-index: 50;");
			insert (commentBox, getWidgetCount ());
			GWT.log ("blinding down", null);

			Effect.appear (commentBox, new EffectOption [] {
					new EffectOption ("duration", "1.0"),
					new EffectOption ("delay", "0.4") });

			// final BoxOutCenter boxFX = new BoxOutCenter (
			// commentBox.getElement ());
			// boxFX.setTransitionType (new BounceTransitionPhysics ());
			// boxFX.setDuration (5.0);
			// boxFX.setIELayoutDefinition (
			// boxFX.getIELayoutDefinition (), "1");
			// boxFX.play ();

			// boxFX.getEffectPanel ().setSize ("300px", "auto");
		} else {
			insert (commentBox, getWidgetCount ());
		}

		if (hideOldPosts && TootsBook.MAX_COMMENTS <= posts.size ()) {
			final int hiddenPosts = posts.size ()
			- TootsBook.MAX_COMMENTS + 1;
			final int index = hiddenPosts + 1;
			GWT.log ("Hiding post at Index " + index, null);
			getWidget (index).setVisible (false);
			showAllComments.setText (hiddenPostsText (hiddenPosts));
			showAllComments.setVisible (true);
		}
	}

	/**
	 * <pre>
	 * twheys@gmail.com Jan 13, 2010
	 * </pre>
	 * 
	 * TO getAddCommentBox WRITEME...
	 * 
	 * @return WRITEME
	 * @throws PrivilegeRequiredException WRITEME
	 */
	public HorizontalPanel getAddCommentBox ()
	throws PrivilegeRequiredException {
		if ( !TootsBook.isLoggedIn ())
			throw new PrivilegeRequiredException (
					DisplayText.LOGGED_IN_FOR_COMMENTS);
		final HorizontalPanel addCommentBox = new HorizontalPanel ();
		final Button submit = new Button (" ", new ClickHandler () {
			/**
			 * (non-Javadoc)
			 * 
			 * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent)
			 */
			@Override
			public void onClick (final ClickEvent event) {
				submitText ();
			}
		});
		final Button cancel = new Button ("  ", new ClickHandler () {
			/**
			 * (non-Javadoc)
			 * 
			 * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent)
			 */
			@Override
			public void onClick (final ClickEvent event) {
				addCommentField
				.setText (DisplayText.COMMENT_FIELD_DEFAULT_TEXT);
				addCommentField.addStyleName ("greyed-text");
				CommentPanel.this.removeAddCommentBox ();
			}
		});

		final VerticalPanel submitBox = new VerticalPanel ();
		submit.setStyleName ("confirm-button-small");
		submit.getElement ().setId ("submit-button-small");
		cancel.setStyleName ("confirm-button-small");
		cancel.getElement ().setId ("cancel-button-small");
		submit.setTitle ("SUBMIT");
		cancel.setTitle ("CANCEL");
		submitBox.add (cancel);
		submitBox.add (submit);
		submitBox.setSpacing (2);

		addCommentField.setVisibleLines (2);
		addCommentField.getSelectionLength ();
		addCommentField.addKeyPressHandler (new KeyPressHandler () {
			/**
			 * @see com.google.gwt.event.dom.client.KeyPressHandler#onKeyPress(com.google.gwt.event.dom.client.KeyPressEvent)
			 */
			@Override
			public void onKeyPress (final KeyPressEvent event) {
				if ( !TootsBook.filterKeys (
						event.getCharCode (),
						(addCommentField.getText ().length () >= TootsBook.MAX_CHAR_LENGTH))) {
					addCommentField.cancelKey ();
					return;
				}
				if (// 15 <= addCommentField.getVisibleLines () &&
						addCommentField.getText ().length () / 30 >= addCommentField
						.getVisibleLines ()) {
					GWT.log ("Adding a row", null);
					addCommentField.setVisibleLines (addCommentField
							.getVisibleLines () + 1);
				}
			}
		});
		final FocusPanel icon = TootsBook.getUser ().getIcon ();

		addCommentBox
		.setVerticalAlignment (HasVerticalAlignment.ALIGN_MIDDLE);
		addCommentBox.add (icon);
		addCommentBox.add (addCommentField);
		addCommentBox.add (submitBox);
		addCommentBox.setWidth ("100%");
		addCommentBox.setBorderWidth (0);
		addCommentBox.setCellWidth (addCommentField, "100%");

		return addCommentBox;
	}

	/**
	 * Centralization of the string for displaying the hidden posts
	 * link.
	 * 
	 * @param hiddenPosts WRITEME
	 * @return Text to display on hidden posts
	 */
	private String hiddenPostsText (final int hiddenPosts) {
		return "Show " + hiddenPosts + " more posts";

	}

	/**
	 * Removes the textfield for adding comments. The box is removed
	 * with a puff animation.
	 */
	public void removeAddCommentBox () {
		if (isCommenting) {
			final Callback callBack = new Callback () {
				/**
				 * @see org.gwtwidgets.client.wrap.Callback#execute()
				 */
				@Override
				public void execute () {
					CommentPanel.this.remove (addCommentField
							.getParent ().getParent ());
				}
			};
			Effect.dropOut (addCommentField.getParent ().getParent (),
					new EffectOption [] { new EffectOption (
							"afterFinish", callBack) });

			// final BlindUp blindFX = new
			// BlindUp(addCommentField.getParent()
			// .getElement());
			// blindFX.setTransitionType(new BounceTransitionPhysics());
			// blindFX.setDuration(1.25);
			// blindFX.play();
			// remove(addCommentBoxIndex);
			isCommenting = false;
			return;
		}
		GWT.log (
				"We're trying to remove the add comment box but we're not commenting",
				null);
	}

	/**
	 * <pre>
	 * twheys@gmail.com Feb 15, 2010
	 * </pre>
	 * 
	 * TO setAddCommentLinkHighlight WRITEME...
	 * 
	 * @param highlighted WRITEM
	 */
	public void setAddCommentLinkHighlight (final boolean highlighted) {
		if (highlighted) {
			addCommentField.addStyleName ("highlighted");
		} else {
			addCommentField.removeStyleName ("highlighted");
		}
	}

	/**
	 * 
	 * <pre>
	 * twheys@gmail.com Jan 13, 2010
	 * </pre>
	 * 
	 * TO setToAddComment WRITEME...
	 * 
	 */
	protected void setToAddComment () {
		if (isCommenting) {
			Effect.scrollTo (addCommentField.getParent ().getParent ()
					.getParent ().getParent ());
			Effect.shake (addCommentField.getParent ().getParent (),
					new EffectOption [] {
				new EffectOption ("duration", "1.0"),
				new EffectOption ("distance", "10"), });
			return;
		}
		GWT.log ("Inserting an addCommentBox", null);
		isCommenting = true;
		try {
			final HorizontalPanel addCommentBox = getAddCommentBox ();
			final SimplePanel addCommentBoxContainer = new SimplePanel ();
			addCommentBoxContainer.getElement ().setAttribute ("style",
			"display: none; z-index: 50;");
			addCommentBoxContainer.add (addCommentBox);
			insert (addCommentBoxContainer, getWidgetCount ());
			addCommentField.setFocus (true);

			Effect.scrollTo (addCommentField.getParent ().getParent ()
					.getParent ().getParent ());
			Effect.slideDown (addCommentBoxContainer,
					new EffectOption [] { new EffectOption ("duration",
					"1.0") });
		} catch (final PrivilegeRequiredException caught) {
			TootsBook
			.showPopup (new ErrorMessage (caught.getMessage ()));
		}
	}

	/**
	 * <pre>
	 * twheys@gmail.com Jan 13, 2010
	 * </pre>
	 * 
	 * TO showAllComments WRITEME...
	 * 
	 */
	protected void showAllComments () {
		final Iterator <Widget> i = getChildren ().iterator ();
		while (i.hasNext ()) {
			final Widget w = i.next ();
			if ( !w.isVisible ()) {
				Effect.slideDown (
						w,
						new EffectOption [] { new EffectOption (
								"queue",
						"{ position: ‘end’, scope: ‘showAll’ }") });
			}
		}

		Effect.squish (showAllComments);
	}

	/**
	 * <pre>
	 * twheys@gmail.com Jan 13, 2010
	 * </pre>
	 * 
	 * TO submitText WRITEME...
	 * 
	 */
	protected void submitText () {
		final String newMessage = addCommentField.getText ().trim ();
		if (DisplayText.COMMENT_FIELD_DEFAULT_TEXT.equals (newMessage)
				|| "".equals (newMessage)) {
			Effect.highlight (addCommentField, Color.RED, Color.WHITE,
					0.5);
			return;
		}
		addCommentField.setText ("");

		final Post newComment = new Post (TootsBook.getUser (),
				newMessage, postParent);
		newComment.setParentID (postParent.getId ());

		final BookServiceAsync service = TootsBook.initService ();

		// Set up the callback object.
		final AsyncCallback <Post> callback = new AsyncCallback <Post> () {
			@Override
			public void onFailure (final Throwable caught) {
				TootsBook.hideLoadingBar ();
				TootsBook.showError (caught);
			}

			@Override
			public void onSuccess (final Post successfulComment) {
				TootsBook.hideLoadingBar ();
				CommentPanel.this.removeAddCommentBox ();
				CommentPanel.this.addComment (successfulComment, false);
			}
		};

		// Make the call to the search service.
		service.addComment (newComment, callback);
		TootsBook.displayLoadingBar ();
	}

}
