/*
 *This library is free software; you can redistribute it and/or
 *modify it under the terms of the GNU Lesser General Public
 *License as published by the Free Software Foundation; either
 *version 2.1 of the License, or (at your option) any later version.
 *
 *This library is distributed in the hope that it will be useful,
 *but WITHOUT ANY WARRANTY; without even the implied warranty of
 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *Lesser General Public License for more details.
 *
 *You should have received a copy of the GNU Lesser General Public
 *License along with this library; if not, write to the Free Software
 *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/* 
 * This software was written by Phillip Lord (p.lord@hgmp.mrc.ac.uk)
 * whilst at the University of Manchester as a Pfizer post-doctoral 
 * Research Fellow. 
 *
 * The initial code base is copyright by Pfizer, or the University
 * of Manchester. Modifications to the initial code base are copyright
 * of their respective authors, or their employers as appropriate. 
 * Authorship of the modifications may be determined from the ChangeLog
 * placed at the end of this file
 */

package uk.ac.man.bioinf.debug; // Package name inserted by JPack


/**
 * DebugMultiplexer.java
 *
 * This class can be used to multiplex other DebugInterface
 * interfaces. It implements DebugInterface directly, rather than
 * extending AbstractInterface, because I want to make no assumptions
 * at all about the instances which it contains.
 *
 * This class has two relevant methods public methods to install and
 * remove other DebugInterface instances. The first time install is called the
 * multiplexer automatically installs itself as the primary
 * DebugInterface instance. If all but one of its DebugInterface instances are removed
 * from it, then it will replace itself as the primary interface with
 * a DefaultDebug instance. 
 *
 * If any of the Debug instances fail at any time in any of their
 * methods, they will be removed. If Debug is true all of the others
 * instances will be informed of this.
 *
 * Created: Sun May  7 20:49:33 2000
 *
 * @author Phillip Lord
 * @version $Id: DebugMultiplexer.java,v 1.3 2001/04/11 17:04:42 lord Exp $
 */

public class DebugMultiplexer implements DebugInterface
{
  // store contents in array. We are probably not going to do a lot of
  // adding and removing, but are going to do a lot of iterating, and
  // this will save us loads of casts.
  private static DebugInterface[] instArray;
  
  private DebugMultiplexer()
  {
    // 
  }
  
  /**
   * Add a new Debug Interface instance. This method ensures that the
   * Multiplexer is installed if it has not been so far. Note that
   * this means the old debug instance is silently replaced and junked!
   * @param deb
   * @return
   */
  public static DebugInterface addDebugInstance( DebugInterface deb )
  {
    if( instArray == null || instArray.length == 0 ){
      // small one element array
      instArray = new DebugInterface[ 1 ];
      instArray[ 0 ] = deb;
      installDebugInstance();
    }else{
      // copy the old array and add the new at the end
      DebugInterface[] newArray = new DebugInterface[ instArray.length + 1 ];
      System.arraycopy( instArray, 0, newArray, 0, instArray.length );
      newArray[ newArray.length - 1 ] = deb;
      instArray = newArray;
    }
    if( Debug.debug )
      Debug.message( DebugMultiplexer.class, "DEBUG: Multiplexer has added new instance " + deb );
      
    return deb;
  }
  
  private static void installDebugInstance()
  {
    DebugInterface inst = new DebugMultiplexer();
    Debug.setInstance( inst );
  }
  
  
  /**
   * Remove a DebugInterface instance from the multiplexer. 
   * @param deb the interface to remove
   * @return the interface removed. Null if the deb wasnt there
   */
  public static DebugInterface removeDebugInstance( DebugInterface deb )
  {
    DebugInterface old = deb;

    int index = indexOf( deb );
    if( index == -1 ){
      return null;
    }
    
    // if its the last kill the array
    if( instArray.length == 1 ){
      DebugInterface last = instArray[ 0 ];
      uninstallDebugInstance();
      instArray = null;
      return last;
    }

    // else remove the index
    DebugInterface newInst[] = new DebugInterface
      [ instArray.length - 1 ];
    int numMoved = newInst.length - index;
    System.arraycopy( instArray, 0, newInst, 0, index );
    System.arraycopy( instArray, index + 1, newInst, index, numMoved );
    instArray = newInst;
    
    if( Debug.debug )
      Debug.message( DebugMultiplexer.class, 
		     "DEBUG: Have removed instance from multiplexer " + old );
    
    return old;
  }
  
  private static int indexOf( DebugInterface deb  )
  {
    if( instArray == null ) return -1;
    for( int i = 0; i < instArray.length; i++ ){
      if( deb == instArray[ i ] )
	return i;
    }
    return -1;
  }

