/*
 * RecupWeb.java, 4 févr. 2006
 * 
 * This file is part of FilmZ.
 *
 * Copyright © 2006 Johan Cwiklinski
 *
 * File :               RecupWeb.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.plugins;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.JOptionPane;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.xpath.XPath;

import be.xtnd.commons.MessagesCommons;
import be.xtnd.commons.gui.MainGui;
import be.xtnd.films.gui.Messages;


/**
 * @author Johan Cwiklinski
 *
 */
public abstract class RecupWeb {
	protected String movieName;
	protected String searchUrl;
	protected String formattedUrl;
	protected String REGEX;
	protected Pattern pattern;
	protected Matcher matcher, matcher_second;
	protected static String rmMarks = "<[/]?[^>]+>";
    //
    protected int current;
    protected int results;
    protected Object[][] listeReponses;
    //
    protected String titre = new String();
    protected String titreOriginal = new String();
    protected ArrayList<String> realisateurs = new ArrayList<String>(2);
    protected ArrayList<String> acteurs = new ArrayList<String>(5);
    protected ArrayList<String> origines = new ArrayList<String>(2);
    protected ArrayList<String> genres = new ArrayList<String>(3);
    protected int duree = 0;
    protected int anneeProduction = 0;
    protected int anneeSortie = 0;
    protected String synopsis = new String();
    protected boolean xml = false;
	protected org.jdom.Document document;
	protected Element racine;
	static Logger logger = Logger.getLogger(RecupWeb.class.getName());
   
	/**
	 * Cherche le titre en paramètre
	 * sur un site web
	 * 
	 * @param title titre à chercher
	 * @param searchurl url de recherche
	 * @param regex expression régulière pour le compte des résultats
	 * @param xml true si le résultat d ela recherche est un fichier xml
	 */
	public RecupWeb(String title, String searchurl, String regex, boolean xml){
		PropertyConfigurator.configure(ClassLoader.getSystemResource("be/xtnd/commons/log4j.properties"));
		this.searchUrl = searchurl;
		this.movieName = title;
		this.xml = xml;
		formattedUrl = searchUrl.replace(
				"[word]", 
				encodeUrl(movieName));
		logger.debug("Formatted URL : "+formattedUrl);
		
		if(xml){
    	    SAXBuilder sxb = new SAXBuilder();
    	    try {
    	    	URL url = new URL ( formattedUrl );
    	    	BufferedInputStream  bis = new BufferedInputStream(url.openStream());
    	    	InputStreamReader reader = new InputStreamReader(bis, "ISO-8859-1");
				this.document = sxb.build(reader);
	    	    this.racine = document.getRootElement();
				XPath countDvd = XPath.newInstance("count(//dvd)");
				ArrayList res = (ArrayList) countDvd.selectNodes(racine);
				results  = Float.valueOf(res.get(0).toString()).intValue();
				if(results<1){
					Object[] args = {movieName};
					listeReponses = new Object[1][];
					listeReponses[0] = new Object[]{
							"",
							MessageFormat.format(Messages.getString("window.search.noresults"), args),
							""};					
				}else{
			    	listeReponses = new Object[results][];					
			    	//résultats 1ère page
			    	parseXmlResults();
				}
			} catch (JDOMException e) {e.printStackTrace();
			} catch (UnknownHostException e1){
				listeReponses = new Object[1][];
				listeReponses[0] = new Object[]{
						"",
						Messages.getString("window.search.cantconnect"),
						""};
		    	JOptionPane.showMessageDialog(
		    			MainGui.desktop,
						MessagesCommons.getString("window.messages.unknownhost"),
						MessagesCommons.getString("window.messages.error"),
						JOptionPane.ERROR_MESSAGE
		    	);				
			} catch (IOException e) {e.printStackTrace();}
		}else{
			final StringBuffer data = loadUrl(formattedUrl);
			if(data.toString().equals("-2")){
				listeReponses = new Object[1][];
				listeReponses[0] = new Object[]{
						"",
						Messages.getString("window.search.cantconnect"),
						""};
			}else if(data.toString().equals("-1")){
				Object[] args = {movieName};
				listeReponses = new Object[1][];
				listeReponses[0] = new Object[]{
						"",
						MessageFormat.format(Messages.getString("window.search.noresults"), args),
						""};
			}else{
		    	//nombre de résultats...
				REGEX = regex;
		    	pattern = Pattern.compile(REGEX,Pattern.CASE_INSENSITIVE+Pattern.DOTALL);
		    	matcher = pattern.matcher(data);
		    	while(matcher.find()){
		    		results = new Integer(matcher.group(1));
		    		logger.debug(results+" results found");
		    	}
		    	listeReponses = new Object[results][];
		    	//résultats 1ère page
   		    	parseResults(data);    	
		    	//résultats pages suivantes
               	nextPages(data);
			}
		}
	}
	
	/**
	 * Cherche et traite si besoin est
	 * les pages suivantes des résultats 
	 * 
	 * @param data Données de la page en cours pour recherche du lien
	 * vers la page suivante
	 */
	protected abstract void nextPages(StringBuffer data);
		
