package org.hibernate.search.demos.wikipedia.endpoint;

import java.net.URI;
import java.util.stream.Collectors;

import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
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.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

import org.hibernate.search.demos.wikipedia.data.Page;
import org.hibernate.search.demos.wikipedia.data.dao.PageDao;
import org.hibernate.search.demos.wikipedia.data.dao.PageSort;
import org.hibernate.search.demos.wikipedia.dto.PageInputDto;
import org.hibernate.search.demos.wikipedia.dto.PageOutputDto;
import org.hibernate.search.demos.wikipedia.dto.mapper.PageMapper;
import org.hibernate.search.demos.wikipedia.util.SearchResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Path("/page")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Transactional(readOnly = true)
public class PageEndpoint {
	
	private static final int ITEMS_PER_PAGE = 20;
	
	@Inject
	private PageDao dao;

	@PUT
	@Path("/")
	@Transactional(readOnly = false)
	public Response create(PageInputDto pageDto, @Context UriInfo uriInfo) {
		Page page = new Page();
		PageMapper.INSTANCE.input( page, pageDto );
		dao.create( page );
		URI pageUri = uriInfo.getAbsolutePathBuilder().path( "{id}" ).build( page.getId() );
		return Response.created( pageUri ).build();
	}

	@POST
	@Path("/{id}")
	@Transactional(readOnly = false)
	public Response update(@PathParam("id") Long id, PageInputDto pageDto) {
		Page page = getExisting( id );
		PageMapper.INSTANCE.input( page, pageDto );
		dao.update( page );
		return Response.ok().build();
	}

	@DELETE
	@Path("/{id}")
	@Transactional(readOnly = false)
	public void delete(@PathParam("id") Long id) {
		dao.delete( getExisting( id ) );
	}

	@GET
	@Path("/{id}")
	public PageOutputDto getById(@PathParam("id") Long id) {
		return PageMapper.INSTANCE.output( getExisting( id ) );
	}

	@GET
	@Path("/search")
	public SearchResult<PageOutputDto> search(@QueryParam("q") String queryString, @QueryParam("s") PageSort sort, @QueryParam("p") Integer page) {
		if ( page == null ) {
			page = 0;
		}
		SearchResult<Page> searchResult = dao.search( queryString, sort, ITEMS_PER_PAGE, page * ITEMS_PER_PAGE );
		
		return new SearchResult<>(
				searchResult.getTotalCount(),
				searchResult.getHits()
						.stream()
						.map( PageMapper.INSTANCE::outputSummary )
						.collect( Collectors.toList() )
		);
	}

	private Page getExisting(Long id) {
		Page page = dao.getById( id );
		if ( page == null ) {
			throw new NotFoundException();
		}
		return page;
	}

}

@@ -191,16 +191,49 @@
 DELETE;%0A
+import javax.ws.rs.DefaultValue;%0A
 import j
@@ -2393,17 +2393,20 @@
 yString,
- 
+%0A%09%09%09
 @QueryPa
@@ -2413,16 +2413,45 @@
 ram(%22s%22)
+ @DefaultValue( %22RELEVANCE%22 )
  PageSor
@@ -2457,17 +2457,20 @@
 rt sort,
- 
+%0A%09%09%09
 @QueryPa
@@ -2482,64 +2482,40 @@
 p%22) 
-Integer page) %7B%0A%09%09if ( page == null ) %7B%0A%09%09%09page = 0;%0A%09%09%7D
+@DefaultValue( %220%22 ) int page) %7B
 %0A%09%09S
@@ -2558,17 +2558,21 @@
 .search(
- 
+%0A%09%09%09%09
 queryStr
@@ -2581,17 +2581,21 @@
 g, sort,
- 
+%0A%09%09%09%09
 ITEMS_PE
@@ -2623,17 +2623,19 @@
 PER_PAGE
- 
+%0A%09%09
 );%0A%09%09%0A%09%09

Fix NPEs