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

// $Id: CanonicalEvent.java,v 1.7 2003/03/06 00:40:49 moltmans Exp $
// CanonicalEvent.java -- 
// Author: Michael Oltmans <moltmans@ai.mit.edu> 
// Created: <Wed May 17 13:03:56 2000> 
// Time-stamp: <00/07/18 16:47:08 moltmans> 
package rec.annotate.rules;

import java.util.*;

import rec.util.*;
import rec.annotate.*;
import rec.annotate.facts.*;

/**
 * A canonical event is one that represents an equivalence class of
 * events.  It has a time interval but remeber that this is the time
 * period in which the event was described, not the time period
 * indicating its position in the sequence of actions in the real
 * world.
 *
 * It also points to events it causes and to the events that cause it.
 **/
public class CanonicalEvent implements Interval
{
  private Set m_events;
  private Set m_causes;
  private Set m_effects;
  private Set m_parts;
  private Set m_partOf;
  private long m_startTime;
  private long m_endTime;
  private Event m_event;

  public CanonicalEvent() 
  {
    m_events = new HashSet();
    m_causes = new HashSet();
    m_effects = new HashSet();
    m_parts = new HashSet();
    m_partOf = new HashSet();
    m_startTime = Long.MAX_VALUE;
    m_endTime = Long.MIN_VALUE;
    m_event = null;
  }
  
  public void merge( CanonicalEvent event ) 
  {
    // we don't really want to handle the general merging problem
    Assert.check( m_causes.isEmpty() && m_effects.isEmpty() &&
		  m_parts.isEmpty() && m_partOf.isEmpty(),
		  "Attempt to merge events after handling cause, " +
		  "effect and part of relations." );
    
    m_events.addAll( event.m_events );
    // construct the composite event
    m_event = m_event.combineWith( event.m_event );
    Assert.notNull( m_event, "Trouble merging canonical events: " +
		    event + " and " + this );
  }

  public void addEvent( Event event ) 
  {
    // if this is a new element check if it is earlier on or latter
    if( m_events.add( event ) ) {
      if( event.getStartTime() < getStartTime() ) {
	m_startTime = event.getStartTime();
      }
      if( event.getEndTime() > getEndTime() ) {
	m_endTime = event.getEndTime();
      }
      if( m_event == null ) {
	m_event = event;
      }
      else {
	m_event = m_event.combineWith( event );
	Assert.notNull( m_event,
			"Trouble merging canonical events" );
      }
    }
  }

  public Set getEvents() 
  {
    return m_events;
  }

  public long getStartTime() 
  {
    return m_startTime;
  }
  
  public long getEndTime() 
  {
    return m_endTime;
  }

  public boolean isBefore( CanonicalEvent e )
  {
    return getStartTime() < e.getStartTime();
  }

  public Set getEffects() 
  {
    return m_effects;
  }

  public Set getCauses()
  {
    return m_causes;
  }

  public boolean isSubEvent() 
  {
    return !m_partOf.isEmpty();
  }
  
  public Set getSubEvents()
  {
    return m_parts;
  }

  public Set getParentEvents()
  {
    return m_partOf;
  }
  
  public void addCause( CanonicalEvent e )
  {
    m_causes.add( e );
  }

  public void addEffect( CanonicalEvent e )
  {
    m_effects.add( e );
  }

  public void addSubEvents( Collection events ) 
  {
    m_parts.addAll( events );
  }

  public void addParentEvent( CanonicalEvent event )
  {
    m_partOf.add( event );
  }
  
  public String toString() 
  {
    return toEnglish();
  }

  public String toEnglish()
  {
    if( m_event == null )
      return "";
    return m_event.toEnglish();
  }
  
  public String detailedToString() 
  {
    String result = "<CanonicalEvent: ";
    Iterator it = m_events.iterator();
    while( it.hasNext() ) {
      result = result + "\n***" + it.next();
    }
    return result + ">";
  }
}

