/*
 * Film.java, 9 sept. 2005
 * 
 * This file is part of FilmZ.
 *
 * Copyright © 2005 Johan Cwiklinski
 *
 * File :               Film.java
 * Author's email :     johan@x-tnd.be
 * Author's Website :   http://www.x-tnd.be/
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 */

package be.xtnd.films;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import be.xtnd.commons.db.Database;
import be.xtnd.gui.FilmzMain;


/**
 * @author Johan Cwiklinski
 * @version 1.1
 */
public class Film {
	private static Database database;
	private String titre, sous_titre, resume;
	private Integer id, annee, duree, cd;

	private ArrayList<Realisateur> realisateurs;
	private ArrayList<Integer> deletedDirectors = new ArrayList<Integer>();
	
	//private boolean special;

	private ArrayList<Acteur> acteurs;
	private ArrayList<Integer> deletedActors = new ArrayList<Integer>();

	private ArrayList<Genre> genres;
	private ArrayList<Integer> deletedTypes = new ArrayList<Integer>();

	private ArrayList<Origine> origines;
	private ArrayList<Integer> deletedOrigins = new ArrayList<Integer>();
	/* variables bdd */
	private static String sqlMessage;
	private static int sqlError = 0;
	private int affectedRows;
	/* CONSTANTES */
	/** Nom de la table des films */
	public static String TABLE;
	//public static final String TABLE = "divx";
	/** Nom de la table des films spéciaux */
	//public static final String TABLE_SPECIALS = "specials";
	/** Clé primaire de la table des films */
	public static final String PK = "id_film";
	/** Requête de liste des films non ordonnée */
	public static String BASE_LIST_QUERY;
	/** Clause grouby (non spéciaux) */
	public static String GROUP_BY;
	/** Clause grouby (spéciaux) */
	//public static final String GROUP_BY_SPECIALS = " GROUP BY "+TABLE_SPECIALS+"."+PK;
	/** Clause Order by */
	public static final String ORDER_BY = " ORDER BY titre, genre ASC";
	/** Requête de liste des films ordonnée */
	public static String LIST_QUERY;
	/** Requête de liste des films spéciaux non ordonnée */
	/*public final static String BASE_LIST_QUERY_SPECIALS = "SELECT "+TABLE_SPECIALS+"."+PK+" As Num, titre As Titre, sous_titre As Sous_Titre, " +
		"spe_genres.genre As Genre, cd As CD FROM "+TABLE_SPECIALS+
		" INNER JOIN spe_divxgenres ON("+TABLE_SPECIALS+"."+PK+"=spe_divxgenres."+PK+")" + 
		" INNER JOIN spe_genres ON(spe_divxgenres.id_genre=spe_genres.id_genre)";*/
	/** Requête de liste des films spéciaux ordonnée */
	//public final static String LIST_QUERY_SPECIALS = BASE_LIST_QUERY_SPECIALS+GROUP_BY_SPECIALS+ORDER_BY;
	static Logger logger = Logger.getLogger(Film.class.getName());
	
	/**
	 * Construit un film vide
	 */
	public Film(){
		//super();
		TABLE = FilmzMain.collection.getTable();
		initConstants();
		PropertyConfigurator.configure(ClassLoader.getSystemResource("be/xtnd/films/log4j.properties"));
		database = FilmzMain.db;
		this.titre = "";
		this.sous_titre = "";
		//this.special = spe;
		this.annee = new Integer(0);
		this.resume = "";
		this.duree = new Integer(0);
		this.cd = new Integer(1);

		this.realisateurs = new ArrayList<Realisateur>();
		this.realisateurs.add(new Realisateur(Realisateur.UNKNOWN));
		this.genres = new ArrayList<Genre>();
		this.genres.add(new Genre(Genre.UNKNOWN));
		this.origines = new ArrayList<Origine>();
		this.origines.add(new Origine(Origine.UNKNOWN));
		this.acteurs = new ArrayList<Acteur>();
	}
	
