package com.packtpub.hibernatesearch.domain;

import java.io.Serializable;
import java.util.Set;

import org.hibernate.search.annotations.DocumentId;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;

/**
 * Prosta klasa encji reprezentująca aplikację komputerową ... z nazwą, długim opisem 
 * i nazwą pliku użytego jako ikona. Klasa posiada flagę "active" określającą, czy dana aplikacja
 * ma być wyszukiwalna.   
 * 
 * Ten wariant klasy App jest mapowany do bazy danych za pomocą klasycznego podejścia opartego na plikach XML.
 * W Mavenowej strukturze projektu wszystkie pliki XML są umieszczone w "src/main/resources".  Hibernate 
 * automatycznie przegląda plik "hibernate.cfg.xml", który odwołuje się do "com/packtpub/hibernatesearch/domain/App.hbm.xml"
 * by załadować informacje o mappowaniu encji.  Rezultaty są identyczne jak w przypadku użycia adnotacji @Entity.
 * 
 * Pomimo, że adnotacja @Entity nie jest używana, konfiguracja Hibernate Search jest nadal oparta o adnotacje.
 * Adnotacja @Indexed informuje Hibernate Search by mapowała encję na indeks Lucene.
 */
@Indexed
public class App implements Serializable {

	private static final long serialVersionUID = 1L;

	/**
	 * Klucz główny, skonfigurowany w pliku "App.hbm.xml" tak, by był generowany automatycznie podczas tworzenia nowej instancji
	 * 
	 * Adnotacja @DocumentId instruuje Hibernate Search by użyło tej wartości jako klucz główny podczas indeksowania encji w Lucene.  
	 * Jeżeli używasz adnotacji do mapowania na tabele w bazie danych, Hibernate Search skorzysta z adnotacji @Id. Używając mapowania XML
	 * musisz zadeklarować @DocumentId.
	 */
	@DocumentId
  private Long id;

	/**
	 * Nazwa aplikacji zrozumiała dla ludzi.  Zamiast adnotacji @Column używamy informacji z pliku "App.hbm.xml", ale 
	 * wciąż używamy adnotacji @Field by poinformować Hibernate Search, że pole ma być oznaczone jako wyszukiwalne w indeksie Lucene.
	 */
	@Field
  private String name;	
	
	/**
	 * Dłuższy, bardziej szczegółowy opis aplikacji.  Zamiast adnotacji @Column używamy informacji z pliku "App.hbm.xml", ale 
	 * wciąż używamy adnotacji @Field by poinformować Hibernate Search, że pole ma być oznaczone jako wyszukiwalne w indeksie Lucene.
	 */
	@Field
  private String description;

	/**
	 * Nazwa pliku obrazka dołączonego do opisu aplikacji. Plik powinien się znajdować w podkatalogu
	 * "images/apps/<obrazek>". Obrazek nie jest adnotowany @Field ponieważ nie będziemy wyszukiwać aplikacji
	 * na podstawie obrazków.
	 */		
  private String image;

	/**
	 * Flaga określająca, czy aplikacja ma być wyszukiwalna.
	 */
  private boolean active;

	/**
	 * Kolekcja powiązanych encji typu Device, reprezentujących urządzenia na których można uruchomić aplikację.
	 * 
	 * Mapowanie Hibernate odbywa się w pliku "App.hbm.xml", używamy elementu XML "<many-to-many>"
	 * zamiast adnotacji @ManyToMany.  Niemniej jednak pobieranie oraz kaskadowanie opisane w komentarzach do kodu w katalogu 
	 * "rozdzial2" mają również zastosowanie w tym przypadku.
	 * 
	 * Adnotacja @IndexedEmbedded informuje Hibernate Search by indeksował powiązane encje.  
	 * Klasa Device może (ale nie musi) posiadać indeks Lucene (w zależności od tego czy klasa jest adnotowana @Indexed), 
	 * ale i tak instancje Device powiązane z aplikacją będą przechowywane w indeksie Lucene klasy App.  
	 */
  @IndexedEmbedded(depth=1)
  private Set<Device> supportedDevices;

	/**
	 * Kolekcja wbudowanych obiektów prezentujących opinie użytkowników o aplikacji. Wbudowane obiekty różnią się od powiązanych encji 
	 * tym, że z chwilą skasowania obiektu, z którym są powiązane one również zostają usunięte. 
	 * 
	 * Mapowanie Hibernate odbywa się w pliku "App.hbm.xml", używamy elementu XML "<composite-element>"
	 * zamiast adnotacji @ElementCollection.  Niemniej jednak pobieranie oraz kaskadowanie opisane w komentarzach do kodu w katalogu 
	 * "rozdzial2" mają również zastosowanie w tym przypadku.
	 * 
	 * Adnotacja @IndexEmbedded ma zdefiniowany opcjonalny element "includePaths" by wskazać, które pola wbudowanych obiektów 
	 * będą indeksowane w encji nadrzędnej.  Innymi słowy pole "comments" będzie jedyną wartością klasy CustomerReview dołączoną
	 * do indeksu Lucene klasy App.  
	 */
  @IndexedEmbedded(depth=1, includePaths = { "comments" })
	private Set<CustomerReview> customerReviews;

	/**
	 * Domyślny pusty konstruktor.
	 */
	public App() {}

	/**
	 * Wygodny konstruktor, ustawiający zawartość wszystkich pól w jednym kroku.  
	 * 
	 * Parametr "active" jest domyślnie ustawiony na wartość "true".  Aby dezaktywować aplikację,
	 * użyj settera dla tego pola. 
	 */
	public App(String name, String image, String description) {
		this.name = name;
		this.image = image;
		this.description = description;
		this.active = true;
	}

	//
	// GETTERY I SETTERY
	//
	
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getImage() {
		return image;
	}

	public void setImage(String image) {
		this.image = image;
	}

	public Set<Device> getSupportedDevices() {
		return supportedDevices;
	}

	public void setSupportedDevices(Set<Device> supportedDevices) {
		this.supportedDevices = supportedDevices;
	}

	public boolean isActive() {
		return active;
	}

	public void setActive(boolean active) {
		this.active = active;
	}

	public Set<CustomerReview> getCustomerReviews() {
		return customerReviews;
	}

	public void setCustomerReviews(Set<CustomerReview> customerReviews) {
		this.customerReviews = customerReviews;
	}

}
