package prolog.implementation;

import java.io.*;
import java.util.*;
import prolog.model.*;
import prolog.util.*;
import prolog.*;

/**
 * <p>The statementmap stores statements under their name.
 * It is a collection with statements but for faster access from
 * the interpreter, they are stored in a map to prevent iterations.</p>
 */
public class StatementMap
	implements IStatementMap
{
	/**
	 * list of registered listeners
	 */
	protected List listeners = new Vector(0);

	/**
	 * storing the statements
	 */
	protected Map statements = new HashMap();

	/**
	 * create a satementmap
	 */
	public StatementMap()
	{
	}

	/**
	 * clears the statement map
	 */
	public void clear()
	{
		statements.clear();
		this.fireChange();
	}

	/**
	 * adds a statement to the statementmap
	 */
	public void addStatement( IStatement statement )
	{
		this.statements.put( new Value( statement.getName() ), statement );
		this.fireChange();
	}

	/**
	 * returns a iterator over all stored statements
	 */
	public Iterator getStatements()
	{
		return statements.values().iterator();
	}

	/**
	 * returns the statement for the given name
	 * @param key is the name
	 * @return a statement if one was found ;-)
	 */
	public IStatement getStatement( int key )
	{
		return (IStatement) statements.get( new Value( key ) );
	}

	/**
	 * returns a statement matching the given fact, if one was found.
	 */
	public IStatement getMatchingStatement( IFact fact )
	{
		IStatement s = getStatement( fact.getName() );
		if( s != null )
		{ // check param count
			if(
				s.getRelation().getValueCount() !=
				fact.getRelation().getValueCount() )
			{
				s = null;
			}
		}

		return s;
	}

	/**
	 * returns a string representation
	 */
	public String toString()
	{
		return toString( null );
	}

	/**
	 * returns a string representation with decoded symbols
	 * @param table
	 * @return
	 */
	public String toString( ISymbolTable table )
	{
		StringBuffer out = new StringBuffer();
		out.append( "statementmap:\n" );
		Iterator i = statements.keySet().iterator();
		while( i.hasNext() )
		{
			Object key = i.next();
			out.append( "\t" );
			if( table != null )
				out.append( ((IStatement)statements.get( key )).toString( table ) );
			else
				out.append( statements.get( key ) );
			out.append( "\n" );
		}

		return out.toString();
	}

	/**
	 * generates a xml representation with decoded symbols
	 * @param out
	 * @param table
	 * @throws IOException
	 */
	public void genXml( Writer out, ISymbolTable table )
		throws IOException
	{
		out.write( "<statementmap>" );
		Iterator i = statements.keySet().iterator();
		while( i.hasNext() )
		{
			Object key = i.next();
			out.write( "\t<statement>" );
			((IStatement)statements.get( key )).genXml( out, table );
			out.write( "</statement>" );
		}
		out.write( "</statementmap>" );
	}

	/**
	 * registers a listener
	 */
	public void addListener( IStatementMapListener l )
	{
		listeners.add( l );
	}

	/**
	 * removes a listener
	 */
	public void removeListener( IStatementMapListener l )
	{
		listeners.remove( l );
	}

	/**
	 * fire a content changed notify
	 */
	protected void fireChange()
	{
		Iterator i = listeners.iterator();
		while( i.hasNext() )
			((IStatementMapListener)i.next()).onStatementsChanged();;
	}
}
