package it.mice.voila.runtime.dao;

import it.mice.voila.runtime.entity.Entity;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.sql.Blob;
import java.sql.Clob;
import java.util.Collection;
import java.util.Map;

/**
 * Created by IntelliJ IDEA.
 * User: zzy9v4
 * Date: 2-feb-2007
 * Time: 23.52.17
 * To change this template use File | Settings | File Templates.
 */
public interface Dao<T extends Entity> {
    
	/**
	 * Ricerca di un Entity accedendo per chiave primaria.<br>
	 * L'implementazione di questo metodo deve estrarre dal DB un oggetto di tipo
	 * {@link Entity} accedendo per la chiave primaria fornita nell'oggetto di input.
	 * 
	 * @param entity
	 *            Entity {@link Entity} valorizzato della sola chiave primaria e da
	 *            utilizzare per l'accesso al DB.
	 * @return il riferimento all'oggetto fornito in input, oppure null se non trovato.
	 */
	T findByPrimaryKey(T entity);
    
	/**
	 * Ricerca di un Entity accedendo per chiave primaria.<br>
	 * L'implementazione di questo metodo deve estrarre dal DB un oggetto di tipo
	 * {@link Entity} accedendo per la chiave primaria fornita nell'oggetto di input.
	 * 
	 * @param entity
	 *            Entity {@link Entity} valorizzato della sola chiave primaria e da
	 *            utilizzare per l'accesso al DB.
	 * @return il riferimento all'oggetto fornito in input, oppure null se non trovato.
	 */
	T findByPrimaryKey(T entity, boolean useAcl);
    
	/**
	 * Ricerca di un Customer accedendo per chiave primaria.<br>
	 * A differenza del metodo findByPrimaryKey, esso evita la registrazione nella hibernate cache dell'oggetto
	 * appena letto, consentendo il suo utilizzo per dei check senza per questo incorrere nella noiosissima
	 * eccezione NonUniqueObjectException di hibernate.
	 * 
	 * @param theCustomer
	 *            Entity {@link Customer} valorizzato della sola chiave primaria e da
	 *            utilizzare per l'accesso al DB.
	 * @return il riferimento all'oggetto fornito in input, oppure null se non trovato.
	 */
	public T findByPrimaryKeyNoCache(final T theEntity);

	/**
	 * Controlla l'esistenza di un Entity accedendo per chiave primaria.<br>
	 * L'implementazione di questo metodo deve controllare nel DB l'esistenza di un
	 * oggetto di tipo {@link Entity} accedendo per la chiave primaria fornita
	 * nell'oggetto di input.
	 * 
	 * @param entity
	 *            Entity {@link Entity} valorizzato della sola chiave primaria e da
	 *            utilizzare per l'accesso al DB.
	 * @return <code>true</code> se l'oggetto Entity è stato trovato;<br>
	 *         <code>false</code> se l'oggetto Entity non è stato trovato.
	 */
	boolean existByPrimaryKey(T entity);

	/**
	 * Estrazione di tutte le istanze di Entity accedendo senza parametri.<br>
	 * L'implementazione di questo metodo deve accedere al DB ed estrarre tutte le
	 * occorrenza dalla tabella.
	 * 
	 * @return una collection contenente un elemento Entity per ogni occorrenza estratta
	 *         dalla tabella. La collection deve essere vuota se nessuna occorrenza viene
	 *         trovata in base dati.
	 */
	Collection<T> findAll();
	
	
	Collection<T> findAll(Boolean cacheable);

	/**
	 * Inserimento di un Entity. L'implementazione di questo metodo deve permettere
	 * l'inserimento di una riga nella tabella rappresentata dall'oggetto Entity fornito
	 * in input.
	 * 
	 * @param entity
	 *            Entity {@link Entity} completamente valorizzato e da inserire nel DB.
	 * @return lo stesso oggetto fornito in input. Considera che tale oggetto potrebbe
	 *         cambiare come nel caso di sequences pk, tracking attributes (data ult.
	 *         agg., utente ins., ecc...).
	 */
	T insert(T entity);

