package prolog.ui;

import java.io.*;
import java.util.*;
import java.awt.*;
import javax.swing.*;
import prolog.model.*;
import prolog.demonstration.*;
import prolog.implementation.*;

public class FactDbRenderer
	implements
		IFactDbListener,
		IStatementMapListener,
		IQueryListListener
{
	protected FactListRenderer renderer = null;
	protected JComponent container = null;
	protected IFactDb db = null;
	protected ISymbolTable symbolTable = null;
	protected StatementMap statementMap = null;
	protected QueryList queryList = null;

	protected Rectangle rect = new Rectangle( 0, 0, 0, 0 );

	public FactDbRenderer()
	{
	}

	public void onFactDbChanged()
	{
		if( container != null )
		{
			container.doLayout();
			container.repaint();
		}
	}

	public void onFactListAdded( IFactList l )
	{
		if( container != null )
		{
			container.doLayout();
			container.repaint();
		}
	}

	public void onRelationAdded( IRelation r, int name )
	{
		if( container != null )
		{
			container.doLayout();
			container.repaint();
		}
	}

	public void onStatementsChanged()
	{
		if( container != null )
		{
			container.doLayout();
			container.repaint();
		}
	}

	public void onQueriesChanged()
	{
		if( container != null )
		{
			container.doLayout();
			container.repaint();
		}
	}

	public void setQueryList( QueryList list )
	{
		if( this.queryList != null )
			this.queryList.removeListener( this );
		this.queryList = list;
		if( this.queryList != null )
			this.queryList.addListener( this );
	}

	public QueryList getQueryList()
	{
		return queryList;
	}

	public void setStatementMap( StatementMap map )
	{
		if( this.statementMap != null )
			this.statementMap.removeListener( this );
		this.statementMap = map;
		if( this.statementMap != null )
			this.statementMap.addListener( this );
	}

	public StatementMap getStatementMap()
	{
		return this.statementMap;
	}


	public void setPosition( Rectangle r )
	{
		this.rect = r;
	}

	public Rectangle getPosition()
	{
		return this.rect;
	}

	public void setContainer( JComponent c )
	{
		this.container = c;
	}

	public JComponent getContainer()
	{
		return this.container;
	}

	public void repaint()
	{
		if( this.container != null )
			this.container.repaint();
	}

	public void setSymbolTable( ISymbolTable t )
	{
		symbolTable = t;
		this.renderer = new FactListRenderer( symbolTable );
	}

	public void setDb( IFactDb db )
	{
		if( this.db != null && this.db instanceof FactDb )
		   ((FactDb)this.db).removeListener( this );
		this.db = db;
		if( this.db != null && this.db instanceof FactDb  )
		   ((FactDb)this.db).addListener( this );
	}

	public IFactDb getDb()
	{
		return this.db;
	}

	public void paint( Graphics2D g )
	{
		g.setColor( Color.lightGray );
		g.fillRect( rect.x, rect.y, rect.width, rect.height );
		int y = rect.y + 10;
		int x = rect.x + 10;

		// paint fact lists
		Iterator i = this.db.getFactLists();
		while( i.hasNext() )
		{
			IFactList fl = (IFactList)i.next();
			Dimension d = renderer.getDimension( fl );
			renderer.render( g, new Rectangle( x, y, d.width, d.height ), fl );
			y += d.height + 5;
		}

		// paint statements
		i = this.statementMap.getStatements();
		while( i.hasNext() )
		{
			IStatement s = (IStatement) i.next();
			UiUtil.paintCell(
				g,
				new Rectangle( x, y, rect.width - 20, 20 ),
				s.toString( this.symbolTable ),
				Color.green,
				Color.darkGray );
			y += 25;
		}

		// paint queries
		i = this.queryList.getQueries();
		while( i.hasNext() )
		{
			IFact s = (IFact) i.next();
			UiUtil.paintCell(
				g,
				new Rectangle( x, y, rect.width - 20, 20 ),
				s.toString( this.symbolTable ),
				Color.red,
				Color.darkGray );
			y += 25;
		}
	}

	public int getWidth()
	{
		Iterator i = this.db.getFactLists();
		int width = 0;
		while( i.hasNext() )
		{
			IFactList fl = (IFactList)i.next();
			Dimension d = renderer.getDimension( fl );
			if( width < d.width + 20 )
				width = d.width + 20;
		}

		return width;
	}

	public int getHeight()
	{
		Iterator i = this.db.getFactLists();
		int height = 0;
		while( i.hasNext() )
		{
			IFactList fl = (IFactList)i.next();
			Dimension d = renderer.getDimension( fl );
			height += d.height;
			if( i.hasNext() )
				height += 5;
		}

		i = this.statementMap.getStatements();
		while( i.hasNext() )
		{
			IStatement s = (IStatement) i.next();
			height += 25;
		}

		i = this.queryList.getQueries();
		while( i.hasNext() )
		{
			IFact s = (IFact) i.next();
			height += 25;
		}

		return height;
	}

	public Dimension getPreferredSize()
	{
		return new Dimension(
			getWidth() + 20,
			getHeight() + 20 );
	}
}
