/*
 * 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_ASYNC_APPENDER_H
#define _LOG4CXX_ASYNC_APPENDER_H

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


#include <log4cxx/appenderskeleton.h>
#include <log4cxx/helpers/appenderattachableimpl.h>
#include <deque>
#include <log4cxx/spi/loggingevent.h>
#include <log4cxx/helpers/thread.h>
#include <log4cxx/helpers/mutex.h>
#include <log4cxx/helpers/condition.h>

#if defined(NON_BLOCKING)
	#include <boost/lockfree/queue.hpp>
#endif

namespace log4cxx
{
LOG4CXX_LIST_DEF(LoggingEventList, log4cxx::spi::LoggingEventPtr);

/**
The AsyncAppender lets users log events asynchronously. It uses a
bounded buffer to store logging events.

<p>The AsyncAppender will collect the events sent to it and then
dispatch them to all the appenders that are attached to it. You can
attach multiple appenders to an AsyncAppender.

<p>The AsyncAppender uses a separate thread to serve the events in
its bounded buffer.

<p><b>Important note:</b> The <code>AsyncAppender</code> can only
be script configured using the {@link xml::DOMConfigurator DOMConfigurator}.
*/
class LOG4CXX_EXPORT AsyncAppender :
	public virtual spi::AppenderAttachable,
	public virtual AppenderSkeleton
{
	public:
		DECLARE_LOG4CXX_OBJECT(AsyncAppender)
		BEGIN_LOG4CXX_CAST_MAP()
		LOG4CXX_CAST_ENTRY(AsyncAppender)
		LOG4CXX_CAST_ENTRY_CHAIN(AppenderSkeleton)
		LOG4CXX_CAST_ENTRY(spi::AppenderAttachable)
		END_LOG4CXX_CAST_MAP()

		/**
		 * Create new instance.
		*/
		AsyncAppender();

		/**
		 *  Destructor.
		 */
		virtual ~AsyncAppender();

		void addRef() const;
		void releaseRef() const;

		/**
		 * Add appender.
		 *
		 * @param newAppender appender to add, may not be null.
		*/
		void addAppender(const AppenderPtr& newAppender);

		virtual void doAppend(const spi::LoggingEventPtr& event,
			log4cxx::helpers::Pool& pool1);

		void append(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& p);

		/**
		Close this <code>AsyncAppender</code> by interrupting the
		dispatcher thread which will process all pending events before
		exiting.
		*/
		void close();

		/**
		 * Get iterator over attached appenders.
		 * @return list of all attached appenders.
		*/
		AppenderList getAllAppenders() const;

		/**
		 * Get appender by name.
		 *
		 * @param name name, may not be null.
		 * @return matching appender or null.
		*/
		AppenderPtr getAppender(const LogString& name) const;

		/**
		 * Gets whether the location of the logging request call
		 * should be captured.
		 *
		 * @return the current value of the <b>LocationInfo</b> option.
		*/
		bool getLocationInfo() const;
		/**
		* Determines if specified appender is attached.
		* @param appender appender.
		* @return true if attached.
		*/
		bool isAttached(const AppenderPtr& appender) const;

		virtual bool requiresLayout() const;

		/**
		 * Removes and closes all attached appenders.
		*/
		void removeAllAppenders();

		/**
		 * Removes an appender.
		 * @param appender appender to remove.
		*/
		void removeAppender(const AppenderPtr& appender);
		/**
		* Remove appender by name.
		* @param name name.
		*/
		void removeAppender(const LogString& name);

		/**
		* The <b>LocationInfo</b> attribute is provided for compatibility
		* with log4j and has no effect on the log output.
		* @param flag new value.
		*/
		void setLocationInfo(bool flag);

		/**
		* The <b>BufferSize</b> option takes a non-negative integer value.
		* This integer value determines the maximum size of the bounded
		* buffer.
		* */
		void setBufferSize(int size);

		/**
		 * Gets the current buffer size.
		 * @return the current value of the <b>BufferSize</b> option.
		*/
		int getBufferSize() const;

		/**
		 * Sets whether appender should wait if there is no
		 * space available in the event buffer or immediately return.
		 *
		 * @param value true if appender should wait until available space in buffer.
		 */
		void setBlocking(bool value);

		/**
		 * Gets whether appender should block calling thread when buffer is full.
		 * If false, messages will be counted by logger and a summary
		 * message appended after the contents of the buffer have been appended.
		 *
		 * @return true if calling thread will be blocked when buffer is full.
		 */
		bool getBlocking() const;


		/**
		 * Set appender properties by name.
		 * @param option property name.
		 * @param value property value.
		 */
		void setOption(const LogString& option, const LogString& value);


	private:
		AsyncAppender(const AsyncAppender&);
		AsyncAppender& operator=(const AsyncAppender&);
		/**
		 * The default buffer size is set to 128 events.
		*/
		enum { DEFAULT_BUFFER_SIZE = 128 };

		/**
		 * Event buffer.
		*/
#if defined(NON_BLOCKING)
		boost::lockfree::queue<log4cxx::spi::LoggingEvent* > buffer;
		std::atomic<size_t> discardedCount;
#else
		LoggingEventList buffer;
#endif

		/**
		 *  Mutex used to guard access to buffer and discardMap.
		 */
		SHARED_MUTEX bufferMutex;

#if defined(NON_BLOCKING)
		::log4cxx::helpers::Semaphore bufferNotFull;
		::log4cxx::helpers::Semaphore bufferNotEmpty;
#else
		::log4cxx::helpers::Condition bufferNotFull;
		::log4cxx::helpers::Condition bufferNotEmpty;
#endif
		class DiscardSummary
		{
			private:
				/**
				 * First event of the highest severity.
				*/
				::log4cxx::spi::LoggingEventPtr maxEvent;

				/**
				* Total count of messages discarded.
				*/
				int count;

			public:
				/**
				 * Create new instance.
				 *
				 * @param event event, may not be null.
				*/
				DiscardSummary(const ::log4cxx::spi::LoggingEventPtr& event);
				/** Copy constructor.  */
				DiscardSummary(const DiscardSummary& src);
				/** Assignment operator. */
				DiscardSummary& operator=(const DiscardSummary& src);

				/**
				 * Add discarded event to summary.
				 *
				 * @param event event, may not be null.
				*/
				void add(const ::log4cxx::spi::LoggingEventPtr& event);

				/**
				 * Create event with summary information.
				 *
				 * @return new event.
				 */
				::log4cxx::spi::LoggingEventPtr createEvent(::log4cxx::helpers::Pool& p);

				static
				::log4cxx::spi::LoggingEventPtr createEvent(::log4cxx::helpers::Pool& p,
					size_t discardedCount);
		};

		/**
		  * Map of DiscardSummary objects keyed by logger name.
		*/
		typedef std::map<LogString, DiscardSummary> DiscardMap;
		DiscardMap* discardMap;

		/**
		 * Buffer size.
		*/
		int bufferSize;

		/**
		 * Nested appenders.
		*/
		helpers::AppenderAttachableImplPtr appenders;

		/**
		 *  Dispatcher.
		 */
		helpers::Thread dispatcher;

		/**
		 * Should location info be included in dispatched messages.
		*/
		bool locationInfo;

		/**
		 * Does appender block when buffer is full.
		*/
		bool blocking;

		/**
		 *  Dispatch routine.
		 */
		static void* LOG4CXX_THREAD_FUNC dispatch(apr_thread_t* thread, void* data);

}; // class AsyncAppender
LOG4CXX_PTR_DEF(AsyncAppender);
}  //  namespace log4cxx

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


#endif//  _LOG4CXX_ASYNC_APPENDER_H