	/**
	 * Encode l'url pour la recherche 
	 * 
	 * @param url chaîne à encoder
	 * @return chaîne encodée en iso-8859-1
	 */
	protected String encodeUrl(String url){
		String encoded = null;
		try {
			encoded = URLEncoder.encode(url, "ISO-8859-1");
		} catch (UnsupportedEncodingException e) {e.printStackTrace();}
		return encoded;
	}
	
	/**
	 * Charge une url depuis un site.
	 * 
	 * @param toLoad url à charger
	 * @return StringBuffer contenant le code de la page, 
	 * qui vaudra -1 si aucun résultat n'a été trouvé
	 * lors de la recherche.
	 */
	protected StringBuffer loadUrl(String toLoad){
		logger.debug("Currently loading datas from "+toLoad);
		StringBuffer data = new StringBuffer();
		URL url = null;
		try {
			url = new URL(toLoad);
		} catch (MalformedURLException e) {e.printStackTrace();}
		
	    InputStream stream;
		try {
			stream = url.openStream();
		    
		    int buffer;
		
		    while ((buffer=stream.read())!=-1) {
		    	data.append((char)buffer);
		    }
		    stream.close();
		    
		    if (data.toString().contains("Pas de résultats")) {
		    	logger.debug("No results found");
		    	results = 0;
		    	data = new StringBuffer("-1");
		    }
		} catch (UnknownHostException e1){
			logger.warn("Host unknown"+e1);
	    	JOptionPane.showMessageDialog(
	    			MainGui.desktop,
					MessagesCommons.getString("window.messages.unknownhost"),
					MessagesCommons.getString("window.messages.error"),
					JOptionPane.ERROR_MESSAGE
	    	);				
	    	return new StringBuffer("-2");
		} catch (IOException e) {
			logger.error("IOException "+e);
			e.printStackTrace();
		} 
		
		return data;
	}

	/**
	 * Parcours les résultats du fichier XML et les stocke
	 * dans un Object[][] pour l'affichage ultérieur dans
	 * une JTable
	 */
	protected void parseXmlResults(){}
	
	/**
	 * Parcours les résultats de la liste et les stocke
	 * dans un Object[][] pour l'affichage ultérieur dans
	 * une JTable
	 * 
	 * @param data données à parser
	 */
	protected abstract void parseResults(StringBuffer data);

	protected void loadNewMovie(String url){
		MainGui.attente(true);
		this.titre = "";
		this.titreOriginal = "";
		this.realisateurs = new ArrayList<String>(2);
		this.acteurs = new ArrayList<String>(5);
		this.anneeSortie = 0;
		this.anneeProduction = 0;
		this.origines = new ArrayList<String>(2);
		this.genres = new ArrayList<String>(3);
		this.duree = 0;
		this.synopsis = "";
		loadMovie(url);
		MainGui.attente(false);
	}
	
	/**
	 * Charge la page des détails d'un film
	 * 
	 * @param url page du film à charger, récupérée normalement
	 * dans la liste des résultats de recherche
	 */
	protected abstract void loadMovie(String url);

	
	/**
	 * Charge la page de casting du film,
	 * récupère et stocke les acteurs dans un 
	 * ArrayList
	 *  
	 * @param url url de la page casting
	 */
	protected abstract void loadActors(String url);
	
	/**
	 * @return Renvoie listeReponses.
	 */
	public Object[][] getListeReponses() {
		return listeReponses;
	}

	/**
	 * @return Renvoie results.
	 */
	public int getResults() {
		return results;
	}

	/**
	 * @return Renvoie acteurs.
	 */
	public ArrayList<String> getActeurs() {
		acteurs.trimToSize();
		return acteurs;
	}

	/**
	 * @return Renvoie anneeProduction.
	 */
	public int getAnneeProduction() {
		return anneeProduction;
	}

	/**
	 * @return Renvoie anneeSortie.
	 */
	public int getAnneeSortie() {
		return anneeSortie;
	}

	/**
	 * @return Renvoie duree.
	 */
	public int getDuree() {
		return duree;
	}

	/**
	 * @return Renvoie genre.
	 */
	public ArrayList<String> getGenres() {
		genres.trimToSize();
		return genres;
	}

	/**
	 * @return Renvoie origine.
	 */
	public ArrayList<String> getOrigines() {
		origines.trimToSize();
		return origines;
	}

	/**
	 * @return Renvoie realisateur.
	 */
	public ArrayList<String> getRealisateurs() {
		realisateurs.trimToSize();
		return realisateurs;
	}

	/**
	 * @return Renvoie synopsis.
	 */
	public String getSynopsis() {
		return synopsis;
	}

	/**
	 * @return Renvoie titre.
	 */
	public String getTitre() {
		return titre;
	}

	/**
	 * @return Renvoie titreOriginal.
	 */
	public String getTitreOriginal() {
		return titreOriginal;
	}

}