	/**
	 * Construit un film en fonction de l'id passée en paramètre
	 * @param id identifiant du film à initialiser
	 */
	public Film(Integer id){
		//super();
		TABLE = FilmzMain.collection.getTable();
		initConstants();
		PropertyConfigurator.configure(ClassLoader.getSystemResource("be/xtnd/commons/log4j.properties"));
		this.id = id;
		String query = null;
		/*if(special)
			query = "SELECT * FROM "+TABLE_SPECIALS+" WHERE "+PK+"="+id;
		else*/
			query = "SELECT * FROM "+TABLE+" WHERE "+PK+"="+id;
		database = FilmzMain.db;
		try {
			ResultSet rs = database.execQuery(query);
			rs.first();
			this.titre = rs.getString("titre");
			this.sous_titre = rs.getString("sous_titre");
			this.annee = new Integer(rs.getInt("annee"));
			this.resume = rs.getString("resume");
			this.duree = new Integer(rs.getInt("duree"));
			this.cd = new Integer(rs.getInt("cd"));
			
			this.realisateurs = Realisateur.realisateursFilm(id);
			this.genres = Genre.genresFilm(id);
			this.origines = Origine.originesFilm(id);
			this.acteurs = Acteur.acteursFilm(id);
		} catch (SQLException e) {
			logger.fatal("SQLException initializing movie by id : "+e.getMessage()+" (code "+e.getErrorCode()+")");
			sqlMessage = "Message was : "+e.getMessage();
			sqlError = e.getErrorCode();
		}
	}
	
	private void initConstants(){
		BASE_LIST_QUERY = "SELECT "+TABLE+"."+PK+" As Num, titre As Titre, sous_titre As Sous_Titre, " +
			"genres.genre As Genre, cd AS CD FROM "+TABLE+
			" INNER JOIN "+TABLE+"genres ON("+TABLE+"."+PK+"="+TABLE+"genres."+PK+")" + 
			" INNER JOIN genres ON("+TABLE+"genres.id_genre=genres.id_genre)";
		GROUP_BY = " GROUP BY "+TABLE+"."+PK;
		LIST_QUERY = BASE_LIST_QUERY+GROUP_BY+ORDER_BY;
	}
	
	/**
	 * Cherche le dernier id entré
	 * @throws NullPointerException
	 * @return dernier id entré
	 */
	public int getMax() throws NullPointerException{
		int max = 0;
		try {
			String query = null;
			/*if(special)
				query = "SELECT MAX("+PK+") As max FROM "+TABLE_SPECIALS;
			else*/
				query = "SELECT MAX("+PK+") As max FROM "+TABLE;
			ResultSet rs = database.execQuery(query);
			rs.first();
			max = rs.getInt("max");
		} catch (SQLException e) {
			logger.fatal("SQLException searching last movie id : "+e.getMessage()+" (code "+e.getErrorCode()+")");
			sqlMessage = "Message was : "+e.getMessage();
			sqlError = e.getErrorCode();
		}
		return max;
	}
	
	/**
	 * Compte le nombre de films enregistrés dans la base
	 * 
	 * @return integer compte 
	 */
	public static Integer countFilms(){
		int count = -1;
		try{
			String query = "SELECT count("+PK+") as compte FROM "+TABLE;
			ResultSet rs = database.execQuery(query);
			rs.first();
			count = rs.getInt("compte");
		}catch(SQLException e){
			logger.fatal("SQLException counting movies : "+e.getMessage()+" (code "+e.getErrorCode()+")");
			sqlMessage = "Message was : "+e.getMessage();
			sqlError = e.getErrorCode();
		}
		
		return count;
	}

