package prolog.implementation;

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

/**
 * <p>this is the base implementation for a relation with a name.</p>
 * <p>prolog:  myFact(dan,joe).</p>
 * <p>in this example, "myFact" is the name and the parameters "dan" and "joe"
 * are the atoms in the relation.</p>
 */
public class Fact
	implements IFact
{
	/**
	 * the relation contained in this fact
	 */
	protected Relation relation = null;

	/**
	 * the name of this fact
	 */
	protected int name = -1;

	/**
	 * constructor
	 * @param name
	 */
	public Fact( int name )
	{
		this.name = name;
		this.relation = (Relation) SingletonFactory.getBuilder().createRelation();
	}

	/**
	 * copy constructor
	 * @param f
	 */
	public Fact( IFact f )
	{
		if( f == null )
			throw new RuntimeException(
				"INTERNAL MACHINE ERROR: Fact.copyconstructor failed! "+
				"Can not copy a null fact!" );

		this.name = f.getName();
		this.relation = new Relation( f.getRelation() );
	}

	/**
	 * constructor
	 * @param name
	 * @param r
	 */
	public Fact( int name, IRelation r )
	{
		if( r == null )
			throw new RuntimeException(
				"INTERNAL MACHINE ERROR: Fact.constructor2 failed! "+
				"Can not create fact without relation!" );

		this.name = name;
		this.relation = (Relation)r;
	}

	/**
	 * adds a IAtom to this fact's relation
	 * @param value - a IAtom
	 */
	public void addAttribute( Object value )
	{
		if( value == null )
			throw new RuntimeException(
				"INTERNAL MACHINE ERROR: Fact.addAttribute failed! "+
				"Can not add null value!" );

		if( ! (value instanceof IAtom ) )
			throw new RuntimeException(
				"INTERNAL MACHINE ERROR: Fact.addAttribute failed! "+
				"Can not add a value that is not a IAtom!" );

		relation.add( value );
	}

	/**
	 * @return the name of this fact
	 */
	public int getName()
	{
		return this.name;
	}

	/**
	 * @return the values of this fact
	 */
	public IRelation getRelation()
	{
		return relation;
	}

	/**
	 * @return a string representation of this fact
	 */
	public String toString()
	{
		return toString( null );
	}

	/**
	 * @param table the symboltable used to decode the symbols
	 * @return a string representation of this fact with decoded symbols
	 */
	public String toString( ISymbolTable table )
	{
		StringBuffer out = new StringBuffer();

		if( table != null )
			out.append( table.decode( getName() ) );
		else
			out.append( getName() );
		out.append( "(" );
		if( table != null )
			out.append(
				StringBuilder.buildSymbolDecoded(
					getRelation().getValues(),
					",",
					table ) );
		else
			out.append(
				StringBuilder.build(
					getRelation().getValues(),
					"," ) );
		out.append( ")" );
		return out.toString();
	}

	/**
	 * generates xml representing this object
	 * @param out
	 * @param table
	 * @throws IOException
	 */
	public void genXml( Writer out, ISymbolTable table )
		throws IOException
	{
		out.write( "<fact class=\"" );
		out.write( getClass().getName() );
		out.write( "\">" );
		out.write( "<name>" );
		if( table != null )
			out.write( table.decode( getName() ) );
		else
			out.write( getName() );
		out.write( "</name>" );
		out.write( "<parameters>" );
		Iterator i = getRelation().getValues();
		while( i.hasNext() )
		{
			out.write( "<parameter>" );
			if( table != null )
				out.write( table.decode( (IAtom) i.next() ) );
			else
				out.write( i.next().toString() );
			out.write( "</parameter>" );
		}
		out.write( "</parameters>" );

		out.write( "</fact>" );
	}
}
