import java.util.Iterator;
import OclCollections.*;
import static OclCollections.Collections.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

/** Mise en oeuvre de l'analyseur XML avec la bibliotheque
 * d'expressions regulieres de Java.
 */

public class AnalyseurXMLAvecRegex implements AnalyseurXML {

    private boolean DEBUG = false;
  
    private Set<InfoBalise> balises;
    private FabriqueInfoBalise fabriqueIB;
    
    public AnalyseurXMLAvecRegex( FabriqueInfoBalise fabriqueIB ) {
	this.fabriqueIB = fabriqueIB;
	reinitialiser();
    }

    public void reinitialiser() {
	balises = emptySet();
    }

    public void analyser( final Sequence<String> s ) {
	for ( String ligne: s ) {
	    analyserLigne( ligne );
	}
    }

    public Set<String> balises() {
	return balises
	    .collect( new Expression<InfoBalise,String>() {
		public String eval( InfoBalise ib ) {
		    return ib.balise();
		} } )
	    .asSet();
    }

    public InfoBalise info( final String balise ) {
	assert baliseDefinie( balise );

	return 
	    balises
	    .any( new Expression<InfoBalise,Boolean>() {
		public Boolean eval( InfoBalise ib ) {
		    return ib.balise().equals( balise );
		} } );
    }


    /************************************************************
     * Methodes privees auxiliaires.
     ************************************************************/

    /** Analyse une chaine (ligne) pour identifier les diverses balises et attributs. 
     *
     * @param s la chaine a analyser
     */
    private void analyserLigne( String s ) { 
	Pattern patronBalise 
	    = Pattern.compile( "(</?(\\w+)\\s*(\\s*(\\w+)\\s*=\\s*\"\\w+\"\\s*)*\\s*/?>)" );
	Matcher matcherPatron
	    = patronBalise.matcher( s );

	while( matcherPatron.find() ) {
	    analyserBalise( matcherPatron.group(2), matcherPatron.group(1) );
	}
    }

    /** Analyse une chaine representant une balise pour identifier les attributs.
     * @param s la chaine a analyser
     */
    private void analyserBalise( String balise, String chaine ) {
	InfoBalise ib;

	if ( baliseDefinie(balise) ) {
	    // Existe deja: On la reutilise.
	    ib = info( balise ); 
	} else {
	    // N'existe pas: on la cree.
	    ib = fabriqueIB.creer( balise );
	    balises = balises.including( ib );
	}

	Pattern patronAttribut 
	    = Pattern.compile( "(\\w+)\\s*=\\s*\"\\w+\"" );
	Matcher matcherAttribut
	    = patronAttribut.matcher( chaine );

	while( matcherAttribut.find() ) {
	    ib.ajouterAttribut( matcherAttribut.group(1) );
	}
    }

    private boolean baliseDefinie( final String balise ) {
	return 
	    balises
	    .exists( new Expression<InfoBalise,Boolean>() {
		public Boolean eval( InfoBalise ib ) {
		    return ib.balise().equals( balise );
		} } );
    }
	    
}