  private static void emergencyUninstall()
  {
    instArray = new DebugInterface[ 0 ];
    Debug.setInstance( new DefaultDebug() );
    Debug.message( DebugMultiplexer.class, 
		   "DEBUG: PANIC! EMERGENCY! Uninstall of DebugMultiplexer!" );
  }
  

  private static void uninstallDebugInstance()
  {
    Debug.setInstance
      ( instArray[ 0 ] );
  }
  
  private void handleDisaster( Throwable th )
  {
    emergencyUninstall();
    if( Debug.debug )
      Debug.throwable( DebugMultiplexer.class, th );
  }
  
  // the rest of the methods are all pretty much the same template,
  // and I could not think of a better way of doing this...
  public void message( Object obj, String message )
  {
    int i = 0;
    try{
      for( i = 0; i < instArray.length; i++ ){
	instArray[ i ].message( obj, message );
      } //end for( i < instArray.length )
    }
    catch( Throwable th ){
      handleDisaster( th );
      // "rethrow" the old message
      Debug.message( obj, message );
    }
  }

  public void message( Object obj, Object message )
  {
    int i = 0;
    try{
      for( i = 0; i < instArray.length; i++ ){
	instArray[ i ].message( obj, message );
      } //end for( i < instArray.length )
    }
    catch( Throwable th ){
      handleDisaster( th );
      // "rethrow" the old message
      Debug.message( obj, message );
    }
  }
  
  public void message( Class cla, String message )
  {
    int i = 0;
    try{
      for( i = 0; i < instArray.length; i++ ){
	instArray[ i ].message( cla, message );
      } //end for( i < instArray.length )
    }
    catch( Throwable th ){
      handleDisaster( th );
      // "rethrow" the old message
      Debug.message( cla, message );
    }
  }

  
  public void message( Class cla, Object message )
  {
    int i = 0;
    try{
      for( i = 0; i < instArray.length; i++ ){
	instArray[ i ].message( cla, message );
      } //end for( i < instArray.length )
    }
    catch( Throwable th ){
      handleDisaster( th );
      // "rethrow" the old message
      Debug.message( cla, message );
    }    
  }
  
  public void throwable( Object obj, Throwable th )
  {
    int i = 0;
    try{
      for( i = 0; i < instArray.length; i++ ){
	instArray[ i ].throwable( obj, th );
      } //end for( i < instArray.length )
    }
    catch( Throwable tha ){
      handleDisaster( tha );
      // "rethrow" the old message
      Debug.message( obj, th );
    }
  }

  
  public void throwable( Class cla, Throwable th )
  {
    int i = 0;
    try{
      for( i = 0; i < instArray.length; i++ ){
	instArray[ i ].throwable( cla, th );
      } //end for( i < instArray.length )
    }
    catch( Throwable tha ){
      handleDisaster( tha );
      // "rethrow" the old message
      Debug.message( cla, th );
    }
  }
  
  public void both( Object obj, String message, Throwable th )
  {
    int i = 0;
    try{
      for( i = 0; i < instArray.length; i++ ){
	instArray[ i ].both( obj, message, th );
      } //end for( i < instArray.length )
    }
    catch( Throwable tha ){
      handleDisaster( tha );
      // "rethrow" old message
      Debug.both( obj, message, th );
    }
  }
  
  public void both( Class cla, String message, Throwable th )
  {
    int i = 0;
    try{
      for( i = 0; i < instArray.length; i++ ){
	instArray[ i ].both( cla, message, th );
      } //end for( i < instArray.length )
    }
    catch( Throwable tha ){
      handleDisaster( tha );
      // "rethrow" the old message
      Debug.both( cla, message, th );
    }
  }
  
  public void both( Object obj, Object message, Throwable th )
  {
    int i = 0;
    try{
      for( i = 0; i < instArray.length; i++ ){
	instArray[ i ].both( obj, message, th );
      } //end for( i < instArray.length )
    }
    catch( Throwable tha ){
      handleDisaster( tha );
      // "rethrow" the old message
      Debug.both( obj, message, th );
    }
  }

  public void both( Class cla, Object message, Throwable th )
  {
    int i = 0;
    try{
      for( i = 0; i < instArray.length; i++ ){
	instArray[ i ].both( cla, message, th );
      } //end for( i < instArray.length )
    }
    catch( Throwable tha ){
      handleDisaster( tha );
      // "rethrow" the old message
      Debug.both( cla, message, th );
    }    
  }
} // DebugMultiplexer



/*
 * ChangeLog
 * $Log: DebugMultiplexer.java,v $
 * Revision 1.3  2001/04/11 17:04:42  lord
 * Added License agreements to all code
 *
 * Revision 1.2  2000/05/30 16:04:18  lord
 * Have rationalised and sorted all the import statements
 *
 * Revision 1.1  2000/05/08 16:22:57  lord
 * Initial checkin
 *
 */
