// (c) MIT 2003.  All rights reserved.

// -*-Mode: Java-*- 
// $Id: FactBrowser.java,v 1.11 2003/03/06 00:40:39 moltmans Exp $
// FactBrowser.java -- 
// Author: Michael Oltmans <moltmans@ai.mit.edu> 
// Created: <Fri May 12 18:15:30 2000> 
// Time-stamp: <2001-02-02 15:09:00 moltmans> 
package rec.tms.gui;

import javax.swing.*;
import javax.swing.event.*;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.*;
import java.util.*;
import rec.util.*;
import rec.tms.*;
import rec.annotate.lisp.LispTMS;

public class FactBrowser extends JPanel
{
  private JTRE m_jtre;
  private FactFetcher m_fetcher;

  private StringGeneratedJList m_list;
  private StringGenerator m_generator;
  private JTextArea m_text;
  private JCheckBox m_inBox;
  private JCheckBox m_outBox;
  private JTextField m_field;
  private JLabel m_status;

  public FactBrowser( LispTMS jtre )
  {
    DebugWindow.addLine("Lisp", "Not Implimented: FactBrowser");
    
  }

  public FactBrowser( JTRE jtre ) 
  {
    this( jtre, new AllFactFetcher() );
  }
  

  public FactBrowser( JTRE jtre, FactFetcher fetcher ) 
  {
    //    super( jtre.getTitle() );

    m_jtre = jtre;
    m_fetcher = fetcher;

    if( m_generator == null ) {
      m_generator = new StringGenerator() {
	  public String makeString( Object obj ) 
	  {
	    return ((Datum)obj).getFact().toString();
	  }
	};
    }
    
    m_list = new StringGeneratedJList( m_generator );
    m_list.setVisibleRowCount( 8 );

    m_text = new JTextArea( 4, 0);
    m_text.setEditable( false );
    m_text.setLineWrap( true );
    m_text.setWrapStyleWord( true );

    m_status = new JLabel( "Welcome to the fact browser.",
			   SwingConstants.CENTER );
    m_field = new JTextField( 15 );

    JPanel txtPanel = new JPanel();
    txtPanel.add( m_field );
    txtPanel.add( m_status );

    JSplitPane split = new JSplitPane( JSplitPane.VERTICAL_SPLIT,
				       new JScrollPane( m_list ),
				       new JScrollPane( m_text ) );

    setLayout( new BorderLayout() );
    add( split );

    JPanel bottom = new JPanel();
    bottom.setLayout( new GridLayout( 2, 1 ) );
    bottom.add( makeButtons() );
    bottom.add( txtPanel );

    add( bottom, BorderLayout.SOUTH );

    update();
    setupListeners();
  }

  private void setupListeners()
  {
    ListSelectionListener listener = new ListSelectionListener() {
	public void valueChanged( ListSelectionEvent e ) 
	{
	  selected();
	  m_status.setText( "Reasons for fact" );
	}
      };
    m_list.addListSelectionListener( listener );

    ActionListener al = new ActionListener() {
      public void actionPerformed( ActionEvent e ) {
	String txt = m_field.getText();
	if( txt == null ||
	    txt.equals( "" ) ||
	    txt.toLowerCase().equals( "all" ) )
	  m_fetcher = new AllFactFetcher();
	else {
	  m_fetcher = new DBClassFetcher( txt );
	}
	update();
      }
    };
    m_field.addActionListener( al );
  }


  private Datum getSelectedDatum() 
  {
    return (Datum)m_list.getSelectedValue();
  }
  
  private void selected() 
  {
    Datum d = getSelectedDatum();
    if( d == null )
      return;
    Fact f = d.getFact();
    m_text.setText( f.toString() + "\n\n" );
    m_text.setText( f.toEnglish() + "\n" );

    String status;
    if( d.getNode().isIn() )
      status = "IN";
    else
      status = "OUT";
    
    m_text.append( "  State: " + status + "\n" );

    m_text.append( showJustifications( d ) );
  }

