//==============================================================================
//	
//	Copyright (c) 2002-
//	Authors:
//	* Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford, formerly University of Birmingham)
//	
//------------------------------------------------------------------------------
//	
//	This file is part of PRISM.
//	
//	PRISM 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.
//	
//	PRISM 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 PRISM; if not, write to the Free Software Foundation,
//	Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//	
//==============================================================================

package prism;

/**
 * PrismLog object that writes all output to a file. 
 */
public class PrismFileLog extends PrismLog
{
	/** Filename (or "stdout") */
	protected String filename;
	/** Native file pointer, cast to a long */
	protected long fp;
	/** Are we writing to stdout? */
	protected boolean stdout;
	
	/**
	 * Pointless constructor. Don't call this.
	 */
	public PrismFileLog()
	{
		filename = "";
		fp = 0;
	}

	/**
	 * Create a PRISM log which will write to {@code filename}, overwriting any previous contents.
	 * @param filename Filename of log file
	 */
	public PrismFileLog(String filename)
	{
		open(filename);
	}

	/**
	 * Create a PRISM log which will write to {@code filename}, appending to an existing file if requested.
	 * @param filename Filename of log file
	 * @param append Append to the existing file?
	 */
	public PrismFileLog(String filename, boolean append)
	{
		open(filename, append);
	}

	/**
	 * Create a PRISM log which will write to {@code filename}, overwriting any previous contents.
	 * Throw a PRISM exception if there is a problem opening the file for writing.
	 * @param filename Filename of log file
	 */
	public static PrismFileLog create(String filename) throws PrismException
	{
		return create(filename, false);
	}
	
	/**
	 * Create a PRISM log which will write to {@code filename}, appending to an existing file if requested.
	 * Throw a PRISM exception if there is a problem opening the file for writing.
	 * @param filename Filename of log file
	 * @param append Append to the existing file?
	 */
	public static PrismFileLog create(String filename, boolean append) throws PrismException
	{
		PrismFileLog log = new PrismFileLog(filename, append);
		if (!log.ready()) {
			throw new PrismException("Could not open file \"" + filename + "\" for output");
		}
		return log;
	}
	
	public void open(String filename)
	{
		open (filename, false);
	}
	
	public void open(String filename, boolean append)
	{
		this.filename = filename;
		if (filename.equals("stdout")) {
			fp = PrismNative.PN_GetStdout();
			stdout = true;
		}
		else {
			fp = append ? PrismNative.PN_OpenFileAppend(filename) : PrismNative.PN_OpenFile(filename);
			stdout = false;
		}
	}

	// Methods for PrismLog
	
	@Override
	public boolean ready()
	{
		return (fp != 0);
	}

	@Override
	public long getFilePointer()
	{
		return fp;
	}

	/** Get the filename (or "stdout" if writing to standard output) */
	public String getFileName()
	{
		return stdout ? "stdout" : filename;
	}

	@Override
	public void flush()
	{
		if (fp == 0) {
			throw new IllegalStateException("Trying to flush an invalid file handle (already closed?)");
		}
		PrismNative.PN_FlushFile(fp);
	}

	@Override
	public void close()
	{
		if (fp == 0) {
			// already closed, ignore (as specified by Closable contract)
			return;
		}

		if (stdout) {
			// we never close stdout
			return;
		}

		PrismNative.PN_CloseFile(fp);
		// set fp to zero to indicate that the file handle is not valid anymore
		fp = 0;
	}
	
	@Override
	public void print(boolean b)
	{
		printToLog("" + b);
	}

	@Override
	public void print(char c)
	{
		printToLog("" + c);
	}

	@Override
	public void print(double d)
	{
		printToLog("" + d);
	}

	@Override
	public void print(float f)
	{
		printToLog("" + f);
	}

	@Override
	public void print(int i)
	{
		printToLog("" + i);
	}

	@Override
	public void print(long l)
	{
		printToLog("" + l);
	}

	@Override
	public void print(Object obj)
	{
		printToLog("" + obj);
	}

	@Override
	public void print(String s)
	{
		printToLog(s);
	}

	@Override
	public void println()
	{
		printToLog("\n");
	}

	/**
	 * Do the actual write (via native code).
	 */
	private void printToLog(String s)
	{
		if (fp == 0) {
			throw new IllegalStateException("Trying to write to an invalid file handle (already closed?)");
		}

		PrismNative.PN_PrintToFile(fp, s);
	}
}

//------------------------------------------------------------------------------