	/**
	 * Supprime un film
	 * @param id identifiant du film à supprimer
	 * @return entier résultat
	 */
	public int delete(Integer id){
		int result=0;
		try {
			String query = null;
			/*if(special)
				query ="DELETE FROM "+TABLE_SPECIALS+" WHERE "+PK+"="+id;
			else*/
				query = "DELETE FROM "+TABLE+" WHERE "+PK+"="+id;
			result = database.execUpdate(query);
		} catch (SQLException e) {
			logger.fatal("SQLException deleting movie : "+e.getMessage()+" (code "+e.getErrorCode()+")");
			sqlMessage = "Message was : "+e.getMessage();
			sqlError = e.getErrorCode();
		}
		return result;	
	}
	
	/**
	 * Enregistre le film
	 * @param nouveau true s'il s'agit d'un nouvel enregistrement, false en cas de modification
	 */
	public void enregistrer(boolean nouveau){
		String query = new String();
		/*String the_table = null;
		if(special)
			the_table = TABLE_SPECIALS;
		else
			the_table = TABLE;*/
		if(nouveau){
			this.id = getMax()+1;
			query = "INSERT INTO "+TABLE+" VALUES("+
					this.id+", " +
					"'" + Database.replace(this.titre,"\'","\\\'") + "', " +
					"'" + Database.replace(this.sous_titre, "\'","\\\'") + "', " +
					this.annee + ", " +
					"'" + Database.replace(this.resume,"\'","\\\'") +"', " +
					this.duree + ", " +
					this.cd + //", " +
					")";
		}else{
			query = "UPDATE "+TABLE+" SET " +
				"titre='" + Database.replace(this.titre,"\'","\\\'") + "', " +
				"sous_titre='" + Database.replace(this.sous_titre, "\'","\\\'") + "', " +
				"annee=" + this.annee + ", " +
				"resume='" + Database.replace(this.resume,"\'","\\\'") +"', " +
				"duree=" + this.duree + ", " +
				"cd=" + this.cd + //", " +
				" WHERE " + PK + "=" + this.id;
		}
		try{
			affectedRows = database.execUpdate(query);
			new Acteur().enregistrerActeurs(this);
			new Genre().enregistrerGenres(this);
			new Origine().enregistrerOrigines(this);
			new Realisateur().enregistrerRealisateurs(this);
		}catch(SQLException e){
			logger.fatal("SQLException storing movie (new="+nouveau+") : "+e.getMessage()+" (code "+e.getErrorCode()+")");
			sqlMessage = "Message was : "+e.getMessage();
			sqlError = e.getErrorCode();
		}
	}

	/**
	 * Ajoute un acteur au tableau pour ce film
	 * @param act acteur à ajouter
	 */
	public void ajouteActeur(Acteur act){
		this.acteurs.add(act);
		if(deletedActors.contains(act.getId())){
			deletedActors.remove(deletedActors.indexOf(act.getId()));
		}
	}

	/**
	 * Ajoute un genre au tableau pour ce film
	 * @param gen genre à ajouter
	 */
	public void ajouteGenre(Genre gen){
		this.genres.add(gen);
		if(deletedTypes.contains(gen.getId())){
			deletedTypes.remove(deletedTypes.indexOf(gen.getId()));
		}
	}

	/**
	 * Ajoute un réalisateur au tableau pour ce film
	 * @param rea réalisateur à ajouter
	 */
	public void ajouteRealisateur(Realisateur rea){
		this.realisateurs.add(rea);
		if(deletedDirectors.contains(rea.getId())){
			deletedDirectors.remove(deletedDirectors.indexOf(rea.getId()));
		}
	}

	/**
	 * Ajoute une origine au tableau pour ce film
	 * @param ori origine à ajouter
	 */
	public void ajouteOrigine(Origine ori){
		this.origines.add(ori);
		if(deletedOrigins.contains(ori.getId())){
			deletedOrigins.remove(deletedOrigins.indexOf(ori.getId()));
		}
	}
	
