/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.wicket.examples.ajax.builtin;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior;
import org.apache.wicket.examples.guestbook.Comment;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.basic.MultiLineLabel;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.PropertyModel;


/**
 * Ajax enabled example for the guestbook.
 * 
 * @author Martijn Dashorst
 */
public class GuestBook extends BasePage
{
	/** A global list of all comments from all users across all sessions */
	public static final List<Comment> commentList = new ArrayList<>();

	/** The list view that shows comments */
	private final ListView<Comment> commentListView;
	/** Container for the comments, used to update the listview. */
	private final WebMarkupContainer comments;

	/** The textarea for entering the comments, is updated in the ajax call. */
	private Component text;

	/**
	 * Constructor.
	 */
	public GuestBook()
	{
		// Add comment form
		CommentForm commentForm = new CommentForm("commentForm");
		add(commentForm);

		// the WebMarkupContainer is used to update the listview in an ajax call
		comments = new WebMarkupContainer("comments");
		add(comments.setOutputMarkupId(true));

		// Add commentListView of existing comments
		comments.add(commentListView = new ListView<Comment>("comments",
			new PropertyModel<>(this, "commentList"))
		{
			@Override
			public void populateItem(final ListItem<Comment> listItem)
			{
				final Comment comment = listItem.getModelObject();
				listItem.add(new Label("date", comment::getDate));
				listItem.add(new MultiLineLabel("text", comment.getText()));
			}
		});

		// The AjaxFormSubmitBehavior already calls the onSubmit of the form,
		// all we need to do in the onSubmit(AjaxRequestTarget) handler is do our
		// Ajax specific stuff, like rendering our components.
		commentForm.add(new AjaxFormSubmitBehavior(commentForm, "submit")
		{
			@Override
			protected void onSubmit(AjaxRequestTarget target)
			{
				// add the list of components that need to be updated
				target.add(comments);
				target.add(text);

				// focus the textarea again
				target.appendJavaScript("document.getElementById('" + text.getMarkupId() +
					"').focus();");
			}

			@Override
			protected void onError(AjaxRequestTarget target)
			{
			}

			@Override
			protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
			{
				super.updateAjaxAttributes(attributes);

				// we need to cancel the standard submit of the form in the onsubmit
				// handler,
				// otherwise we'll get double submits. To do so, we return false after
				// the
				// ajax submit has occurred.
				attributes.setPreventDefault(true);
			}
		});
	}

	/**
	 * A form that allows a user to add a comment.
	 * 
	 * @author Jonathan Locke
	 */
	private final class CommentForm extends Form<Comment>
	{
		/**
		 * Constructor
		 * 
		 * @param id
		 *            The name of this component
		 */
		private CommentForm(final String id)
		{
			// Construct form with no validation listener
			super(id, new CompoundPropertyModel<>(new Comment()));

			// Add text entry widget
			text = new TextArea<>("text").setOutputMarkupId(true);
			add(text);
		}

		/**
		 * Show the resulting valid edit
		 */
		@Override
		public final void onSubmit()
		{
			// Construct a copy of the edited comment
			final Comment comment = getModelObject();
			final Comment newComment = new Comment(comment);

			// Set date of comment to add
			newComment.setDate(new Date());

			// Add the component we edited to the list of comments
			commentList.add(0, newComment);

			// Clear out the text component
			comment.setText("");
		}
	}

	/**
	 * Clears the comments.
	 */
	public static void clear()
	{
		commentList.clear();
	}
}
