/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <log4cxx/writerappender.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/helpers/synchronized.h>
#include <log4cxx/layout.h>
#include <log4cxx/helpers/stringhelper.h>

using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::spi;

IMPLEMENT_LOG4CXX_OBJECT(WriterAppender)

WriterAppender::WriterAppender()
{
	LOCK_W sync(mutex);
	immediateFlush = true;
}

WriterAppender::WriterAppender(const LayoutPtr& layout1,
	log4cxx::helpers::WriterPtr& writer1)
	: AppenderSkeleton(layout1), writer(writer1)
{
	Pool p;
	LOCK_W sync(mutex);
	immediateFlush = true;
	activateOptions(p);
}

WriterAppender::WriterAppender(const LayoutPtr& layout1)
	: AppenderSkeleton(layout1)
{
	LOCK_W sync(mutex);
	immediateFlush = true;
}


WriterAppender::~WriterAppender()
{
	finalize();
}

void WriterAppender::activateOptions(Pool& p)
{
	int errors = 0;

	if (layout == 0)
	{
		errorHandler->error(
			((LogString) LOG4CXX_STR("No layout set for the appender named ["))
			+ name + LOG4CXX_STR("]."));
		errors++;
	}

	if (writer == 0)
	{
		errorHandler->error(
			((LogString) LOG4CXX_STR("No writer set for the appender named ["))
			+ name + LOG4CXX_STR("]."));
		errors++;
	}

	if (errors == 0)
	{
		AppenderSkeleton::activateOptions(p);
	}
}



void WriterAppender::append(const spi::LoggingEventPtr& event, Pool& pool1)
{

	if (!checkEntryConditions())
	{
		return;
	}

	subAppend(event, pool1);
}

/**
   This method determines if there is a sense in attempting to append.

   <p>It checks whether there is a set output target and also if
   there is a set layout. If these checks fail, then the boolean
   value <code>false</code> is returned. */
bool WriterAppender::checkEntryConditions() const
{
	static bool warnedClosed = false;
	static bool warnedNoWriter = false;

	if (closed)
	{
		if (!warnedClosed)
		{
			LogLog::warn(LOG4CXX_STR("Not allowed to write to a closed appender."));
			warnedClosed = true;
		}

		return false;
	}

	if (writer == 0)
	{
		if (warnedNoWriter)
		{
			errorHandler->error(
				LogString(LOG4CXX_STR("No output stream or file set for the appender named [")) +
				name + LOG4CXX_STR("]."));
			warnedNoWriter = true;
		}

		return false;
	}

	if (layout == 0)
	{
		errorHandler->error(
			LogString(LOG4CXX_STR("No layout set for the appender named [")) +
			name + LOG4CXX_STR("]."));
		return false;
	}

	return true;
}




/**
   Close this appender instance. The underlying stream or writer is
   also closed.

   <p>Closed appenders cannot be reused.

   @see #setWriter
   */
void WriterAppender::close()
{
	LOCK_W sync(mutex);

	if (closed)
	{
		return;
	}

	closed = true;
	closeWriter();
}

/**
 * Close the underlying {@link java.io.Writer}.
 * */
void WriterAppender::closeWriter()
{
	if (writer != NULL)
	{
		try
		{
			// before closing we have to output out layout's footer
			//
			//   Using the object's pool since this is a one-shot operation
			//    and pool is likely to be reclaimed soon when appender is destructed.
			//
			writeFooter(pool);
			writer->close(pool);
			writer = 0;
		}
		catch (IOException& e)
		{
			LogLog::error(LogString(LOG4CXX_STR("Could not close writer for WriterAppender named ")) + name, e);
		}
	}

}

/**
   Returns an OutputStreamWriter when passed an OutputStream.  The
   encoding used will depend on the value of the
   <code>encoding</code> property.  If the encoding value is
   specified incorrectly the writer will be opened using the default
   system encoding (an error message will be printed to the loglog.  */
WriterPtr WriterAppender::createWriter(OutputStreamPtr& os)
{

	LogString enc(getEncoding());

	CharsetEncoderPtr encoder;

	if (enc.empty())
	{
		encoder = CharsetEncoder::getDefaultEncoder();
	}
	else
	{
		if (StringHelper::equalsIgnoreCase(enc,
				LOG4CXX_STR("utf-16"), LOG4CXX_STR("UTF-16")))
		{
			encoder = CharsetEncoder::getEncoder(LOG4CXX_STR("UTF-16BE"));
		}
		else
		{
			encoder = CharsetEncoder::getEncoder(enc);
		}

		if (encoder == NULL)
		{
			encoder = CharsetEncoder::getDefaultEncoder();
			LogLog::warn(LOG4CXX_STR("Error initializing output writer."));
			LogLog::warn(LOG4CXX_STR("Unsupported encoding?"));
		}
	}

	return new OutputStreamWriter(os, encoder);
}

LogString WriterAppender::getEncoding() const
{
	return encoding;
}

void WriterAppender::setEncoding(const LogString& enc)
{
	encoding = enc;
}

void WriterAppender::subAppend(const spi::LoggingEventPtr& event, Pool& p)
{
	LogString msg;
	layout->format(msg, event, p);
	{
		LOCK_W sync(mutex);

		if (writer != NULL)
		{
			writer->write(msg, p);

			if (immediateFlush)
			{
				writer->flush(p);
			}
		}
	}
}


void WriterAppender::writeFooter(Pool& p)
{
	if (layout != NULL)
	{
		LogString foot;
		layout->appendFooter(foot, p);
		LOCK_W sync(mutex);
		writer->write(foot, p);
	}
}

void WriterAppender::writeHeader(Pool& p)
{
	if (layout != NULL)
	{
		LogString header;
		layout->appendHeader(header, p);
		LOCK_W sync(mutex);
		writer->write(header, p);
	}
}


void WriterAppender::setWriter(const WriterPtr& newWriter)
{
	LOCK_W sync(mutex);
	writer = newWriter;
}


bool WriterAppender::requiresLayout() const
{
	return true;
}

void WriterAppender::setOption(const LogString& option, const LogString& value)
{
	if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("ENCODING"), LOG4CXX_STR("encoding")))
	{
		setEncoding(value);
	}
	else
	{
		AppenderSkeleton::setOption(option, value);
	}
}


void WriterAppender::setImmediateFlush(bool value)
{
	LOCK_W sync(mutex);
	immediateFlush = value;
}