	/**
	 * Supprime un acteur du tableau.
	 * L'ajoute au tableau de suppression pour effacer
	 * sa relation avec le film de la base 
	 * @param index index de l'acteur à supprimer
	 */
	public void supprimeActeur(Integer index){
		deletedActors.add(index);
		
		for ( Iterator it = acteurs.iterator(); it.hasNext(); ) {
			Acteur ac = (Acteur)it.next();
			if(ac.getId().equals(index))
				it.remove();
		}
	}

	/**
	 * Supprime tous les acteurs du tableau.
	 * Les ajoute au tableau de suppression pour effacer
	 * leur relation avec le film de la base 
	 */
	public void supprimeActeurs(){
		for ( Iterator it = acteurs.iterator(); it.hasNext(); ) {
			Acteur ac = (Acteur)it.next();
			deletedActors.add(ac.getId());
			it.remove();
		}
	}

	/**
	 * Supprime un genre du tableau.
	 * L'ajoute au tableau de suppression pour effacer
	 * sa relation avec le film de la base 
	 * @param index index du genre à supprimer
	 */
	public void supprimeGenre(Integer index){
		deletedTypes.add(index);
		
		for ( Iterator it = genres.iterator(); it.hasNext(); ) {
			Genre ge = (Genre)it.next();
			if(ge.getId().equals(index))
				it.remove();
		}
	}

	/**
	 * Supprime tous les genres du tableau.
	 * Les ajoute au tableau de suppression pour effacer
	 * leur relation avec le film de la base 
	 */
	public void supprimeGenres(){
		for ( Iterator it = genres.iterator(); it.hasNext(); ) {
			Genre ge = (Genre)it.next();
			deletedTypes.add(ge.getId());
			it.remove();
		}
	}
	
	/**
	 * Supprime un réalisateur du tableau.
	 * L'ajoute au tableau de suppression pour effacer
	 * sa relation avec le film de la base 
	 * @param index index du réalisateur à supprimer
	 */
	public void supprimeRealisateur(Integer index){
		deletedDirectors.add(index);
		
		for ( Iterator it = realisateurs.iterator(); it.hasNext(); ) {
			Realisateur re = (Realisateur)it.next();
			if(re.getId().equals(index))
				it.remove();
		}
	}

	/**
	 * Supprime tous les réalisateurs du tableau.
	 * Les ajoute au tableau de suppression pour effacer
	 * leur relation avec le film de la base 
	 */
	public void supprimeRealisateurs(){
		for ( Iterator it = realisateurs.iterator(); it.hasNext(); ) {
			Realisateur re = (Realisateur)it.next();
			deletedDirectors.add(re.getId());
			it.remove();
		}
	}
	
	/**
	 * Supprime une origine du tableau.
	 * L'ajoute au tableau de suppression pour effacer
	 * sa relation avec le film de la base 
	 * @param index index de l'origine à supprimer
	 */
	public void supprimeOrigine(Integer index){
		deletedOrigins.add(index);
		
		for ( Iterator it = origines.iterator(); it.hasNext(); ) {
			Origine or = (Origine)it.next();
			if(or.getId().equals(index))
				it.remove();
		}
	}

	/**
	 * Supprime toues les origines du tableau.
	 * Les ajoute au tableau de suppression pour effacer
	 * leur relation avec le film de la base 
	 */
	public void supprimeOrigines(){
		for ( Iterator it = origines.iterator(); it.hasNext(); ) {
			Origine or = (Origine)it.next();
			deletedOrigins.add(or.getId());
			it.remove();
		}
	}

