/*
 * JBoss, the OpenSource EJB server
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.logging.log4j;

import java.io.IOException;
import java.io.PrintStream;

import org.apache.log4j.Category;
import org.apache.log4j.Priority;

/** A subclass of PrintStream that redirects its output to a log4j Category.
This class is used to map PrintStream/PrintWriter oriented logging onto
the log4j Categories. Examples include capturing System.out/System.err writes.

@author Scott.Stark@jboss.org
@version $Revision: 1.3.2.3 $
*/
public class CategoryStream extends PrintStream
{
   private Category category;
   private Priority priority;
   private boolean issuedWarning;
   private boolean inWrite;
   
    /** Redirect logging to the indicated category using Priority.INFO
    */
    public CategoryStream(Category category)
    {
        this(category, Priority.INFO, System.out);
    }
    /** Redirect logging to the indicated category using the given
        priority. The ps is simply passed to super but is not used.
    */
    public CategoryStream(Category category, Priority priority, PrintStream ps)
    {
        super(ps);
        this.category = category;
        this.priority = priority;
    }
    public void println(String msg)
    {
        if( msg == null )
            msg = "null";
        byte[] bytes = msg.getBytes();
        write(bytes, 0, bytes.length);
    }
    public void println(Object msg)
    {
        if( msg == null )
            msg = "null";
        byte[] bytes = msg.toString().getBytes();
        write(bytes, 0, bytes.length);
    }
    public void write(byte b)
    {
        byte[] bytes = {b};
        write(bytes, 0, 1);
    }

   private ThreadLocal recursiveCheck = new ThreadLocal();
   public void write(byte[] b, int off, int len)
   {
      
      Boolean recursed = (Boolean)recursiveCheck.get();
      if (recursed != null && recursed.equals(Boolean.TRUE))
      {
         /* There is a configuration error that is causing looping. Most
            likely there are two console appenders so just return to prevent
            spinning.
         */
         if( issuedWarning == false )
         {
            issuedWarning = true;
            String msg = "ERROR: invalid console appender config detected, console stream is looping";
            try
            {
               out.write(msg.getBytes());
            }
            catch(IOException e)
            {
            }
         }
         return;
      }
      // Remove the end of line chars
      while( len > 0 && (b[len-1] == '\n' || b[len-1] == '\r') && len > off )
         len --;
      
      String msg = new String(b, off, len);
      recursiveCheck.set(Boolean.TRUE);
      category.log(priority, msg);
      recursiveCheck.set(Boolean.FALSE);
   }
}
