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

// -*-Mode: Java-*- 
// $Id: DebugWindow.java,v 1.10 2003/03/06 00:40:38 moltmans Exp $
// DebugWindow.java -- 
// Author: Michael Oltmans <moltmans@ai.mit.edu> 
// Created: <Fri Feb  4 13:26:20 2000> 
// Time-stamp: <2001-09-10 19:39:05 moltmans> 
package rec.util;

import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.AttributeSet;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.Icon;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JTextPane;
import javax.swing.JScrollPane;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.JButton;
import java.awt.Frame;
import javax.swing.JScrollBar;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.StringTokenizer;

/**
 * This class provides a mechanism for displaying debug output in
 * separate panels of a tabbed window.  The target page of the panel
 * is specified by a string.  <p>

 * For example:
 * <code>Debug.println( "speed info", speedinfoObj )</code><p>
 *
 * In addition buttons can be added to the debug window with the
 * <code>addButton</code> method.  This is useful for having simple on
 * demand output such as printing the value of a variable or
 * performing actions that are not performed outside of a debuging
 * context.<p>
 *
 * The frame will be opened the first time that it is accessed.
 *
 * See the <code>main</code> function for a demonstration.
 **/
public class DebugWindow extends JFrame
{
  private static DebugWindow m_theDebug;
  private static boolean m_debug = true;

  private JTabbedPane m_tabs;

  /**
   * Print obj to the debug panel named title.  If no such panel
   * exists, one will be created and added to the tab.
   **/
  public static void print( String title, Object obj ) 
  {
    if ( m_debug ) {
      getDebug( title ).print( obj );
      m_theDebug.markDirty( title );
    }
  }
  
  /**
   * Print obj to the debug panel named title followed by a newline.
   * If no such panel exists, one will be created and added to the
   * tab.
   **/
  public static void println( String title, Object obj )
  {
    if ( m_debug ) {
      print( title, obj + "\n" );
    }
  }

  public static void addLine( String title, Object comment )
  {
    addLine( title, comment.toString() );
  }

  public static void addLine( String title, String comment )
  {
    addWithNewlines( title, comment );
  }

  private static void addWithNewlines( String title, String text ) 
  {
    StringTokenizer st = new StringTokenizer( text, "\n", false );

    while ( st.hasMoreTokens() ) {
      println( title, st.nextToken());
    }
    //    getDebugWindow( title ).redisplay();
  }

  /**
   * Println to the note tab.
   **/
  public static void note( String msg ) 
  {
    println( "Notes", msg );
  }

  /**
   * println to the Error tab and bring the debug window to the front.
   **/
  public static void error( String msg ) 
  {
    println( "Errors", msg );
    makeActive( "Errors" );
  }
  
  public static void makeActive( String title ) 
  {
    if ( m_debug ) {
      getDebug( title );
      m_theDebug.m_tabs.setSelectedComponent( getDebug( title ) );
      getDebugFrame().show();
      getDebugFrame().setState(Frame.NORMAL);
      getDebugFrame().toFront();
    }
    
  }

  /**
   * Print an exception to the Error tab and bring the debug window to the front.
   *
   * @param exception a value of type <code>Throwable</code>
   */
  public static void error( Throwable exception ) 
  {
      StringWriter sw = new StringWriter();
      PrintWriter pw = new PrintWriter( sw );
      exception.printStackTrace( pw );
      
      error( exception.toString() + "\n" + sw.toString() );

  }

  public static void clear( String title )
  {
    if ( m_debug ) {
      getDebug( title ).clear();
    }
    
  }

  /**
   * Add a button to the bottom of the debug pane of the specified title.
   **/
  public static void addButton(String title, JButton button) 
  {
    if ( m_debug ) {
      getDebug( title ).addButton( button );
    }
  }

