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

// $Id: EventGroup.java,v 1.1 2003/06/03 15:37:13 cadlerun Exp $
// EventGroup.java -- 
// Author: Aaron Adler <cadlerun@fracas.ai.mit.edu> 
// Copyright: Copyright (C) 2003 by MIT.  All rights reserved.
// Created: <Mon Apr  7 13:46:05 2003> 

/**
 * This class is a data structure for groups of sketched and spoken events
 * This will allow a list view to be created so that the events in
 * each group can be more easily seen.
 **/

package rec.multi;

import java.util.Iterator;
import java.util.TreeSet;
import java.util.Set;
import java.util.ArrayList;
import java.util.NoSuchElementException;

import edu.mit.tools.watch.timeline.TimelineDataElement;
import edu.mit.tools.watch.timeline.BreakTimelineDataElement;
import edu.mit.tools.watch.timeline.TimelineDataElementComparator;

import edu.mit.tools.watch.Logging;
import org.apache.log4j.Logger;

public class EventGroup {
  private static Logger LOG = Logging.SPEECH;

  private TreeSet m_intBreaks;
  private ArrayList m_eventGroups;
  private int m_currentIndex = -1;

  
  public EventGroup(Iterator i) {
    // the input is an iterator of the timeline data
    TreeSet breaks; // we use this set of breaks so that we can easily extract the groups from the timeline events
    TreeSet events; // use to get the intial groups

    //initialize TreeSets
    breaks = new TreeSet(new TimelineDataElementComparator());
    events = new TreeSet(new TimelineDataElementComparator());
    m_intBreaks = new TreeSet();
    
    while (i.hasNext()) {
      TimelineDataElement tde = (TimelineDataElement)i.next();
      // There are two types of TimelineDataElements,
      // BasicTimelineDataElements and BreakTimelineDataElements
      if (tde instanceof BreakTimelineDataElement) {
	breaks.add(tde);
	m_intBreaks.add(new Integer(tde.getStartTime()));
	LOG.debug("adding break: "+tde.getStartTime());
      }
      else {
	if (tde.getType().equalsIgnoreCase("speech") ||
	    tde.getType().equalsIgnoreCase("sketch")) {
	  // only add speech and sketching events
	  events.add(tde);
	  LOG.debug("adding other: "+tde.getType()+" "+tde.getStartTime()+" "+tde.getEndTime());
	}
      }
    }

    // now fill in the data structure that we'll use. namely, the list of sets of timeline data elements
    m_eventGroups = new ArrayList();

    Iterator breaksIterator = breaks.iterator();
    if (!breaksIterator.hasNext()) {
      // no breaks, all in one group
      if (events.size() > 0) {
	m_eventGroups.add(events);
      }
    }
    else {
      BreakTimelineDataElement previousBreak = null;

      // first set
      BreakTimelineDataElement b = (BreakTimelineDataElement)breaksIterator.next();
      m_eventGroups.add(events.headSet(b));
      previousBreak = b;

      // middle sets
      while(breaksIterator.hasNext()) {
	b = (BreakTimelineDataElement)breaksIterator.next();
	m_eventGroups.add(events.subSet(previousBreak, b));
	previousBreak = b;
      }

      // end set
      m_eventGroups.add(events.tailSet(previousBreak));
    }

    // only set current index to 0 if there is at least 1 group
    if (m_eventGroups.size() > 0) m_currentIndex = 0;
    
  }

  
  //// methods to retrieve sets of timeline events /////
  
  public Set getGroupByTime (int time) {
    if (m_currentIndex == -1) throw new NoSuchElementException("No elements in EventGroup.");

    Integer t = new Integer(time+1); // head set will only get strickly less than and we want less than or equal to
    int pos = m_intBreaks.headSet(t).size();
    m_currentIndex = pos;
    return (Set) m_eventGroups.get(pos);
  }

  public Set getNextGroup() throws NoSuchElementException {
    if (m_currentIndex == -1) throw new NoSuchElementException("No elements in EventGroup.");

    if (m_currentIndex >= (m_eventGroups.size() - 1)) throw new NoSuchElementException("No next element in EventGroup.");
    m_currentIndex++;
    return (Set) m_eventGroups.get(m_currentIndex);
  }
  
  public Set getPreviousGroup() throws NoSuchElementException {
    if (m_currentIndex == -1) throw new NoSuchElementException("No elements in EventGroup.");
    
    if (m_currentIndex == 0) throw new NoSuchElementException("No previous element in EventGroup.");
	
    m_currentIndex--;
    return (Set) m_eventGroups.get(m_currentIndex);
  }
  
  public Iterator iterator() {
    return m_eventGroups.iterator();
  }
  
  public boolean hasNextGroup() {
    if ((m_currentIndex != -1) && (m_currentIndex < (m_eventGroups.size() - 1)))
      return true;
    else
      return false;
  }
  
  public boolean hasPreviousGroup() {
    if (m_currentIndex > 0)
      return true;
    else
      return false;
  }
}