	/**
	 * @return Renvoie acteurs.
	 */
	public ArrayList<Acteur> getActeurs() {
		if(acteurs.size()>0)
			acteurs.trimToSize();
		return acteurs;
	}
	/**
	 * @param acteurs acteurs à définir.
	 */
	public void setActeurs(ArrayList<Acteur> acteurs) {
		this.acteurs = acteurs;
		if(this.acteurs.size()>0)
			this.acteurs.trimToSize();
	}
	/**
	 * @return Renvoie annee.
	 */
	public Integer getAnnee() {
		return annee;
	}
	/**
	 * @param annee annee à définir.
	 */
	public void setAnnee(Integer annee) {
		this.annee = annee;
	}
	/**
	 * @return Renvoie cd.
	 */
	public Integer getCd() {
		return cd;
	}
	/**
	 * @param cd cd à définir.
	 */
	public void setCd(Integer cd) {
		this.cd = cd;
	}
	/**
	 * @return Renvoie duree.
	 */
	public Integer getDuree() {
		return duree;
	}
	/**
	 * @param duree duree à définir.
	 */
	public void setDuree(Integer duree) {
		this.duree = duree;
	}
	/**
	 * @return Renvoie genre.
	 */
	public ArrayList<Genre> getGenres() {
		return genres;
	}
	/**
	 * @param genres genre à définir.
	 */
	public void setGenres(ArrayList<Genre> genres) {
		this.genres = genres;
	}
	/**
	 * @return Renvoie id.
	 */
	public Integer getId() {
		return id;
	}
	/**
	 * @param id id à définir.
	 */
	public void setId(Integer id) {
		this.id = id;
	}
	/**
	 * @return Renvoie origine.
	 */
	public ArrayList<Origine> getOrigines() {
		return origines;
	}
	/**
	 * @param origines origine à définir.
	 */
	public void setOrigines(ArrayList<Origine> origines) {
		this.origines = origines;
	}
	/**
	 * @return Renvoie realisateur.
	 */
	public ArrayList<Realisateur> getRealisateurs() {
		return realisateurs;
	}
	/**
	 * @param realisateurs realisateur à définir.
	 */
	public void setRealisateurs(ArrayList<Realisateur> realisateurs) {
		this.realisateurs = realisateurs;
	}
	/**
	 * @return Renvoie resume.
	 */
	public String getResume() {
		return resume;
	}
	/**
	 * @param resume resume à définir.
	 */
	public void setResume(String resume) {
		this.resume = resume;
	}
	/**
	 * @return Renvoie sous_titre.
	 */
	public String getSous_titre() {
		return sous_titre;
	}
	/**
	 * @param sous_titre sous_titre à définir.
	 */
	public void setSous_titre(String sous_titre) {
		this.sous_titre = sous_titre;
	}
	/**
	 * @return Renvoie titre.
	 */
	public String getTitre() {
		return titre;
	}
	/**
	 * @param titre titre à définir.
	 */
	public void setTitre(String titre) {
		this.titre = titre;
	}

	/**
	 * @return Renvoie special.
	 */
	/*public boolean isSpecial() {
		return special;
	}*/

	/**
	 * @return Renvoie sqlMessage.
	 */
	public String getSqlMessage() {
		return sqlMessage;
	}

	/**
	 * @param message message à définir.
	 */
	public void setSqlMessage(String message) {
		sqlMessage = message;
	}

	/**
	 * @return Renvoie affectedRows.
	 */
	public int getAffectedRows() {
		return affectedRows;
	}

	/**
	 * @return Renvoie sqlError.
	 */
	public int getSqlError() {
		return sqlError;
	}

	/**
	 * @return Renvoie deletedActors.
	 */
	public ArrayList<Integer> getDeletedActors() {
		return deletedActors;
	}

	/**
	 * @return Renvoie deletedTypes.
	 */
	public ArrayList<Integer> getDeletedTypes() {
		return deletedTypes;
	}

	/**
	 * @return Renvoie deletedDirectors.
	 */
	public ArrayList<Integer> getDeletedDirectors() {
		return deletedDirectors;
	}

	/**
	 * @return Renvoie deletedOrigins.
	 */
	public ArrayList<Integer> getDeletedOrigins() {
		return deletedOrigins;
	}
}