  /**
   * Provide a listener and a button name and the Debug window will
   * create a button (at the bottom of the specified panel) and attach
   * the listener to it.  This is usefull if you need to add one
   * button to several panels.  e.g.:<br>
   *
   * <code>
      ActionListener listener = new ActionListener() {
        public void actionPerformed( ActionEvent e ) 
	{
	  Test.test();
	}
      };

      DebugWindow.addButton( "Random1", "run test", listener );
      DebugWindow.addButton( "Random2", "run test", listener );
      DebugWindow.addButton( "Random3", "run test", listener );
     </code>
   **/
  public static void addButton(String title, String buttonName,
			       ActionListener listener )
  {
    JButton b = new JButton( buttonName );
    b.addActionListener( listener );
    addButton( title, b );
  }
  

  /**
   * Get the frame that houses the debug pane.
   **/
  public static JFrame getDebugFrame() 
  {
    return m_theDebug;
  }

  public static void setDebugging( boolean value ) 
  {
    m_debug = value;
  }

  public static boolean isDebugging( boolean value ) 
  {
    return m_debug;
  }

  private static DebugPanel getDebug( String title ) 
  {
    if ( m_theDebug == null ) {
      m_theDebug = new DebugWindow();
    }
    
    return m_theDebug.getDebugPanel( title );
  }
  
  
//////////////////////////////////////////////////////////////////////

  public DebugWindow() {
    this( "Debug Window" );
  }
  

  public DebugWindow ( String title ) {
    super( title );

    setSize(400, 500);
    show();
    m_tabs = new JTabbedPane();
    getContentPane().add(m_tabs, BorderLayout.CENTER);
    m_tabs.addMouseListener(new MouseAdapter() {
	public void mouseClicked(MouseEvent e) {
	  Icon i = m_tabs.getIconAt(m_tabs.getSelectedIndex());
	  ((DotIcon)i).setColor(Color.green);
	  m_tabs.repaint();
	}
	public void mouseEntered(MouseEvent e) {
	}
	public void mouseExited(MouseEvent e) {
	}
	public void mousePressed(MouseEvent e) {
	}
	public void mouseReleased(MouseEvent e) {
	}
      });
      
    m_tabs.addChangeListener(new ChangeListener() {
	int state = 0;
	public void stateChanged(ChangeEvent e) {
	  Icon i = m_tabs.getIconAt(m_tabs.getSelectedIndex());
	  ((DotIcon)i).setColor(Color.green);
	}
      });
  }

  protected DebugPanel getDebugPanel( String title ) 
  {
    int index = m_tabs.indexOfTab(title);
    if (index >= 0) {
      return (DebugPanel)m_tabs.getComponentAt(index);
    }

    DebugPanel debugPanel = new DebugPanel(title);
    m_tabs.addTab(title, new DotIcon(Color.red), debugPanel);
    m_tabs.setSelectedComponent(debugPanel);
    return debugPanel;
  }

  public void markDirty( String title ) 
  {
    int index = m_tabs.indexOfTab( title );
    if ( m_tabs.getSelectedIndex() != index ) {
      ((DotIcon)m_tabs.getIconAt( index )).setColor( Color.red );
      m_tabs.repaint();
    }
  }

  /** Test out the debug windows **/
  public static void main( String[] args )
  {
    DebugWindow.println( "out1", "  this is a comment" );
    DebugWindow.println( "out1", "this is another comment" );

    for( int i = 1; i< 3; i++ ) {
      DebugWindow.println( "out2", "other comments go here" );
      DebugWindow.println( "out2", "it is like the second nature...:-)" );
    }

    JButton b = new JButton("out1");
    b.addActionListener(new ActionListener() {
	public void actionPerformed(ActionEvent e) {
	  DebugWindow.println("out1", "more output");
	}
      });

    JButton c = new JButton("out2");
    c.addActionListener(new ActionListener() {
	public void actionPerformed(ActionEvent e) {
	  DebugWindow.println("out2", "more output");
	}
      });

    JButton d = new JButton("clear");
    d.addActionListener(new ActionListener() {
	public void actionPerformed(ActionEvent e) {
	  DebugWindow.clear("out1");
	}
      });

    DebugWindow.addButton("out1", b);
    DebugWindow.addButton("out2", c);
    DebugWindow.addButton("out1", d);
  }
  
} //DebugWindow