	/**
	 * Inserimento di una collection di Entity. L'implementazione di questo metodo deve
	 * permettere l'inserimento di una riga nella tabella per ogni elemento estratto dalla
	 * collection di entity fornita in input.
	 * 
	 * @param entityList
	 *            collection contenente un elemento per ogni entity da inserire nel DB.
	 * @return lo stesso oggetto fornito in input. Considera che tale oggetto potrebbe
	 *         cambiare come nel caso di sequences pk, tracking attributes (data ult.
	 *         agg., utente ins., ecc...).
	 */
	Collection<T> insert(Collection<T> entityList);

	/**
	 * Aggiornamento di un Entity. L'implementazione di questo metodo deve permettere
	 * l'aggiornamento di una riga nella tabella rappresentata dall'oggetto Entity
	 * fornito in input.
	 * 
	 * @param entity
	 *            Entity {@link Entity} completamente valorizzato e da aggiornare nel
	 *            DB.
	 * @return lo stesso oggetto fornito in input. Considera che tale oggetto potrebbe
	 *         cambiare come nel caso di tracking attributes (data ult. agg., utente ins.,
	 *         ecc...).
	 */
	T update(T entity);

	/**
	 * Aggiornamento di una collection di Entity. L'implementazione di questo metodo
	 * deve permettere l'aggiornamento di una riga nella tabella per ogni elemento
	 * estratto dalla collection di entity fornita in input.
	 * 
	 * @param entityList
	 *            collection contenente un elemento per ogni entity da aggiornare nel DB.
	 * @return lo stesso oggetto fornito in input. Considera che tale oggetto potrebbe
	 *         cambiare come nel caso di tracking attributes (data ult. agg., utente ins.,
	 *         ecc...).
	 */
	Collection<T> update(Collection<T> entityList);

	/**
	 * Inserimento/Aggiornamento di un Entity. L'implementazione di questo metodo deve
	 * prendere in input l'oggetto di tipo {@link Entity} dal quale preleverà lo stato
	 * interno ed, in funzione di tale stato dovrà eseguire le seguenti operazioni:
	 * <ul>
	 * <li>insert - se lo stato interno è <code>new</code>.</li>
	 * <li>update - se lo stato interno è <code>changed</code>.</li>
	 * </ul>
	 * 
	 * @param entity
	 *            Entity {@link Entity} da inserire/aggiornare.
	 * @return lo stesso oggetto fornito in input. Considera che tale oggetto potrebbe
	 *         cambiare come nel caso di tracking attributes (data ult. agg., utente ins.,
	 *         ecc...).
	 */
	T store(T entity);

	/**
	 * Cancellazione di un Entity accedendo per chiave primaria.<br>
	 * L'implementazione di questo metodo deve permettere la cancellazione di una riga
	 * dalla tabella rappresentata dall'oggetto Entity fornito in input.
	 * 
	 * @param entity
	 *            Entity {@link Entity} completamente valorizzato e da eliminare dal DB.
	 * @return <code>true</code> se l'oggetto Entity è stato cancellato correttamente;<br>
	 *         <code>false</code> se l'oggetto Entity non è stato cancellato
	 *         correttamente.
	 */
	boolean delete(T entity);

	/**
	 * Come il metodo {@link #delete(Entity)} ma operando su di una collection.
	 * 
	 * @param entityList
	 *            collection di entity da cancellare dal db.
	 * @return <code>true</code> se la collection è stata cancellata correttamente,
	 *         altrimenti <code>false</code>.
	 * @see #delete(Entity)
	 */
	boolean delete(Collection<T> entityList);

	/**
	 * Ricerca di un elenco di Entity accedendo per Filtro.<br>
	 * L'implementazione di questo metodo deve permettere la ricerca di Entity accedendo
	 * per filtri from/to. L'implementazione assume che nessun criteria map è utilizzato,
	 * di conseguenza criteri di ricerca standard verranno utilizzati.
	 * 
	 * @param entityFrom
	 *            Entity {@link Entity} utilizzato come filtro (From)
	 * @param entityTo
	 *            Entity {@link Entity} utilizzato come filtro (To)
	 * @return Una Collection di Entity. Attenzione, la Collection avrà size 0 se non
	 *         viene trovata alcuna occorrenza.
	 */
	Collection<T> findByFilter(T entityFrom, T entityTo);

