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

// -*-Mode: Java-*- 
// $Id: JTMS.java,v 1.6 2003/03/06 00:40:39 moltmans Exp $
// JTMS.java -- 
// Author: Michael Oltmans <moltmans@ai.mit.edu> 
// Created: <Wed Apr 26 16:46:30 2000> 
// Time-stamp: <2000-05-13 18:15:43 moltmans> 
package rec.tms;

import java.util.*;
import rec.util.*;

/*   This code is adpabted from the lisp version by:
 *     Kenneth D. Forbus, Northwestern University
 *     Johan de Kleer, the Xerox Corportation.
 *  
 *  Copyright (c) 1986-1992, Kenneth D. Forbus, Northwestern University,
 *  and Johan de Kleer, the Xerox Corporation.
 *  All rights reserved.
 *  
 *  See the file legal.txt for a paragraph stating scope of permission
 *  and disclaimer of warranty.  The above copyright notice and that
 *  paragraph must be included in any separate copy of this file.
 */

public class JTMS 
{
  private String m_name;
  private LinkedList m_nodes;
  private LinkedList m_justs;
  private LinkedList m_contradictions;
  private LinkedList m_assumptions;
  private ContradictionHandler m_handler;
  private Thunk m_enqueueProc;
  private boolean m_isDebugging;

  public JTMS( String name )
  {
    m_name = name;
    m_nodes = new LinkedList();
    m_justs = new LinkedList();
    m_contradictions = new LinkedList();
    m_assumptions = new LinkedList();
    m_handler = new ContradictionError();
    m_enqueueProc = null;
    //m_isDebugging = true;
    m_isDebugging = false;
  }

  void addNode( Node node )
  {
    if( node.isAssumption() ) {
      m_assumptions.add( node );
    }
    
    if( node.isContradictory() ) {
      m_contradictions.add( node );
    }
    
    m_nodes.add( node );
  }

  void addJustification( Justification just ) 
  {
    m_justs.add( just );
  }

  void addContradiction( Node node ) 
  {
    m_contradictions.add( node );
  }

  /** Set the proc to run when a node in the JTMS becomes IN **/
  void setEnqueueProc( Thunk thunk ) 
  {
    m_enqueueProc = thunk;
  }

  /** Get the proc to run when a node in the JTMS is made in. **/
  Thunk getEnqueueProc()
  {
    return m_enqueueProc;
  }

  /**
   * Given the list of newly OUT nodes, attempt to find alternate
   * support to bring them back IN..
   **/
  Justification findAlternativeSupport( LinkedList outs ) 
  {
    debugging( "   Looking for alternative supports." );
    Iterator it = outs.iterator();

    while( it.hasNext() ) {
      Node node = (Node)it.next();

      if( node.isOut() ) {
	Iterator justs = node.getJustifications().iterator();
	while( justs.hasNext() ) {
	  Justification just = (Justification)justs.next();

	  if( just.checkJustification() ) {
	    // sanity check
	    Assert.check( just.getConsequence() == node,
			  "Consequence of node's support " +
			  "should be that node." );
	    just.getConsequence().installSupport( just );
	    return just;
	  }
	}
      }
    }
    return null;
  }

  /** Determine if a contradiction is IN, and fire handler if so. **/
  public void checkForContradictions()
  {
    LinkedList contradictions = new LinkedList();
    Iterator it = m_contradictions.iterator();

    while( it.hasNext() ) {
      Node node = (Node)it.next();
      if( node.isIn() ) {
	contradictions.add( node );
      }
    }
    if( !contradictions.isEmpty() ) {
      m_handler.handle( contradictions );
    }
  }

  /**
   * Enable as many of the default assumptions as possible without
   * causing a contradiction.
   **/
  public void defaultAssumptions() 
  {
    ContradictionHandler oldHandler = m_handler;
    
    Iterator it = m_assumptions.iterator();
    while( it.hasNext() ) {
      Node assumption = (Node)it.next();
      if( assumption.isEnabledAssumption() ) {
      }
      else if( assumption.isDefaultAssumption() ) {
	// create a new handler that just flags contradictions
	m_handler = new ContradictionFlagger();

	// enable the default assumption
	assumption.enableAssumption();

	// if there were any contradictions don't enable this
	// assumption--it is a trouble maker
	if( ((ContradictionFlagger)m_handler).contradictionsFound ) {
	  assumption.retractAssumption();
	}
      }
    }

    // restore the original handler
    m_handler = oldHandler;
  }

  public void debugging( String out ) 
  {
    if( m_isDebugging ) {
      System.out.println( out );
      //    DebugWindow.addLine( "JTMS", out );
    }
  }
  

  class ContradictionFlagger implements ContradictionHandler 
  {
    boolean contradictionsFound = false;

    public void handle( LinkedList contradictions ) {
      contradictionsFound = true;
    }
  }

  class ContradictionError implements ContradictionHandler 
  {
    public void handle( LinkedList contradictions ) {
      Iterator it = contradictions.iterator();

      while( it.hasNext() ) {
	Node node = (Node)it.next();
	debugging( "Contradiction: " + node );
	debugging( "   Supported by: " + node.getAssumptions() );
      }
      
      throw new Error( "Contradiction found: " + contradictions );
    }
  }
}