class DebugPanel extends JPanel {

  private JTextPane m_pane;
  private JPanel m_buttonBar;
  private JScrollBar m_scrollBar;
  private DefaultStyledDocument m_doc;
  private String m_title;
  private AttributeSet m_attr;

  DebugPanel ( String title)
  {
    m_title = title;
    m_doc = new DefaultStyledDocument();
    m_pane = new JTextPane(m_doc);
    m_buttonBar = new JPanel();

    JScrollPane scrollPane = new JScrollPane( m_pane );
    m_scrollBar = scrollPane.getVerticalScrollBar();

    setLayout(new BorderLayout());
    add( scrollPane, BorderLayout.CENTER );
    add( m_buttonBar, BorderLayout.SOUTH );

    m_pane.setEditable( false );
    SimpleAttributeSet m_attr = new SimpleAttributeSet();
    StyleConstants.setFontFamily(m_attr, "courier");
    StyleConstants.setFontSize(m_attr, 12);

    clear();
  }

  void print( Object obj ) 
  {
    try {
      m_doc.insertString( m_doc.getLength(), obj.toString(), m_attr );
      m_scrollBar.setValue( m_scrollBar.getMaximum() );
    }
    catch ( BadLocationException ble ) {
    }
  }

  void clear()
  {
    try {
      m_doc.remove( 0, m_doc.getLength() );
    }
    catch ( BadLocationException ble ) {
    }
  }

  void addButton( JButton button )
  {
    m_buttonBar.add(button);
    validate();
  }

}// DebugPanel


//  import java.awt.*;
//  import java.awt.event.*;
//  import java.util.*;
//  import javax.swing.*;
//  import javax.swing.event.ChangeListener;
//  import javax.swing.event.ChangeEvent;

//  /**
//   * This class provides a mechanism for displaying debug output in
//   * separate windows.
//   **/
//  public class DebugWindow extends JPanel
//  {
//    private static JFrame m_frame;
//    private static JTabbedPane m_tabs;
//    private static JPanel m_buttonBar;

//    //private static Hashtable m_Windows = new Hashtable();

//    private Content m_Content;
//    private TinyBrowserPane m_Pane;
//    private String m_Title;

//    public static void addLine( String title, Object comment )
//    {
//      addLine( title, comment.toString() );
//    }

//    public static void addLine( String title, String comment )
//    {
//      addWithNewlines( title, comment );
//    }

//    private static void addWithNewlines( String title, String text ) 
//    {
//      StringTokenizer st = new StringTokenizer( text, "\n", false );

//      while ( st.hasMoreTokens() ) {
//        getContent( title ).addText( st.nextToken());
//        getContent( title ).addBreak();
//      }
//      getDebugWindow( title ).redisplay();
//    }
  
//    public static void addText( String title, String comment )
//    {
//      getContent( title ).addText( comment );
//    }

//    public static void addParagraph( String title )
//    {
//      getContent( title ).addParagraph();
//    }

//    public static void makeActive( String title )
//    {
//      getDebugWindow( title ).makeActive();
//    }

//    public static void clear( String title )
//    {
//      getDebugWindow( title ).clear();
//    }


//    public static DebugWindow getDebugWindow( String title )
//    {
//      if (m_frame == null) {
//        m_frame = new JFrame("Debug Window");
//        m_frame.setSize(400, 500);
//        m_frame.show();
//        m_tabs = new JTabbedPane();
//        m_frame.getContentPane().add(m_tabs, BorderLayout.CENTER);
//        m_tabs.addMouseListener(new MouseAdapter() {
//  	  public void mouseClicked(MouseEvent e) {
//  	    DebugWindow w = (DebugWindow)m_tabs.getSelectedComponent();
//  	    Icon i = m_tabs.getIconAt(m_tabs.getSelectedIndex());
//  	    ((DotIcon)i).setColor(Color.green);
//  	    m_tabs.repaint();
//  	  }
//  	  public void mouseEntered(MouseEvent e) {
//  	  }
//  	  public void mouseExited(MouseEvent e) {
//  	  }
//  	  public void mousePressed(MouseEvent e) {
//  	  }
//  	  public void mouseReleased(MouseEvent e) {
//  	  }
//  	});
      
