/*
 * Copyright (C) 2005 Luca Veltri - University of Parma - Italy
 * 
 * This file is part of MjSip (http://www.mjsip.org)
 * 
 * MjSip is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * MjSip 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MjSip; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * Author(s):
 * Luca Veltri (luca.veltri@unipr.it)
 */

package org.zoolu.tools;

import java.io.*;
import java.util.Date;

// import java.util.Locale;
// import java.text.DateFormat;
// import java.text.SimpleDateFormat;

/**
 * Class Log allows the printing of log messages onto standard output or files
 * or any PrintStream.
 * <p>
 * Every Log has a <i>verboselevel</i> associated with it; any log request with
 * <i>loglevel</i> less or equal to the <i>verbose-level</i> is logged. <br>
 * Verbose level 0 indicates no log. The log levels should be greater than 0.
 * <p>
 * Parameter <i>logname</i>, if non-null, is used as log header (i.e. written
 * at the begin of each log row).
 */
public class Log {

	/** ***************************** Attributes ****************************** */

	/** (static) Default maximum log file size (4MB) */
	// public static final long MAX_SIZE=4096*1024; // 4MB
	public static final long MAX_SIZE = 1024 * 1024; // 1MB

	/** The log output stream */
	PrintStream out_stream;

	/** The log tag at the beginning of each log row */
	String log_tag;

	/**
	 * The <i>log_level</i>.
	 * <p>
	 * Only messages with a level less or equal this <i>log_level</i> are
	 * effectively logged
	 */
	int verbose_level;

	/**
	 * The maximum size of the log stream/file [bytes] Value -1 indicates no
	 * maximum size
	 */
	long max_size;

	/** The size of the log tag (e.g. "MyLog: " has tag_size=7) */
	int tag_size;

	/** Whether messages are logged */
	boolean do_log;

	/** The char counter of the already logged data */
	long counter;

	/** **************************** Constructors ***************************** */

	/**
	 * Associates a new Log to the PrintStream <i>outstream</i>. Log size has
	 * no bound
	 */

	public Log(PrintStream out_stream, String log_tag, int verbose_level) {
		init(out_stream, log_tag, verbose_level, -1);
	}

	/**
	 * Associates a new Log to the file <i>filename</i>. Log size is limited to
	 * the MAX_SIZE
	 */
	public Log(String file_name, String log_tag, int verbose_level) {
		PrintStream os = null;
		if (verbose_level > 0) {
			try {
				os = new PrintStream(new FileOutputStream(file_name));
			} catch (IOException e) {
				e.printStackTrace();
			}
			init(os, log_tag, verbose_level, MAX_SIZE);
		}
	}

	/**
	 * Associates a new Log to the file <i>filename</i>. Log size is limited to
	 * <i>logsize</i> [bytes]
	 */

	public Log(String file_name, String log_tag, int verbose_level,
			long max_size) {
		PrintStream os = null;
		if (verbose_level > 0) {
			try {
				os = new PrintStream(new FileOutputStream(file_name));
			} catch (IOException e) {
				e.printStackTrace();
			}
			init(os, log_tag, verbose_level, max_size);
		} else {
			init(null, log_tag, 0, 0);
			do_log = false;
		}
	}

	/**
	 * Associates a new Log to the file <i>filename</i>. Log size is limited to
	 * <i>logsize</i> [bytes]
	 */

	public Log(String file_name, String log_tag, int verbose_level,
			long max_size, boolean append) {
		PrintStream os = null;
		if (verbose_level > 0) {
			try {
				os = new PrintStream(new FileOutputStream(file_name, append));
			} catch (IOException e) {
				e.printStackTrace();
			}
			init(os, log_tag, verbose_level, max_size);
		} else {
			init(null, log_tag, 0, 0);
			do_log = false;
		}
	}

	/** ************************** Protected methods *************************** */

	/** Initializes the log */
	protected void init(PrintStream out_stream, String log_tag,
			int verbose_level, long max_size) {
		this.out_stream = out_stream;
		this.log_tag = log_tag;
		this.verbose_level = verbose_level;
		this.max_size = max_size;

		if (log_tag != null)
			tag_size = log_tag.length() + 2;
		else
			tag_size = 0;
		do_log = true;
		counter = 0;
	}

	/** Flushes */
	protected Log flush() {
		if (verbose_level > 0)
			out_stream.flush();
		return this;
	}

	/** *************************** Public methods **************************** */

	/** Closes the log */
	public void close() {
		do_log = false;
		out_stream.close();
	}

	/** Logs the Exception */
	public Log printException(Exception e, int level) { // ByteArrayOutputStream
		// err=new
		// ByteArrayOutputStream();
		// e.printStackTrace(new PrintStream(err));
		// return println("Exception: "+err.toString(),level);
		return println("Exception: " + ExceptionPrinter.getStackTraceOf(e),
				level);
	}

	/** Logs the Exception.toString() and Exception.printStackTrace() */
	public Log printException(Exception e) {
		return printException(e, 1);
	}

	/** Logs the packet timestamp */
	public Log printPacketTimestamp(String proto, String remote_addr,
			int remote_port, int len, String message, int level) {
		String str = remote_addr + ":" + remote_port + "/" + proto + " (" + len
				+ " bytes)";
		if (message != null)
			str += ": " + message;
		println(DateFormat.formatHHMMSS(new Date()) + ", " + str, level);
		return this;
	}

	/**
	 * Prints the <i>log</i> if <i>level</i> isn't greater than the Log
	 * <i>verbose_level</i>
	 */
	public Log println(String message, int level) {
		return print(message + "\r\n", level).flush();
	}

	/** Prints the <i>log</i> if the Log <i>verbose_level</i> is greater than 0 */
	public Log println(String message) {
		return println(message, 1);
	}

	/** Prints the <i>log</i> if the Log <i>verbose_level</i> is greater than 0 */
	public Log print(String message) {
		return print(message, 1);
	}

	/**
	 * Prints the <i>log</i> if <i>level</i> isn't greater than the Log
	 * <i>verbose_level</i>
	 */
	public Log print(String message, int level) {
		if (do_log && level <= verbose_level) {
			if (log_tag != null)
				out_stream.print(log_tag + ": " + message);
			else
				out_stream.print(message);

			if (max_size >= 0) {
				counter += tag_size + message.length();
				if (counter > max_size) {
					out_stream
							.println("\r\n----MAXIMUM LOG SIZE----\r\nSuccessive logs are lost.");
					do_log = false;
				}
			}
		}
		return this;
	}

}
