/*
 * 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.
 */

#ifndef _LOG4CXX_APPENDER_SKELETON_H
#define _LOG4CXX_APPENDER_SKELETON_H

#if defined(_MSC_VER)
	#pragma warning ( push )
	#pragma warning ( disable: 4231 4251 4275 4786 )
#endif


#include <log4cxx/appender.h>
#include <log4cxx/layout.h>
#include <log4cxx/spi/errorhandler.h>
#include <log4cxx/spi/filter.h>
#include <log4cxx/helpers/object.h>
#include <log4cxx/helpers/pool.h>
#include <log4cxx/level.h>

namespace log4cxx
{
/**
*  Implementation base class for all appenders.
*
*  This class provides the code for common functionality, such as
*  support for threshold filtering and support for general filters.
* */
class LOG4CXX_EXPORT AppenderSkeleton :
	public virtual Appender,
	public virtual helpers::Object
{
	protected:
		/** The layout variable does not need to be set if the appender
		implementation has its own layout. */
		LayoutPtr layout;

		/** Appenders are named. */
		LogString name;

		/**
		There is no level threshold filtering by default.  */
		LevelPtr threshold;

		/**
		It is assumed and enforced that errorHandler is never null.
		*/
		spi::ErrorHandlerPtr errorHandler;

		/** The first filter in the filter chain. Set to <code>null</code>
		initially. */
		spi::FilterPtr headFilter;

		/** The last filter in the filter chain. */
		spi::FilterPtr tailFilter;

		/**
		Is this appender closed?
		*/
		bool closed;

		log4cxx::helpers::Pool pool;
		mutable log4cxx::shared_mutex mutex;

		/**
		Subclasses of <code>AppenderSkeleton</code> should implement this
		method to perform actual logging. See also AppenderSkeleton::doAppend
		method.
		*/
		virtual void append(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& p) = 0;

		void doAppendImpl(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& pool);

	public:
		DECLARE_ABSTRACT_LOG4CXX_OBJECT(AppenderSkeleton)
		BEGIN_LOG4CXX_CAST_MAP()
		LOG4CXX_CAST_ENTRY(AppenderSkeleton)
		LOG4CXX_CAST_ENTRY(Appender)
		LOG4CXX_CAST_ENTRY(spi::OptionHandler)
		END_LOG4CXX_CAST_MAP()

		AppenderSkeleton();
		AppenderSkeleton(const LayoutPtr& layout);

		/**
		Finalize this appender by calling the derived class'
		<code>close</code> method.
		*/
		void finalize();

		/**
		Derived appenders should override this method if option structure
		requires it.
		*/
		virtual void activateOptions(log4cxx::helpers::Pool& /* pool */) {}
		virtual void setOption(const LogString& option, const LogString& value);

		/**
		Add a filter to end of the filter list.
		*/
		void addFilter(const spi::FilterPtr& newFilter) ;

	public:
		/**
		Clear the filters chain.
		*/
		void clearFilters();

		/**
		Return the currently set spi::ErrorHandler for this
		Appender.
		*/
		const spi::ErrorHandlerPtr& getErrorHandler() const
		{
			return errorHandler;
		}

		/**
		Returns the head Filter.
		*/
		spi::FilterPtr getFilter() const
		{
			return headFilter;
		}

		/**
		Return the first filter in the filter chain for this
		Appender. The return value may be <code>0</code> if no is
		filter is set.
		*/
		const spi::FilterPtr& getFirstFilter() const
		{
			return headFilter;
		}

		/**
		Returns the layout of this appender. The value may be 0.
		*/
		LayoutPtr getLayout() const
		{
			return layout;
		}


		/**
		Returns the name of this Appender.
		*/
		LogString getName() const
		{
			return name;
		}

		/**
		Returns this appenders threshold level. See the #setThreshold
		method for the meaning of this option.
		*/
		const LevelPtr& getThreshold() const
		{
			return threshold;
		}

		/**
		Check whether the message level is below the appender's
		threshold. If there is no threshold set, then the return value is
		always <code>true</code>.
		*/
		bool isAsSevereAsThreshold(const LevelPtr& level) const;


		/**
		* This method performs threshold checks and invokes filters before
		* delegating actual logging to the subclasses specific
		* AppenderSkeleton#append method.
		* */
		virtual void doAppend(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& pool);

		/**
		Set the {@link spi::ErrorHandler ErrorHandler} for this Appender.
		*/
		void setErrorHandler(const spi::ErrorHandlerPtr eh);

		/**
		Set the layout for this appender. Note that some appenders have
		their own (fixed) layouts or do not use one. For example, the
		{@link net::SocketAppender SocketAppender} ignores the layout set
		here.
		*/
		void setLayout(const LayoutPtr& layout1)
		{
			this->layout = layout1;
		}

		/**
		Set the name of this Appender.
		*/
		void setName(const LogString& name1)
		{
			this->name.assign(name1);
		}


		/**
		Set the threshold level. All log events with lower level
		than the threshold level are ignored by the appender.

		<p>In configuration files this option is specified by setting the
		value of the <b>Threshold</b> option to a level
		string, such as "DEBUG", "INFO" and so on.
		*/
		void setThreshold(const LevelPtr& threshold);

}; // class AppenderSkeleton
}  // namespace log4cxx

#if defined(_MSC_VER)
	#pragma warning ( pop )
#endif


#endif //_LOG4CXX_APPENDER_SKELETON_H
