package uk.ac.ebi.biosamples.controller;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PagedResourcesAssembler;
import org.springframework.hateoas.*;
import org.springframework.hateoas.mvc.ControllerLinkBuilder;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import uk.ac.ebi.biosamples.model.Sample;
import uk.ac.ebi.biosamples.service.FilterService;
import uk.ac.ebi.biosamples.service.SamplePageService;
import uk.ac.ebi.biosamples.service.SampleReadService;
import uk.ac.ebi.biosamples.service.SampleResourceAssembler;
import uk.ac.ebi.biosamples.solr.service.SolrSampleService;

import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;
import java.util.concurrent.TimeUnit;
import uk.ac.ebi.biosamples.service.SampleReadService;

/**
 * Primary controller for REST operations both in JSON and XML and both read and
 * write.
 * 
 * See {@link SampleHtmlController} for the HTML equivalent controller.
 * 
 * @author faulcon
 *
 */
@RestController
@ExposesResourceFor(Sample.class)
@RequestMapping("/samples")
public class SamplesRestController {

	private final SampleReadService sampleService;
	private final SamplePageService samplePageService;
	private final FilterService filterService;

	private final SampleResourceAssembler sampleResourceAssembler;

	private final EntityLinks entityLinks;

	private Logger log = LoggerFactory.getLogger(getClass());

	public SamplesRestController(SampleReadService sampleService,
			SamplePageService samplePageService,FilterService filterService,
			SampleResourceAssembler sampleResourceAssembler, EntityLinks entityLinks) {
		this.sampleService = sampleService;
		this.samplePageService = samplePageService;
		this.filterService = filterService;
		this.sampleResourceAssembler = sampleResourceAssembler;
		this.entityLinks = entityLinks;
	}

	@CrossOrigin(methods = RequestMethod.GET)
	@GetMapping(produces = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
	public ResponseEntity<PagedResources<Resource<Sample>>> searchHal(
			@RequestParam(name = "text", required = false) String text,
			@RequestParam(name = "updatedafter", required = false) String updatedAfter,
			@RequestParam(name = "updatedbefore", required = false) String updatedBefore,
			@RequestParam(name = "filter", required = false) String[] filter, Pageable page,
			PagedResourcesAssembler<Sample> pageAssembler) {

		MultiValueMap<String, String> filtersMap = filterService.getFilters(filter);
		
		LocalDateTime updatedAfterDate = null;
		if (updatedAfter != null) {
			try {
				updatedAfterDate = LocalDateTime.parse(updatedAfter, SolrSampleService.solrFormatter);
			} catch (DateTimeParseException e) {
				//do nothing
			}
		}

		LocalDateTime updatedBeforeDate = null;
		if (updatedBefore != null) {
			try {
				updatedBeforeDate = LocalDateTime.parse(updatedBefore, SolrSampleService.solrFormatter);
			} catch (DateTimeParseException e) {
				//do nothing
			}
		}
		
		Page<Sample> pageSample = samplePageService.getSamplesByText(text, filtersMap, updatedAfterDate, updatedBeforeDate, page);

		// add the links to each individual sample on the page
		// also adds links to first/last/next/prev at the same time
		PagedResources<Resource<Sample>> pagedResources = pageAssembler.toResource(pageSample, sampleResourceAssembler,
				entityLinks.linkToCollectionResource(Sample.class));

		// to generate the HAL template correctly, the parameter name must match
		// the requestparam name
		pagedResources
				.add(ControllerLinkBuilder.linkTo(ControllerLinkBuilder.methodOn(SampleAutocompleteRestController.class)
						.getAutocompleteHal(text, filter, null)).withRel("autocomplete"));
		pagedResources.add(ControllerLinkBuilder
				.linkTo(ControllerLinkBuilder.methodOn(SampleFacetRestController.class).getFacetsHal(text, filter))
				.withRel("facet"));
		pagedResources.add(ControllerLinkBuilder
				.linkTo(ControllerLinkBuilder.methodOn(SampleRestController.class).getSampleHal(null))
				.withRel("sample"));

		return ResponseEntity.ok()
				.header(HttpHeaders.CACHE_CONTROL, CacheControl.maxAge(1, TimeUnit.MINUTES).cachePublic().getHeaderValue())
				.body(pagedResources);
	}

}

@@ -1359,16 +1359,89 @@
 rvice;%0A%0A
+import java.io.UnsupportedEncodingException;%0Aimport java.net.URLDecoder;%0A
 import j
@@ -3222,16 +3222,427 @@
 ler) %7B%0A%0A
+%09%09%0A%09%09if (text != null) %7B%0A%09%09%09try %7B%0A%09%09%09%09text = URLDecoder.decode(text, %22UTF-8%22);%0A%09%09%09%7D catch (UnsupportedEncodingException e) %7B%0A%09%09%09%09throw new RuntimeException(e);%0A%09%09%09%7D%0A%09%09%7D%0A%09%09%0A%09%09if (filter != null) %7B%0A%09%09%09for (int i = 0; i %3C filter.length; i++) %7B%0A%09%09%09%09try %7B%0A%09%09%09%09%09filter%5Bi%5D = URLDecoder.decode(filter%5Bi%5D, %22UTF-8%22);%0A%09%09%09%09%7D catch (UnsupportedEncodingException e) %7B%0A%09%09%09%09%09throw new RuntimeException(e);%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%0A%09%09%0A%09%09%0A
 %09%09MultiV

fix to handle urnencoded arguments