	/**
	 * Ricerca di un elenco di Entity accedendo per Filtro.<br>
	 * L'implementazione di questo metodo deve permettere la ricerca di Entity accedendo
	 * per filtri from/to. L'implementazione assume che un criteria map è utilizzato, di
	 * conseguenza criteri di ricerca avanzati verranno utilizzati. Criteria map è una Map
	 * implementation con la chiave corrispondente al nome dell'attributo da filtrare ed
	 * il valore corrispondente al tipo di criterio da utilizzare.
	 * 
	 * @param entityFrom
	 *            Entity {@link Entity} utilizzato come filtro (From)
	 * @param entityTo
	 *            Entity {@link Entity} utilizzato come filtro (To)
	 * @param criteria
	 *            attribute name/criteria type map per applicazione di criteri avanzati di
	 *            ricerca.
	 * @return Una Collection di Entity. Attenzione, la Collection avrà size 0 se non
	 *         viene trovata alcuna occorrenza.
	 */
	Collection<T> findByFilter(T entityFrom, T entityTo,
			Map<String, Object> criteria);

	/**
	 * Ricerca di un elenco di Entity accedendo per Filtro e limitando la ricerca ad un
	 * range di record specifico. L'implementazione di questo metodo deve permettere la
	 * ricerca di Entity accedendo per filtri from/to. L'implementazione assume che
	 * nessun criteria map è utilizzato, di conseguenza criteri di ricerca standard
	 * verranno utilizzati.
	 * 
	 * @param entityFrom
	 *            Entity {@link Entity} utilizzato come filtro (From)
	 * @param entityTo
	 *            Entity {@link Entity} utilizzato come filtro (To)
	 * @param firstResult
	 *            Numero occorrenza iniziale da estrarre.
	 * @param maxResult
	 *            Numero totale di occorrenze da estrarre.
	 * @return Una Collection di Entity. Attenzione, la Collection avrà size 0 se non
	 *         viene trovata alcuna occorrenza.
	 */
	Collection<T> findByFilter(T entityFrom, T entityTo,
			int firstResult, int maxResult);

	/**
	 * Ricerca di un elenco di Entity accedendo per Filtro e limitando la ricerca ad un
	 * range di record specifico. L'implementazione di questo metodo deve permettere la
	 * ricerca di Entity accedendo per filtri from/to. L'implementazione assume che un
	 * criteria map è utilizzato, di conseguenza criteri di ricerca avanzati verranno
	 * utilizzati. Criteria map è una Map implementation con la chiave corrispondente al
	 * nome dell'attributo da filtrare ed il valore corrispondente al tipo di criterio da
	 * utilizzare.
	 * 
	 * @param entityFrom
	 *            Entity {@link Entity} utilizzato come filtro (From)
	 * @param entityTo
	 *            Entity {@link Entity} utilizzato come filtro (To)
	 * @param criteria
	 *            attribute name/criteria type map per applicazione di criteri avanzati di
	 *            ricerca.
	 * @param firstResult
	 *            Numero occorrenza iniziale da estrarre.
	 * @param maxResult
	 *            Numero totale di occorrenze da estrarre.
	 * @return Una Collection di Entity. Attenzione, la Collection avrà size 0 se non
	 *         viene trovata alcuna occorrenza.
	 */
	Collection<T> findByFilter(T entityFrom, T entityTo,
			Map<String, Object> criteria, int firstResult, int maxResult);