//        m_tabs.addChangeListener(new ChangeListener() {
//  	  int state = 0;
//  	  public void stateChanged(ChangeEvent e) {
//  	    DebugWindow w = (DebugWindow)m_tabs.getSelectedComponent();
//  	    Icon i = m_tabs.getIconAt(m_tabs.getSelectedIndex());
//  	    ((DotIcon)i).setColor(Color.green);
//  	  }
//  	});
//        m_buttonBar = new JPanel();
//        m_frame.getContentPane().add(m_buttonBar, BorderLayout.SOUTH);
//      } // end of if ()

//      int index = m_tabs.indexOfTab(title);
//      if (index >= 0) {
//        return (DebugWindow)m_tabs.getComponentAt(index);
//      }

//      DebugWindow dw = new DebugWindow(title);
//      m_tabs.addTab(title, new DotIcon(Color.red), dw);

//      dw.makeActive();
//      return dw;
//    }

//    public static void addButton(JButton button) 
//    {
//      m_buttonBar.add(button);
//      m_frame.validate();
//    }
  
//    protected static Content getContent( String title )
//    {
//      return getDebugWindow( title ).m_Content;
//    }

//    public static void showDebugWindow() 
//    {
//      m_frame.show();
//    }

//    protected DebugWindow( String title ) 
//    {
//      m_Title = title;
//      m_Pane = new TinyBrowserPane(200,200);
//      setLayout(new BorderLayout());
//      add(m_Pane, BorderLayout.CENTER);

//      m_Content = new Content();
//      clear();
//    }

//    public void redisplay() 
//    {
//      m_Pane.display( m_Content );
//      if (m_tabs.getSelectedIndex() >= 0) {
//        ((DotIcon)m_tabs.getIconAt(m_tabs.indexOfComponent(this))).setColor(Color.red);
//        m_tabs.repaint();
//      }
//    }

//    public void makeActive() 
//    {
//      m_Pane.display( m_Content );
//      m_tabs.setSelectedComponent(this);
//    }

//    public void addText( String text )
//    {
//      m_Content.addText( text );
//    }

//    public void addLine( String text )
//    {
//      m_Content.addText( text );
//      m_Content.addBreak();
//    }

//    public void addBreak()
//    {
//      m_Content.addBreak();
//    }
  
//    public void addParagraph()
//    {
//      m_Content.addParagraph();
//    }

//    public void clear()
//    {
//      m_Content.clear();
//      m_Content.setFont( new Font( "SERIF", Font.BOLD, 14 ));
//      m_Content.setColor( Color.red );
//      m_Content.addText( m_Title );
//      m_Content.addParagraph();
//      m_Content.setColor( Color.black );
//      m_Content.setFont( new Font( "HELVETICA", Font.PLAIN, 12 ));
//    }

//    /** Test out the debug windows **/
//    public static void main( String[] args )
//    {
//      DebugWindow.addLine( "out1", "this is a comment" );
//      DebugWindow.addLine( "out1", "this is another comment" );

//      for( int i = 1; i< 3; i++ ) {
//        DebugWindow.addLine( "out2", "other comments go here" );
//        DebugWindow.addLine( "out2", "it is like the second nature...:-)" );
//      }

//      JButton b = new JButton("out1");
//      b.addActionListener(new ActionListener() {
//  	public void actionPerformed(ActionEvent e) {
//  	  DebugWindow.addLine("out1", "more output");
//  	}
//        });

//      JButton c = new JButton("out2");
//      c.addActionListener(new ActionListener() {
//  	public void actionPerformed(ActionEvent e) {
//  	  DebugWindow.addLine("out2", "more output");
//  	}
//        });
//      DebugWindow.addButton(b);
//      DebugWindow.addButton(c);
//    }
  
//  }

