package org.jboss.resteasy.links.test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;

import org.jboss.resteasy.links.AddLinks;
import org.jboss.resteasy.links.LinkResource;
import org.jboss.resteasy.links.LinkResources;
import org.jboss.resteasy.links.ParamBinding;
import org.jboss.resteasy.links.RESTServiceDiscovery;
import org.jboss.resteasy.links.RESTServiceDiscovery.AtomLink;

@Path("/")
public class BookStore {
	
	private Map<String,Book> books = new HashMap<String,Book>();
	
	{
		Book book = new Book("foo", "bar");
		book.addComment(0, "great book");
		book.addComment(1, "terrible book");
		books.put(book.getTitle(), book);
	}

	@Produces({"application/xml", "application/json"})
	@AddLinks
	@LinkResource(value = Book.class, rel = "list")
	@GET
	@Path("books")
	public Collection<Book> getBooks(){
		return books.values();
	}

	@Consumes({"application/xml", "application/json"})
	@LinkResource(value = Book.class, rel = "add")
	@POST
	@Path("books")
	public void addBook(Book book){
		books.put(book.getTitle(), book);
	}

	@Produces({"application/xml", "application/json"})
	@AddLinks
	@LinkResource(value = Book.class, pathParameters = "${title}")
	@GET
	@Path("book/{id}")
	public Book getBook(@PathParam("id") String id){
		return books.get(id);
	}

	@Consumes({"application/xml", "application/json"})
	@LinkResource(value = Book.class, pathParameters = "${title}")
	@PUT
	@Path("book/{id}")
	public void updateBook(@PathParam("id") String id, Book book){
		books.put(id, book);
	}

	@LinkResource(value = Book.class, pathParameters = "${title}")
	@DELETE
	@Path("book/{id}")
	public void deleteBook(@PathParam("id") String id){
		books.remove(id);
	}
	
	// comments
	
	@Produces({"application/xml", "application/json"})
	@AddLinks
	@LinkResources({
		@LinkResource(value = Book.class, rel = "comments", pathParameters = "${title}"),
		@LinkResource(value = Comment.class, rel = "list", pathParameters = "${book.title}")
	})
	@GET
	@Path("book/{id}/comments")
	public Collection<Comment> getComments(@PathParam("id") String bookId){
		return books.get(bookId).getComments();
	}

	@Produces({"application/xml", "application/json"})
	@AddLinks
	@LinkResources({
		@LinkResource(value = Book.class, rel="comment-collection"),
		@LinkResource(value = Comment.class, rel="collection"),
		@LinkResource(value = ScrollableCollection.class, rel = "prev", constraint = "${this.start - this.limit >= 0}", queryParameters = {
				@ParamBinding(name = "start", value = "${this.start - this.limit}"),
				@ParamBinding(name = "limit", value = "${this.limit}") }),
		@LinkResource(value = ScrollableCollection.class, rel = "next", constraint = "${this.start + this.limit < this.totalRecords}", queryParameters = {
				@ParamBinding(name = "start", value = "${this.start + this.limit}"),
				@ParamBinding(name = "limit", value = "${this.limit}")
		}, matrixParameters = {@ParamBinding(name = "query", value = "${this.query}")})
	})
	@GET
	@Path("book/{id}/comment-collection")
	public ScrollableCollection getScrollableComments(@Context UriInfo uriInfo, @PathParam("id") String id, @QueryParam("start") int start, @QueryParam("limit") @DefaultValue("1") int limit, @MatrixParam("query") String query){
		List<Comment> comments = new ArrayList<Comment>();
		for (Comment comment : books.get(id).getComments()) {
			if (comment.getText().contains(query)) {
				comments.add(comment);
			}
		}
		start = start < 0 ? 0 : start;
		limit = limit < 1 ? 1 : limit;
		limit = (start + limit) > comments.size() ? comments.size() - start : limit;
		ScrollableCollection result = new ScrollableCollection(id, start, limit, comments.size(), comments.subList(start, start + limit), query);
		
		RESTServiceDiscovery discovery = new RESTServiceDiscovery();
		discovery.addLink(uriInfo.getBaseUriBuilder().build(), "home");
		result.setRest(discovery);
		
		return result;
	}

	@Produces({"application/xml", "application/json"})
	@AddLinks
	@LinkResource(value = Comment.class, rel = "self", pathParameters = {"${book.title}", "${id}"})
	@GET
	@Path("book/{id}/comment/{cid}")
	public Comment getComment(@PathParam("id") String bookId, @PathParam("cid") int commentId){
		return books.get(bookId).getComment(commentId);
	}

	@Consumes({"application/xml", "application/json"})
	@LinkResource(value = Comment.class, rel = "add", pathParameters = {"${book.title}"})
	@POST
	@Path("book/{id}/comments")
	public void addComment(@PathParam("id") String bookId, Comment comment){
		books.get(bookId).getComments().add(comment);
	}

	@Consumes({"application/xml", "application/json"})
	@LinkResource(value = Comment.class, rel = "update", pathParameters = {"${book.title}", "${id}"})
	@PUT
	@Path("book/{id}/comment/{cid}")
	public void updateComment(@PathParam("id") String bookId, @PathParam("cid") int commentId, Comment comment){
		books.get(bookId).getComment(commentId).setText(comment.getText());
	}

	@LinkResource(value = Comment.class, rel = "remove", pathParameters = {"${book.title}", "${id}"})
	@DELETE
	@Path("book/{id}/comment/{cid}")
	public void deleteComment(@PathParam("id") String bookId, @PathParam("cid") int commentId){
		Book book = books.get(bookId);
		Comment c = book.getComment(commentId);
		book.getComments().remove(c);
	}

}