	/**
	 * Ricerca di un elenco di Entity accedendo per Filtro e limitando la ricerca ad un
	 * range di record specifico. Il metodo consente anche di specificare (se diverso da
	 * null) un DB sorting. L'implementazione di questo metodo deve permettere la ricerca
	 * di Entity accedendo per filtri from/to. L'implementazione assume che un criteria
	 * map è utilizzato, di conseguenza criteri di ricerca avanzati verranno utilizzati.
	 * Criteria map è una Map implementation con la chiave corrispondente al nome
	 * dell'attributo da filtrare ed il valore corrispondente al tipo di criterio da
	 * utilizzare.
	 * 
	 * @param entityFrom
	 *            Entity {@link Entity} utilizzato come filtro (From)
	 * @param entityTo
	 *            Entity {@link Entity} utilizzato come filtro (To)
	 * @param criteria
	 *            attribute name/criteria type map per applicazione di criteri avanzati di
	 *            ricerca.
	 * @param firstResult
	 *            Numero occorrenza iniziale da estrarre.
	 * @param maxResult
	 *            Numero totale di occorrenze da estrarre.
	 * @param orderBy
	 *            String che rappresenta la clausola 'order by' senza il prefisso
	 *            "ORDER BY".
	 * @return Una Collection di Entity. Attenzione, la Collection avrà size 0 se non
	 *         viene trovata alcuna occorrenza.
	 */
	Collection<T> findByFilter(T entityFrom, T entityTo,
			Map<String, Object> criteria, int firstResult, int maxResult, String orderBy);

	/**
	 * Conta il numero di occorrenze accedendo per Filtro. L'implementazione di questo
	 * metodo deve permettere il conteggio del numero totale di records in base ai criteri
	 * di ricerca specificati. L'implementazione assume che nessun criteria map è
	 * utilizzato, di conseguenza criteri di ricerca standard verranno utilizzati.
	 * 
	 * @param entityFrom
	 *            Entity {@link Entity} utilizzato come filtro (From)
	 * @param entityTo
	 *            Entity {@link Entity} utilizzato come filtro (To)
	 * @return il numero di records contati.
	 */
	int countByFilter(T entityFrom, T entityTo);

	/**
	 * Conta il numero di occorrenze accedendo per Filtro. L'implementazione di questo
	 * metodo deve permettere il conteggio del numero totale di records accedendo per
	 * filtri from/to. L'implementazione assume che un criteria map è utilizzato, di
	 * conseguenza criteri di ricerca avanzati verranno utilizzati. Criteria map è una Map
	 * implementation con la chiave corrispondente al nome dell'attributo da filtrare ed
	 * il valore corrispondente al tipo di criterio da utilizzare.
	 * 
	 * @param entityFrom
	 *            Entity {@link Entity} utilizzato come filtro (From)
	 * @param entityTo
	 *            Entity {@link Entity} utilizzato come filtro (To)
	 * @param criteria
	 *            attribute name/criteria type map per applicazione di criteri avanzati di
	 *            ricerca.
	 * @return il numero di records contati.
	 */
	int countByFilter(T entityFrom, T entityTo,
			Map<String, Object> criteria);
	
	/**
	 * Method to create a Clob object from a String.
	 * 
	 * @param clobContent the Clob content as a String
	 * @return the Clob object
	 */
	public Clob createClob(String clobContent);
	
	/**
	 * Utility method to create a Clob object from a Reader.
	 * 
	 * @param reader the Clob content as a String
	 * @param length the number of characters in the stream
	 * @return the Clob object
	 */	
	public Clob createClob(Reader reader, long length);
	
	/**
	 * Utility method to create a <tt>Blob</tt> object from a byte array using the
	 * hibernate specific implementation. The returned object will be initially
	 * immutable.
	 * 
	 * @param bytes a byte array
	 * @return the Blob object
	 */
	Blob createBlob(byte[] bytes);

	/**
	 * Utility method to create a <tt>Blob</tt> object from an InputStram using the
	 * hibernate specific implementation. The returned object will be initially
	 * immutable.
	 * 
	 * @param stream a binary stream
	 * @return the Blob object
	 * @throws IOException
	 */
	Blob createBlob(InputStream stream) throws IOException;
	
	/**
	 * Utility method to create a <tt>Blob</tt> object from an InputStram using the
	 * hibernate specific implementation. The returned object will be initially
	 * immutable.
	 * 
	 * @param stream a binary stream
 	 * @param length the number of bytes in the stream
	 * @return the Blob object
	 */
	Blob createBlob(InputStream stream, int length);
}
