package com.packtpub.hibernatesearch.rest;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.packtpub.hibernatesearch.domain.App;
import com.packtpub.hibernatesearch.util.StartupDataLoader;

/**
 * RESTowa usługa zaimplementowana w JAX-RS. Pobiera encję App na podstawie jej ID.  Dzięki niej 
 * servlet wyszukujący może użyć zapytań w oparciu o projekcje by pobrac potrzebne dane z Lucene.
 * Baza danych jest odpytywana wyłącznie gdy użytkownik naciśnie przycisk "Szczegóły".  Naciskając 
 * przycisk użytkownik wywołuje AJAXowe żądanie do tej usługi. Wynikiem jest encja przesłana w formacie
 * JSON.
 * 
 * Klasa "RestfulApplication" rejestruje usługę i udostępnia ją użytkownikom.
 * 
 * Adnotacja @Path definiuje URL, który będzie obsługiwany przez usługę. W połączeniu z podstawową ścieżką
 * zdefiniowaną w "RestfulApplication" pełna ścieżka będzie wyglądać np. tak http://localhost:8080/rest/appById/1. 
 * 
 * Adnotacja @Produces instruuje JAX-RS by skonwertował wynik do formatu JSON.
 */
@Path("/appById/{appId}")
@Produces(MediaType.APPLICATION_JSON)
public class AppResource {
	
	Logger logger = LoggerFactory.getLogger(AppResource.class);

	/**
	 * Adnotacja @GET powoduje, że ta metoda jest wywoływana zawsze, gdy żądanie HTTP GET przyjdzie pod 
	 * zarejestrowany URL. 
	 */
	@GET
	public App getAppData( @PathParam("appId") Long appId ) {
		// Zainicjalizuj Hibernate
		Session session = StartupDataLoader.openSession();
		session.beginTransaction();
		
		// Pobierz encję App na podstawie przesłanego ID, używając zachłannego pobierania. Konwersja do JSONa odbędzie 
		// się po zamknięciu sesji Hibernate... gdybyśmy użyli leniwego pobierania, konwerter JSONa nie zakończyłby operacji 
		// pomyślnie po napotkaniu powiązanych obiektów.
		Criteria criteria = session.createCriteria(App.class);
		criteria.add( Restrictions.eq("id", appId) );
		criteria.setFetchMode("supportedDevices", FetchMode.SELECT);
		criteria.setFetchMode("customerReviews", FetchMode.SELECT);
		App app = (App) criteria.uniqueResult();
		
		// Czyszczenie Hibernate
		session.getTransaction().commit();
		session.clear();
		session.close();
		
		return app;
	}
	
}
