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

// -*-Mode: Java-*- 
// $Id: EditModeManager.java,v 1.7 2003/03/06 00:40:40 moltmans Exp $
// EditModeManager.java -- 
// Author: Michael Oltmans <moltmans@ai.mit.edu> 
// Created: <Fri Sep 10 15:22:48 1999> 
// Time-stamp: <2000-03-14 20:31:32 moltmans> 
package rec.sys;

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

//////////////////////////////////////////////////////////////////////
// Some issues:
//
// what happens when you remove a module that has a recognizer that
// was used in a different module?
//////////////////////////////////////////////////////////////////////


public class EditModeManager 
{
  /**
   * This maps from editing modes to collections (HashSets) of modules
   * active in that mode
   **/
  public Hashtable m_ModeTable;
  private HashSet m_ActiveModes;
  private HashSet m_majorModes;

  /** The name of the default edit mode **/
  public static final String DEFAULT_MODE = "Standard";

  public EditModeManager() 
  {
    m_ModeTable = new Hashtable();
    //    m_ModeTable.put( DEFAULT_MODE, new HashSet() );
    m_ActiveModes = new HashSet();
    m_majorModes = new HashSet();
    //    m_ActiveModes.add( DEFAULT_MODE );
  }

//    public void removeMode( String name )
//    {
//      m_ModeTable.remove( name );
//    }

//    public void addModuleToMode( Module m ) 
//    {
//      addModuleToMode( m, null );
//    }

  /**
   * Add module to the set of modules associated with the modeName.
   **/
  public void addModuleToMode( Module module, HashSet mode )
  {
    if ( mode == null ) {
      mode = new HashSet();
      mode.add( DEFAULT_MODE );
    }

    Console.writeln( "Adding module: " + module );
    Console.writeln( "      To mode: " + mode );

    Set modules = getModules( mode );

    if ( modules == null ) {
      modules = new HashSet();
      m_ModeTable.put( new HashSet( mode ), modules );
    }

    modules.add( module );

//      if ( isActive( mode ) ) {
//        module.enable();
//      }
//      else {
//        module.disable();
//      }
  }

  public void addMajorMode( String mode ) 
  {
    m_majorModes.add( mode );
  }
    
  public void removeModuleFromMode( Module module, String mode )
  {
    HashSet set = new HashSet();
    if ( mode == null ) {
      mode = DEFAULT_MODE;
    }
    set.add( mode );
    
    removeModuleFromMode( module, set );
  }
  
  public void removeModuleFromMode( Module module, HashSet mode )
  {
    if ( mode == null ) {
      mode = new HashSet();
      mode.add( DEFAULT_MODE );
    }

    Collection modules = getModules( mode );

    if ( modules == null )
      return;
    
    modules.remove( module );

    if ( isActive( mode ) ) {
      module.disable();
    }
  }
  
  private Set getModules( HashSet mode )
  {
    return (Set)m_ModeTable.get( mode );
    
    // The obvious thing should work since hashtable uses equal and
    // the equal method of sets calls equal on all the components
    // regardless of their ordering int he two sets.  i.e. everything
    // should be ok, but then again
  }

  public Set getActiveModules() 
  {
    HashSet mode = m_ActiveModes;
    HashSet result = new HashSet();
    Iterator keys = m_ModeTable.keySet().iterator();

    while ( keys.hasNext() ) {
      HashSet key = (HashSet)keys.next();

      if ( mode.containsAll( key ) ) {
	result.addAll( (HashSet)m_ModeTable.get( key ) );
      }
    }
    
    return result;
  }


  /**
   * Install the modules associated with the referenced editing mode.
   * Enter the edit mode with no arguments specified to be passed
   * along.
   **/
  public void enterEditMode( String mode ) 
  {
    enterEditMode( mode, null );
  }

  /**
   * Install the modules associated with the referenced editing mode.
   * Enter the edit mode with the given arg.
   **/
  public void enterEditMode( String mode, Object arg )
  {
//      DebugWindow.addLine( "MO-mode", "Entering mode: " + mode );
//      DebugWindow.addLine( "MO-mode", "With arg:      " + arg );
//      DebugWindow.addLine( "MO-mode", "Currently in:  " + m_ActiveModes );
    Console.writeln( "Entering mode: " + mode );
    Console.writeln( "With arg:      " + arg );
//      Assert.check( !isActive( mode ),
//  		  "Attempting to enter an active mode: " + mode );


    // If this is a major mode then we need to remove all previously
    // active modules to install this one.
    if ( m_majorModes.contains( mode ) ) {
      Set oldModules = getActiveModules();
      m_ActiveModes.clear();

      // Disable all the old modules
      Iterator it = oldModules.iterator();
      while ( it.hasNext() ) {
	Module module = (Module)it.next();
	module.disable();
	Console.writeln( "Disable Module: " + module );
      }
    }

    // add this mode to the list of active modes
    m_ActiveModes.add( mode );
    Set modules = getActiveModules();

    if ( modules == null || modules.size() == 0 ) {
      Assert.note( "Entering an edit mode with no entries." );
      return;
    }

    // Enable the modules that should be active
    Iterator it = modules.iterator();
    Object module = null;
    while ( it.hasNext() ) {
      module = it.next();
      if ( module instanceof EditModeModule ) {
	((EditModeModule)module).enable(arg);
      }
      else {
	((Module)module).enable();
      }
      Console.writeln( "Enabled: " + module );
    }

//      DebugWindow.addLine( "MO-mode", "Now in modes:   " + m_ActiveModes );
//      DebugWindow.addLine( "MO-mode", "Active modules: " + getActiveModules() );
//      DebugWindow.addLine( "MO-mode", "==============" );
  }
  

  /** Remove the modules associated with the referenced editing mode. **/
  public void leaveEditMode( String mode )
  {
    Console.writeln( "Leaving mode: " + mode );

    if ( ! isActive( mode ) ) {
      Assert.note( "Attempting to leave a mode that is not active" );
      return;
    }

    Set modules = getActiveModules();
    m_ActiveModes.remove( mode );
    Set currentModules = getActiveModules();
    
    // remove the modules that are still active from the set.
    // now we just have the deactivated modules
    modules.removeAll( currentModules );
    
    if ( modules == null ) {
      //      Assert.note( "Leaving an edit mode with no entries." );
      return;
    }

    Iterator it = modules.iterator();
    while ( it.hasNext() ) {
      Module module = (Module)it.next();
      module.disable();
      Console.writeln( "Disable Module: " + module );
    }
  }

  public Collection getActiveModes()
  {
    return m_ActiveModes;
  }

  public boolean isActive( String mode )
  {
    HashSet set = new HashSet();
    set.add( mode );
    return isActive( set );
  }

  public boolean isActive( HashSet mode ) 
  {
    return m_ActiveModes.containsAll( mode );
  }
  

  
  
}