  private String showJustifications( Datum d ) 
  {
    StringBuffer result = new StringBuffer();
    Node node = d.getNode();
    if( d.isAssumption() ) {
      return ( "\n because it was assumed by: " +
	       d.getAssumption().toString() );
    }
    
    Collection justs = node.getJustifications();
    Iterator it = justs.iterator();
    while( it.hasNext() ) {
      Justification just = (Justification)it.next();
      result.append( "\n because: " + just.getInformant() );
      Collection antecedents = just.getAntecedents();
      if( antecedents != null ) {
	Iterator antes = antecedents.iterator();
	while( antes.hasNext() ) {
	  Node n = (Node)antes.next();
	  result.append( "\n  " + n.getDatum().getFact() + ": " );
	  if( n.isIn() )
	    result.append( "IN" );
	  else
	    result.append( "OUT" );
	}	
      }
    }

    return result.toString();
  }
  
  private void updateList() 
  {
    Object selected = m_list.getSelectedValue();
    List items = new LinkedList();

    Iterator it = m_fetcher.fetchFacts( m_jtre ).iterator();
    while( it.hasNext() ) {
      Datum d = (Datum)it.next();
      if( ( d.getNode().isIn() && m_inBox.isSelected() ) ||
	  ( d.getNode().isOut() && m_outBox.isSelected() ) )
      {
	items.add( d );
      }
    }
    m_list.setListData( items.toArray() );
    m_list.setSelectedValue( selected, true );
    m_text.setText( "No facts selected" );
    selected();
  }

  private void retract() 
  {
    if( m_list.getSelectedIndex() < 0 )
      return;

    Datum d = getSelectedDatum();
    if( d.isAssumption() ) {
      m_jtre.retract( d.getFact(), d.getAssumption() );
      m_status.setText( "Assumption retracted" );
      update();
    }
    else
      m_status.setText( "Cannot retract a non-assumption" );
  }

  private void assume() 
  {
    if( m_list.getSelectedIndex() < 0 )
      return;

    Datum d = getSelectedDatum();
    if( d.getNode().isAssumption() ) {
      m_jtre.assume( d.getFact(), "USER" );
      m_status.setText( "Fact Assumed" );
      update();
    }
    else
      m_status.setText( "Cannot assume a non-assumption" );
  }
  
  
      
  private JPanel makeButtons() 
  {
    JButton update = new JButton( "Update" );
    JButton retract = new JButton( "Retract" );
    JButton assume = new JButton( "Assume" );

    ActionListener updateListener = new ActionListener() {
      public void actionPerformed( ActionEvent e ) {
	update();
	m_status.setText( "Updated information" );
      }
    };
    update.addActionListener( updateListener );

    ActionListener retractListener = new ActionListener() {
      public void actionPerformed( ActionEvent e ) {
	retract();
      }
    };
    retract.addActionListener( retractListener );

    ActionListener assumeListener = new ActionListener() {
      public void actionPerformed( ActionEvent e ) {
	assume();
      }
    };
    assume.addActionListener( assumeListener );

    m_inBox = new JCheckBox( "Show IN Facts", true );
    m_outBox = new JCheckBox( "Show OUT Facts", false );

    ItemListener boxer = new ItemListener() {
      public void itemStateChanged( ItemEvent e ) {
	update();
      }
    };
    m_inBox.addItemListener( boxer );
    m_outBox.addItemListener( boxer );

    JPanel p = new JPanel();
    p.setLayout( new FlowLayout() );
    p.add( m_inBox );
    p.add( m_outBox );
    p.add( update );
    p.add( retract );
    p.add( assume );
    return p;
  }

  public void update() 
  {
    updateList();
  }

}

class DBClassFetcher implements FactFetcher
{
  private String m_className;

  public DBClassFetcher( String className ) 
  {
    m_className = className;
  }
  public Collection fetchFacts( JTRE jtre )
  {
    return jtre.fetchDatums( m_className );
  }
}

class AllFactFetcher implements FactFetcher
{
  public Collection fetchFacts( JTRE jtre ) 
  {
    return jtre.getAllDatums();
  }
}
