#region Apache License
//
// 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.
//
#endregion

using System;
using System.Collections;
using System.IO;

using log4net.Core;
using log4net.Layout.Pattern;
using log4net.Util;
using log4net.Util.PatternStringConverters;
using AppDomainPatternConverter=log4net.Layout.Pattern.AppDomainPatternConverter;
using DatePatternConverter=log4net.Layout.Pattern.DatePatternConverter;
using IdentityPatternConverter=log4net.Layout.Pattern.IdentityPatternConverter;
using PropertyPatternConverter=log4net.Layout.Pattern.PropertyPatternConverter;
using UserNamePatternConverter=log4net.Layout.Pattern.UserNamePatternConverter;
using UtcDatePatternConverter=log4net.Layout.Pattern.UtcDatePatternConverter;

namespace log4net.Layout
{
	/// <summary>
	/// A flexible layout configurable with pattern string.
	/// </summary>
	/// <remarks>
	/// <para>
	/// The goal of this class is to <see cref="M:PatternLayout.Format(TextWriter,LoggingEvent)"/> a 
	/// <see cref="LoggingEvent"/> as a string. The results
	/// depend on the <i>conversion pattern</i>.
	/// </para>
	/// <para>
	/// The conversion pattern is closely related to the conversion
	/// pattern of the printf function in C. A conversion pattern is
	/// composed of literal text and format control expressions called
	/// <i>conversion specifiers</i>.
	/// </para>
	/// <para>
	/// <i>You are free to insert any literal text within the conversion
	/// pattern.</i>
	/// </para>
	/// <para>
	/// Each conversion specifier starts with a percent sign (%) and is
	/// followed by optional <i>format modifiers</i> and a <i>conversion
	/// pattern name</i>. The conversion pattern name specifies the type of
	/// data, e.g. logger, level, date, thread name. The format
	/// modifiers control such things as field width, padding, left and
	/// right justification. The following is a simple example.
	/// </para>
	/// <para>
	/// Let the conversion pattern be <b>"%-5level [%thread]: %message%newline"</b> and assume
	/// that the log4net environment was set to use a PatternLayout. Then the
	/// statements
	/// </para>
	/// <code lang="C#">
	/// ILog log = LogManager.GetLogger(typeof(TestApp));
	/// log.Debug("Message 1");
	/// log.Warn("Message 2");   
	/// </code>
	/// <para>would yield the output</para>
	/// <code>
	/// DEBUG [main]: Message 1
	/// WARN  [main]: Message 2  
	/// </code>
	/// <para>
	/// Note that there is no explicit separator between text and
	/// conversion specifiers. The pattern parser knows when it has reached
	/// the end of a conversion specifier when it reads a conversion
	/// character. In the example above the conversion specifier
	/// <b>%-5level</b> means the level of the logging event should be left
	/// justified to a width of five characters.
	/// </para>
	/// <para>
	/// The recognized conversion pattern names are:
	/// </para>
	/// <list type="table">
	///     <listheader>
	///         <term>Conversion Pattern Name</term>
	///         <description>Effect</description>
	///     </listheader>
	///     <item>
	///         <term>a</term>
	///         <description>Equivalent to <b>appdomain</b></description>
	///     </item>
	///     <item>
	///         <term>appdomain</term>
	///         <description>
	///				Used to output the friendly name of the AppDomain where the 
	///				logging event was generated. 
	///         </description>
	///     </item>
	///     <item>
	///         <term>aspnet-cache</term>
	///         <description>
    ///             <para>
    ///             Used to output all cache items in the case of <b>%aspnet-cache</b> or just one named item if used as <b>%aspnet-cache{key}</b>
    ///             </para>
    ///             <para>
    ///             This pattern is not available for Compact Framework or Client Profile assemblies.
    ///             </para>
	///         </description>
	///     </item>
	///     <item>
	///         <term>aspnet-context</term>
	///         <description>
    ///             <para>
    ///             Used to output all context items in the case of <b>%aspnet-context</b> or just one named item if used as <b>%aspnet-context{key}</b>
    ///             </para>
    ///             <para>
    ///             This pattern is not available for Compact Framework or Client Profile assemblies.
    ///             </para>
    ///         </description>
	///     </item>
	///     <item>
	///         <term>aspnet-request</term>
	///         <description>
    ///             <para>
    ///             Used to output all request parameters in the case of <b>%aspnet-request</b> or just one named param if used as <b>%aspnet-request{key}</b>
    ///             </para>
    ///             <para>
    ///             This pattern is not available for Compact Framework or Client Profile assemblies.
    ///             </para>
    ///         </description>
	///     </item>
	///     <item>
	///         <term>aspnet-session</term>
	///         <description>
    ///             <para>
    ///             Used to output all session items in the case of <b>%aspnet-session</b> or just one named item if used as <b>%aspnet-session{key}</b>
    ///             </para>
    ///             <para>
    ///             This pattern is not available for Compact Framework or Client Profile assemblies.
    ///             </para>
    ///         </description>
	///     </item>
	///     <item>
	///         <term>c</term>
	///         <description>Equivalent to <b>logger</b></description>
	///     </item>
	///     <item>
	///         <term>C</term>
	///         <description>Equivalent to <b>type</b></description>
	///     </item>
	///     <item>
	///         <term>class</term>
	///         <description>Equivalent to <b>type</b></description>
	///     </item>
	///     <item>
	///         <term>d</term>
	///         <description>Equivalent to <b>date</b></description>
	///     </item>
	///     <item>
	///			<term>date</term> 
	///			<description>
	/// 			<para>
	/// 			Used to output the date of the logging event in the local time zone. 
	/// 			To output the date in universal time use the <c>%utcdate</c> pattern.
	/// 			The date conversion 
	/// 			specifier may be followed by a <i>date format specifier</i> enclosed 
	/// 			between braces. For example, <b>%date{HH:mm:ss,fff}</b> or
	/// 			<b>%date{dd MMM yyyy HH:mm:ss,fff}</b>.  If no date format specifier is 
	/// 			given then ISO8601 format is
	/// 			assumed (<see cref="log4net.DateFormatter.Iso8601DateFormatter"/>).
	/// 			</para>
	/// 			<para>
	/// 			The date format specifier admits the same syntax as the
	/// 			time pattern string of the <see cref="M:DateTime.ToString(string)"/>.
	/// 			</para>
	/// 			<para>
	/// 			For better results it is recommended to use the log4net date
	/// 			formatters. These can be specified using one of the strings
	/// 			"ABSOLUTE", "DATE" and "ISO8601" for specifying 
	/// 			<see cref="log4net.DateFormatter.AbsoluteTimeDateFormatter"/>, 
	/// 			<see cref="log4net.DateFormatter.DateTimeDateFormatter"/> and respectively 
	/// 			<see cref="log4net.DateFormatter.Iso8601DateFormatter"/>. For example, 
	/// 			<b>%date{ISO8601}</b> or <b>%date{ABSOLUTE}</b>.
	/// 			</para>
	/// 			<para>
	/// 			These dedicated date formatters perform significantly
	/// 			better than <see cref="M:DateTime.ToString(string)"/>.
	/// 			</para>
	///			</description>
	///		</item>
	///		<item>
	///			<term>exception</term>
	///			<description>
	///				<para>
	///				Used to output the exception passed in with the log message.
	///				</para>
	///				<para>
	/// 			If an exception object is stored in the logging event
	/// 			it will be rendered into the pattern output with a
	/// 			trailing newline.
	/// 			If there is no exception then nothing will be output
	/// 			and no trailing newline will be appended.
	/// 			It is typical to put a newline before the exception
	/// 			and to have the exception as the last data in the pattern.
	///				</para>
	///			</description>
	///		</item>
	///     <item>
	///         <term>F</term>
	///         <description>Equivalent to <b>file</b></description>
	///     </item>
	///		<item>
	///			<term>file</term>
	///			<description>
	///				<para>
	///				Used to output the file name where the logging request was
	///				issued.
	///				</para>
	///				<para>
	///				<b>WARNING</b> Generating caller location information is
	///				extremely slow. Its use should be avoided unless execution speed
	///				is not an issue.
	///				</para>
	/// 			<para>
	/// 			See the note below on the availability of caller location information.
	/// 			</para>
	///			</description>
	///		</item>
	///		<item>
	///			<term>identity</term>
	///			<description>
	///				<para>
	///				Used to output the user name for the currently active user
	///				(Principal.Identity.Name).
	///				</para>
	///				<para>
	///				<b>WARNING</b> Generating caller information is
	///				extremely slow. Its use should be avoided unless execution speed
	///				is not an issue.
	///				</para>
	///			</description>
	///		</item>
	///     <item>
	///         <term>l</term>
	///         <description>Equivalent to <b>location</b></description>
	///     </item>
	///     <item>
	///         <term>L</term>
	///         <description>Equivalent to <b>line</b></description>
	///     </item>
	///		<item>
	///			<term>location</term>
	///			<description>
	/// 			<para>
	/// 			Used to output location information of the caller which generated
	/// 			the logging event.
	/// 			</para>
	/// 			<para>
	/// 			The location information depends on the CLI implementation but
	/// 			usually consists of the fully qualified name of the calling
	/// 			method followed by the callers source the file name and line
	/// 			number between parentheses.
	/// 			</para>
	/// 			<para>
	/// 			The location information can be very useful. However, its
	/// 			generation is <b>extremely</b> slow. Its use should be avoided
	/// 			unless execution speed is not an issue.
	/// 			</para>
	/// 			<para>
	/// 			See the note below on the availability of caller location information.
	/// 			</para>
	///			</description>
	///		</item>
	///		<item>
	///			<term>level</term>
	///			<description>
	/// 			<para>
	/// 			Used to output the level of the logging event.
	/// 			</para>
	///			</description>
	///		</item>
	///		<item>
	///			<term>line</term>
	///			<description>
	///				<para>
	///				Used to output the line number from where the logging request
	///				was issued.
	///				</para>
	///				<para>
	///				<b>WARNING</b> Generating caller location information is
	///				extremely slow. Its use should be avoided unless execution speed
	///				is not an issue.
	///				</para>
	/// 			<para>
	/// 			See the note below on the availability of caller location information.
	/// 			</para>
	///			</description>
	///		</item>
	///     <item>
	///         <term>logger</term>
	///         <description>
	///             <para>
	///				Used to output the logger of the logging event. The
	/// 			logger conversion specifier can be optionally followed by
	/// 			<i>precision specifier</i>, that is a decimal constant in
	/// 			brackets.
	///             </para>
	/// 			<para>
	/// 			If a precision specifier is given, then only the corresponding
	/// 			number of right most components of the logger name will be
	/// 			printed. By default the logger name is printed in full.
	/// 			</para>
	/// 			<para>
	/// 			For example, for the logger name "a.b.c" the pattern
	/// 			<b>%logger{2}</b> will output "b.c".
	/// 			</para>
	///         </description>
	///     </item>
	///     <item>
	///         <term>m</term>
	///         <description>Equivalent to <b>message</b></description>
	///     </item>
	///     <item>
	///         <term>M</term>
	///         <description>Equivalent to <b>method</b></description>
	///     </item>
	///		<item>
	///			<term>message</term>
	///			<description>
	/// 			<para>
	/// 			Used to output the application supplied message associated with 
	/// 			the logging event.
	/// 			</para>
	///			</description>
	///		</item>
	///		<item>
	///			<term>mdc</term>
	///			<description>
	/// 			<para>
	/// 			The MDC (old name for the ThreadContext.Properties) is now part of the
	/// 			combined event properties. This pattern is supported for compatibility
	/// 			but is equivalent to <b>property</b>.
	/// 			</para>
	///			</description>
	///		</item>
	///		<item>
	///			<term>method</term>
	///			<description>
	///				<para>
	///				Used to output the method name where the logging request was
	///				issued.
	///				</para>
	///				<para>
	///				<b>WARNING</b> Generating caller location information is
	///				extremely slow. Its use should be avoided unless execution speed
	///				is not an issue.
	///				</para>
	/// 			<para>
	/// 			See the note below on the availability of caller location information.
	/// 			</para>
	///			</description>
	///		</item>
	///     <item>
	///         <term>n</term>
	///         <description>Equivalent to <b>newline</b></description>
	///     </item>
	///		<item>
	///			<term>newline</term>
	///			<description>
	/// 			<para>
	/// 			Outputs the platform dependent line separator character or
	/// 			characters.
	/// 			</para>
	/// 			<para>
	/// 			This conversion pattern offers the same performance as using 
	/// 			non-portable line separator strings such as	"\n", or "\r\n". 
	/// 			Thus, it is the preferred way of specifying a line separator.
	/// 			</para> 
	///			</description>
	///		</item>
	///		<item>
	///			<term>ndc</term>
	///			<description>
	/// 			<para>
	/// 			Used to output the NDC (nested diagnostic context) associated
	/// 			with the thread that generated the logging event.
	/// 			</para>
	///			</description>
	///		</item>
	///     <item>
	///         <term>p</term>
	///         <description>Equivalent to <b>level</b></description>
	///     </item>
	///     <item>
	///         <term>P</term>
	///         <description>Equivalent to <b>property</b></description>
	///     </item>
	///     <item>
	///         <term>properties</term>
	///         <description>Equivalent to <b>property</b></description>
	///     </item>
	///		<item>
	///			<term>property</term>
	///			<description>
	/// 			<para>
	/// 			Used to output the an event specific property. The key to 
	/// 			lookup must be specified within braces and directly following the
	/// 			pattern specifier, e.g. <b>%property{user}</b> would include the value
	/// 			from the property that is keyed by the string 'user'. Each property value
	/// 			that is to be included in the log must be specified separately.
	/// 			Properties are added to events by loggers or appenders. By default 
	/// 			the <c>log4net:HostName</c> property is set to the name of machine on 
	/// 			which the event was originally logged.
	/// 			</para>
	/// 			<para>
	/// 			If no key is specified, e.g. <b>%property</b> then all the keys and their
	/// 			values are printed in a comma separated list.
	/// 			</para>
	/// 			<para>
	/// 			The properties of an event are combined from a number of different
	/// 			contexts. These are listed below in the order in which they are searched.
	/// 			</para>
	/// 			<list type="definition">
	/// 				<item>
	/// 					<term>the event properties</term>
	/// 					<description>
	/// 					The event has <see cref="LoggingEvent.Properties"/> that can be set. These 
	/// 					properties are specific to this event only.
	/// 					</description>
	/// 				</item>
	/// 				<item>
	/// 					<term>the thread properties</term>
	/// 					<description>
	/// 					The <see cref="ThreadContext.Properties"/> that are set on the current
	/// 					thread. These properties are shared by all events logged on this thread.
	/// 					</description>
	/// 				</item>
	/// 				<item>
	/// 					<term>the global properties</term>
	/// 					<description>
	/// 					The <see cref="GlobalContext.Properties"/> that are set globally. These 
	/// 					properties are shared by all the threads in the AppDomain.
	/// 					</description>
	/// 				</item>
	/// 			</list>
	/// 			
	///			</description>
	///		</item>
	///     <item>
	///         <term>r</term>
	///         <description>Equivalent to <b>timestamp</b></description>
	///     </item>
	/// 	<item>
	///			<term>stacktrace</term> 
	///			<description>
	/// 			<para>
	/// 			Used to output the stack trace of the logging event
	/// 			The stack trace level specifier may be enclosed 
	/// 			between braces. For example, <b>%stacktrace{level}</b>.  
	/// 			If no stack trace level specifier is given then 1 is assumed 
	/// 			</para>
    /// 			<para>
    /// 			Output uses the format:
    /// 			type3.MethodCall3 > type2.MethodCall2 > type1.MethodCall1
    /// 			</para>
    ///             <para>
    ///             This pattern is not available for Compact Framework assemblies.
    ///             </para>
    ///			</description>
	///		</item>
    /// 	<item>
    ///			<term>stacktracedetail</term> 
    ///			<description>
    /// 			<para>
    /// 			Used to output the stack trace of the logging event
    /// 			The stack trace level specifier may be enclosed 
    /// 			between braces. For example, <b>%stacktracedetail{level}</b>.  
    /// 			If no stack trace level specifier is given then 1 is assumed 
    /// 			</para>
    /// 			<para>
    /// 			Output uses the format:
    ///             type3.MethodCall3(type param,...) > type2.MethodCall2(type param,...) > type1.MethodCall1(type param,...)
    /// 			</para>
    ///             <para>
    ///             This pattern is not available for Compact Framework assemblies.
    ///             </para>
    ///			</description>
    ///		</item>
    ///     <item>
	///         <term>t</term>
	///         <description>Equivalent to <b>thread</b></description>
	///     </item>
	///		<item>
	///			<term>timestamp</term>
	///			<description>
	/// 			<para>
	/// 			Used to output the number of milliseconds elapsed since the start
	/// 			of the application until the creation of the logging event.
	/// 			</para>
	///			</description>
	///		</item>
	///		<item>
	///			<term>thread</term>
	///			<description>
	/// 			<para>
	/// 			Used to output the name of the thread that generated the
	/// 			logging event. Uses the thread number if no name is available.
	/// 			</para>
	///			</description>
	///		</item>
	///     <item>
	///			<term>type</term> 
	///			<description>
	/// 			<para>
	/// 			Used to output the fully qualified type name of the caller
	/// 			issuing the logging request. This conversion specifier
	/// 			can be optionally followed by <i>precision specifier</i>, that
	/// 			is a decimal constant in brackets.
	/// 			</para>
	/// 			<para>
	/// 			If a precision specifier is given, then only the corresponding
	/// 			number of right most components of the class name will be
	/// 			printed. By default the class name is output in fully qualified form.
	/// 			</para>
	/// 			<para>
	/// 			For example, for the class name "log4net.Layout.PatternLayout", the
	/// 			pattern <b>%type{1}</b> will output "PatternLayout".
	/// 			</para>
	/// 			<para>
	/// 			<b>WARNING</b> Generating the caller class information is
	/// 			slow. Thus, its use should be avoided unless execution speed is
	/// 			not an issue.
	/// 			</para>
	/// 			<para>
	/// 			See the note below on the availability of caller location information.
	/// 			</para>
	///			</description>
	///     </item>
	///     <item>
	///         <term>u</term>
	///         <description>Equivalent to <b>identity</b></description>
	///     </item>
	///		<item>
	///			<term>username</term>
	///			<description>
	///				<para>
	///				Used to output the WindowsIdentity for the currently
	///				active user.
	///				</para>
	///				<para>
	///				<b>WARNING</b> Generating caller WindowsIdentity information is
	///				extremely slow. Its use should be avoided unless execution speed
	///				is not an issue.
	///				</para>
	///			</description>
	///		</item>
	///     <item>
	///			<term>utcdate</term> 
	///			<description>
	/// 			<para>
	/// 			Used to output the date of the logging event in universal time. 
	/// 			The date conversion 
	/// 			specifier may be followed by a <i>date format specifier</i> enclosed 
	/// 			between braces. For example, <b>%utcdate{HH:mm:ss,fff}</b> or
	/// 			<b>%utcdate{dd MMM yyyy HH:mm:ss,fff}</b>.  If no date format specifier is 
	/// 			given then ISO8601 format is
	/// 			assumed (<see cref="log4net.DateFormatter.Iso8601DateFormatter"/>).
	/// 			</para>
	/// 			<para>
	/// 			The date format specifier admits the same syntax as the
	/// 			time pattern string of the <see cref="M:DateTime.ToString(string)"/>.
	/// 			</para>
	/// 			<para>
	/// 			For better results it is recommended to use the log4net date
	/// 			formatters. These can be specified using one of the strings
	/// 			"ABSOLUTE", "DATE" and "ISO8601" for specifying 
	/// 			<see cref="log4net.DateFormatter.AbsoluteTimeDateFormatter"/>, 
	/// 			<see cref="log4net.DateFormatter.DateTimeDateFormatter"/> and respectively 
	/// 			<see cref="log4net.DateFormatter.Iso8601DateFormatter"/>. For example, 
	/// 			<b>%utcdate{ISO8601}</b> or <b>%utcdate{ABSOLUTE}</b>.
	/// 			</para>
	/// 			<para>
	/// 			These dedicated date formatters perform significantly
	/// 			better than <see cref="M:DateTime.ToString(string)"/>.
	/// 			</para>
	///			</description>
	///		</item>
	///     <item>
	///         <term>w</term>
	///         <description>Equivalent to <b>username</b></description>
	///     </item>
	///     <item>
	///         <term>x</term>
	///         <description>Equivalent to <b>ndc</b></description>
	///     </item>
	///     <item>
	///         <term>X</term>
	///         <description>Equivalent to <b>mdc</b></description>
	///     </item>
	///		<item>
	///			<term>%</term>
	///			<description>
	/// 			<para>
	/// 			The sequence %% outputs a single percent sign.
	/// 			</para>
	///			</description>
	///		</item>
	/// </list>
	/// <para>
	/// The single letter patterns are deprecated in favor of the 
	/// longer more descriptive pattern names.
	/// </para>
	/// <para>
	/// By default the relevant information is output as is. However,
	/// with the aid of format modifiers it is possible to change the
	/// minimum field width, the maximum field width and justification.
	/// </para>
	/// <para>
	/// The optional format modifier is placed between the percent sign
	/// and the conversion pattern name.
	/// </para>
	/// <para>
	/// The first optional format modifier is the <i>left justification
	/// flag</i> which is just the minus (-) character. Then comes the
	/// optional <i>minimum field width</i> modifier. This is a decimal
	/// constant that represents the minimum number of characters to
	/// output. If the data item requires fewer characters, it is padded on
	/// either the left or the right until the minimum width is
	/// reached. The default is to pad on the left (right justify) but you
	/// can specify right padding with the left justification flag. The
	/// padding character is space. If the data item is larger than the
	/// minimum field width, the field is expanded to accommodate the
	/// data. The value is never truncated.
	/// </para>
	/// <para>
	/// This behavior can be changed using the <i>maximum field
	/// width</i> modifier which is designated by a period followed by a
	/// decimal constant. If the data item is longer than the maximum
	/// field, then the extra characters are removed from the
	/// <i>beginning</i> of the data item and not from the end. For
	/// example, it the maximum field width is eight and the data item is
	/// ten characters long, then the first two characters of the data item
	/// are dropped. This behavior deviates from the printf function in C
	/// where truncation is done from the end.
	/// </para>
	/// <para>
	/// Below are various format modifier examples for the logger
	/// conversion specifier.
	/// </para>
	/// <div class="tablediv">
	///		<table class="dtTABLE" cellspacing="0">
	///			<tr>
	///				<th>Format modifier</th>
	///				<th>left justify</th>
	///				<th>minimum width</th>
	///				<th>maximum width</th>
	///				<th>comment</th>
	///			</tr>
	///			<tr>
	///				<td align="center">%20logger</td>
	///				<td align="center">false</td>
	///				<td align="center">20</td>
	///				<td align="center">none</td>
	///				<td>
	///					<para>
	///					Left pad with spaces if the logger name is less than 20
	///					characters long.
	///					</para>
	///				</td>
	///			</tr>
	///			<tr>
	///				<td align="center">%-20logger</td>
	///				<td align="center">true</td>
	///				<td align="center">20</td>
	///				<td align="center">none</td>
	///				<td>
	///					<para>
	///					Right pad with spaces if the logger 
	///					name is less than 20 characters long.
	///					</para>
	///				</td>
	///			</tr>
	///			<tr>
	///				<td align="center">%.30logger</td>
	///				<td align="center">NA</td>
	///				<td align="center">none</td>
	///				<td align="center">30</td>
	///				<td>
	///					<para>
	///					Truncate from the beginning if the logger 
	///					name is longer than 30 characters.
	///					</para>
	///				</td>
	///			</tr>
	///			<tr>
	///				<td align="center"><nobr>%20.30logger</nobr></td>
	///				<td align="center">false</td>
	///				<td align="center">20</td>
	///				<td align="center">30</td>
	///				<td>
	///					<para>
	///					Left pad with spaces if the logger name is shorter than 20
	///					characters. However, if logger name is longer than 30 characters,
	///					then truncate from the beginning.
	///					</para>
	///				</td>
	///			</tr>
	///			<tr>
	///				<td align="center">%-20.30logger</td>
	///				<td align="center">true</td>
	///				<td align="center">20</td>
	///				<td align="center">30</td>
	///				<td>
	///					<para>
	///					Right pad with spaces if the logger name is shorter than 20
	///					characters. However, if logger name is longer than 30 characters,
	///					then truncate from the beginning.
	///					</para>
	///				</td>
	///			</tr>
	///		</table>
	///	</div>
	///	<para>
	///	<b>Note about caller location information.</b><br />
	///	The following patterns <c>%type %file %line %method %location %class %C %F %L %l %M</c> 
	///	all generate caller location information.
	/// Location information uses the <c>System.Diagnostics.StackTrace</c> class to generate
	/// a call stack. The caller's information is then extracted from this stack.
	/// </para>
	/// <note type="caution">
	/// <para>
	/// The <c>System.Diagnostics.StackTrace</c> class is not supported on the 
	/// .NET Compact Framework 1.0 therefore caller location information is not
	/// available on that framework.
	/// </para>
	/// </note>
	/// <note type="caution">
	/// <para>
	/// The <c>System.Diagnostics.StackTrace</c> class has this to say about Release builds:
	/// </para>
	/// <para>
	/// "StackTrace information will be most informative with Debug build configurations. 
	/// By default, Debug builds include debug symbols, while Release builds do not. The 
	/// debug symbols contain most of the file, method name, line number, and column 
	/// information used in constructing StackFrame and StackTrace objects. StackTrace 
	/// might not report as many method calls as expected, due to code transformations 
	/// that occur during optimization."
	/// </para>
	/// <para>
	/// This means that in a Release build the caller information may be incomplete or may 
	/// not exist at all! Therefore caller location information cannot be relied upon in a Release build.
	/// </para>
	/// </note>
	/// <para>
	/// Additional pattern converters may be registered with a specific <see cref="PatternLayout"/>
	/// instance using the <see cref="M:AddConverter(string, Type)"/> method.
	/// </para>
	/// </remarks>
	/// <example>
	/// This is a more detailed pattern.
	/// <code><b>%timestamp [%thread] %level %logger %ndc - %message%newline</b></code>
	/// </example>
	/// <example>
	/// A similar pattern except that the relative time is
	/// right padded if less than 6 digits, thread name is right padded if
	/// less than 15 characters and truncated if longer and the logger
	/// name is left padded if shorter than 30 characters and truncated if
	/// longer.
	/// <code><b>%-6timestamp [%15.15thread] %-5level %30.30logger %ndc - %message%newline</b></code>
	/// </example>
	/// <author>Nicko Cadell</author>
	/// <author>Gert Driesen</author>
	/// <author>Douglas de la Torre</author>
	/// <author>Daniel Cazzulino</author>
	public class PatternLayout : LayoutSkeleton
	{
		#region Constants

		/// <summary>
		/// Default pattern string for log output. 
		/// </summary>
		/// <remarks>
		/// <para>
		/// Default pattern string for log output. 
		/// Currently set to the string <b>"%message%newline"</b> 
		/// which just prints the application supplied message. 
		/// </para>
		/// </remarks>
		public const string DefaultConversionPattern ="%message%newline";

		/// <summary>
		/// A detailed conversion pattern
		/// </summary>
		/// <remarks>
		/// <para>
		/// A conversion pattern which includes Time, Thread, Logger, and Nested Context.
		/// Current value is <b>%timestamp [%thread] %level %logger %ndc - %message%newline</b>.
		/// </para>
		/// </remarks>
		public const string DetailConversionPattern = "%timestamp [%thread] %level %logger %ndc - %message%newline";

		#endregion

		#region Static Fields

		/// <summary>
		/// Internal map of converter identifiers to converter types.
		/// </summary>
		/// <remarks>
		/// <para>
		/// This static map is overridden by the m_converterRegistry instance map
		/// </para>
		/// </remarks>
		private static Hashtable s_globalRulesRegistry;

		#endregion Static Fields

		#region Member Variables
    
		/// <summary>
		/// the pattern
		/// </summary>
		private string m_pattern;
  
		/// <summary>
		/// the head of the pattern converter chain
		/// </summary>
		private PatternConverter m_head;

		/// <summary>
		/// patterns defined on this PatternLayout only
		/// </summary>
		private Hashtable m_instanceRulesRegistry = new Hashtable();

		#endregion

		#region Static Constructor

		/// <summary>
		/// Initialize the global registry
		/// </summary>
		/// <remarks>
		/// <para>
		/// Defines the builtin global rules.
		/// </para>
		/// </remarks>
		static PatternLayout()
		{
			s_globalRulesRegistry = new Hashtable(45);

			s_globalRulesRegistry.Add("literal", typeof(LiteralPatternConverter));
			s_globalRulesRegistry.Add("newline", typeof(NewLinePatternConverter));
			s_globalRulesRegistry.Add("n", typeof(NewLinePatternConverter));

// .NET Compact Framework 1.0 has no support for ASP.NET
// SSCLI 1.0 has no support for ASP.NET
#if !NETCF && !SSCLI && !CLIENT_PROFILE
			s_globalRulesRegistry.Add("aspnet-cache", typeof(AspNetCachePatternConverter));
			s_globalRulesRegistry.Add("aspnet-context", typeof(AspNetContextPatternConverter));
			s_globalRulesRegistry.Add("aspnet-request", typeof(AspNetRequestPatternConverter));
			s_globalRulesRegistry.Add("aspnet-session", typeof(AspNetSessionPatternConverter));
#endif

			s_globalRulesRegistry.Add("c", typeof(LoggerPatternConverter));
			s_globalRulesRegistry.Add("logger", typeof(LoggerPatternConverter));

			s_globalRulesRegistry.Add("C", typeof(TypeNamePatternConverter));
			s_globalRulesRegistry.Add("class", typeof(TypeNamePatternConverter));
			s_globalRulesRegistry.Add("type", typeof(TypeNamePatternConverter));

			s_globalRulesRegistry.Add("d", typeof(DatePatternConverter));
			s_globalRulesRegistry.Add("date", typeof(DatePatternConverter));

			s_globalRulesRegistry.Add("exception", typeof(ExceptionPatternConverter));

			s_globalRulesRegistry.Add("F", typeof(FileLocationPatternConverter));
			s_globalRulesRegistry.Add("file", typeof(FileLocationPatternConverter));

			s_globalRulesRegistry.Add("l", typeof(FullLocationPatternConverter));
			s_globalRulesRegistry.Add("location", typeof(FullLocationPatternConverter));

			s_globalRulesRegistry.Add("L", typeof(LineLocationPatternConverter));
			s_globalRulesRegistry.Add("line", typeof(LineLocationPatternConverter));

			s_globalRulesRegistry.Add("m", typeof(MessagePatternConverter));
			s_globalRulesRegistry.Add("message", typeof(MessagePatternConverter));

			s_globalRulesRegistry.Add("M", typeof(MethodLocationPatternConverter));
			s_globalRulesRegistry.Add("method", typeof(MethodLocationPatternConverter));

			s_globalRulesRegistry.Add("p", typeof(LevelPatternConverter));
			s_globalRulesRegistry.Add("level", typeof(LevelPatternConverter));

			s_globalRulesRegistry.Add("P", typeof(PropertyPatternConverter));
			s_globalRulesRegistry.Add("property", typeof(PropertyPatternConverter));
			s_globalRulesRegistry.Add("properties", typeof(PropertyPatternConverter));

			s_globalRulesRegistry.Add("r", typeof(RelativeTimePatternConverter));
			s_globalRulesRegistry.Add("timestamp", typeof(RelativeTimePatternConverter));
			
#if !NETCF
			s_globalRulesRegistry.Add("stacktrace", typeof(StackTracePatternConverter));
            s_globalRulesRegistry.Add("stacktracedetail", typeof(StackTraceDetailPatternConverter));
#endif

			s_globalRulesRegistry.Add("t", typeof(ThreadPatternConverter));
			s_globalRulesRegistry.Add("thread", typeof(ThreadPatternConverter));

			// For backwards compatibility the NDC patterns
			s_globalRulesRegistry.Add("x", typeof(NdcPatternConverter));
			s_globalRulesRegistry.Add("ndc", typeof(NdcPatternConverter));

			// For backwards compatibility the MDC patterns just do a property lookup
			s_globalRulesRegistry.Add("X", typeof(PropertyPatternConverter));
			s_globalRulesRegistry.Add("mdc", typeof(PropertyPatternConverter));

			s_globalRulesRegistry.Add("a", typeof(AppDomainPatternConverter));
			s_globalRulesRegistry.Add("appdomain", typeof(AppDomainPatternConverter));

			s_globalRulesRegistry.Add("u", typeof(IdentityPatternConverter));
			s_globalRulesRegistry.Add("identity", typeof(IdentityPatternConverter));

			s_globalRulesRegistry.Add("utcdate", typeof(UtcDatePatternConverter));
			s_globalRulesRegistry.Add("utcDate", typeof(UtcDatePatternConverter));
			s_globalRulesRegistry.Add("UtcDate", typeof(UtcDatePatternConverter));

			s_globalRulesRegistry.Add("w", typeof(UserNamePatternConverter));
			s_globalRulesRegistry.Add("username", typeof(UserNamePatternConverter));
		}

		#endregion Static Constructor

		#region Constructors

		/// <summary>
		/// Constructs a PatternLayout using the DefaultConversionPattern
		/// </summary>
		/// <remarks>
		/// <para>
		/// The default pattern just produces the application supplied message.
		/// </para>
		/// <para>
		/// Note to Inheritors: This constructor calls the virtual method
		/// <see cref="CreatePatternParser"/>. If you override this method be
		/// aware that it will be called before your is called constructor.
		/// </para>
		/// <para>
		/// As per the <see cref="IOptionHandler"/> contract the <see cref="ActivateOptions"/>
		/// method must be called after the properties on this object have been
		/// configured.
		/// </para>
		/// </remarks>
		public PatternLayout() : this(DefaultConversionPattern)
		{
		}

		/// <summary>
		/// Constructs a PatternLayout using the supplied conversion pattern
		/// </summary>
		/// <param name="pattern">the pattern to use</param>
		/// <remarks>
		/// <para>
		/// Note to Inheritors: This constructor calls the virtual method
		/// <see cref="CreatePatternParser"/>. If you override this method be
		/// aware that it will be called before your is called constructor.
		/// </para>
		/// <para>
		/// When using this constructor the <see cref="ActivateOptions"/> method 
		/// need not be called. This may not be the case when using a subclass.
		/// </para>
		/// </remarks>
		public PatternLayout(string pattern) 
		{
			// By default we do not process the exception
			IgnoresException = true;

			m_pattern = pattern;
			if (m_pattern == null)
			{
				m_pattern = DefaultConversionPattern;
			}

			ActivateOptions();
		}

		#endregion
  
		/// <summary>
		/// The pattern formatting string
		/// </summary>
		/// <remarks>
		/// <para>
		/// The <b>ConversionPattern</b> option. This is the string which
		/// controls formatting and consists of a mix of literal content and
		/// conversion specifiers.
		/// </para>
		/// </remarks>
		public string ConversionPattern
		{
			get { return m_pattern;	}
			set { m_pattern = value; }
		}

		/// <summary>
		/// Create the pattern parser instance
		/// </summary>
		/// <param name="pattern">the pattern to parse</param>
		/// <returns>The <see cref="PatternParser"/> that will format the event</returns>
		/// <remarks>
		/// <para>
		/// Creates the <see cref="PatternParser"/> used to parse the conversion string. Sets the
		/// global and instance rules on the <see cref="PatternParser"/>.
		/// </para>
		/// </remarks>
		virtual protected PatternParser CreatePatternParser(string pattern) 
		{
			PatternParser patternParser = new PatternParser(pattern);

			// Add all the builtin patterns
			foreach(DictionaryEntry entry in s_globalRulesRegistry)
			{
                ConverterInfo converterInfo = new ConverterInfo();
                converterInfo.Name = (string)entry.Key;
                converterInfo.Type = (Type)entry.Value;
                patternParser.PatternConverters[entry.Key] = converterInfo;
			}
			// Add the instance patterns
			foreach(DictionaryEntry entry in m_instanceRulesRegistry)
			{
				patternParser.PatternConverters[entry.Key] = entry.Value;
			}

			return patternParser;
		}
  
		#region Implementation of IOptionHandler

		/// <summary>
		/// Initialize layout options
		/// </summary>
		/// <remarks>
		/// <para>
		/// This is part of the <see cref="IOptionHandler"/> delayed object
		/// activation scheme. The <see cref="ActivateOptions"/> method must 
		/// be called on this object after the configuration properties have
		/// been set. Until <see cref="ActivateOptions"/> is called this
		/// object is in an undefined state and must not be used. 
		/// </para>
		/// <para>
		/// If any of the configuration properties are modified then 
		/// <see cref="ActivateOptions"/> must be called again.
		/// </para>
		/// </remarks>
		override public void ActivateOptions() 
		{
			m_head = CreatePatternParser(m_pattern).Parse();

			PatternConverter curConverter = m_head;
			while(curConverter != null)
			{
				PatternLayoutConverter layoutConverter = curConverter as PatternLayoutConverter;
				if (layoutConverter != null)
				{
					if (!layoutConverter.IgnoresException)
					{
						// Found converter that handles the exception
						this.IgnoresException = false;

						break;
					}
				}
				curConverter = curConverter.Next;
			}
		}

		#endregion

		#region Override implementation of LayoutSkeleton

		/// <summary>
		/// Produces a formatted string as specified by the conversion pattern.
		/// </summary>
		/// <param name="loggingEvent">the event being logged</param>
		/// <param name="writer">The TextWriter to write the formatted event to</param>
		/// <remarks>
		/// <para>
		/// Parse the <see cref="LoggingEvent"/> using the patter format
		/// specified in the <see cref="ConversionPattern"/> property.
		/// </para>
		/// </remarks>
		override public void Format(TextWriter writer, LoggingEvent loggingEvent) 
		{
			if (writer == null)
			{
				throw new ArgumentNullException("writer");
			}
			if (loggingEvent == null)
			{
				throw new ArgumentNullException("loggingEvent");
			}

			PatternConverter c = m_head;

			// loop through the chain of pattern converters
			while(c != null) 
			{
				c.Format(writer, loggingEvent);
				c = c.Next;
			}
		}

		#endregion

		/// <summary>
		/// Add a converter to this PatternLayout
		/// </summary>
		/// <param name="converterInfo">the converter info</param>
		/// <remarks>
		/// <para>
		/// This version of the method is used by the configurator.
		/// Programmatic users should use the alternative <see cref="M:AddConverter(string,Type)"/> method.
		/// </para>
		/// </remarks>
		public void AddConverter(ConverterInfo converterInfo)
		{
            if (converterInfo == null) throw new ArgumentNullException("converterInfo");

            if (!typeof(PatternConverter).IsAssignableFrom(converterInfo.Type))
            {
                throw new ArgumentException("The converter type specified [" + converterInfo.Type + "] must be a subclass of log4net.Util.PatternConverter", "converterInfo");
            }
            m_instanceRulesRegistry[converterInfo.Name] = converterInfo;
		}

		/// <summary>
		/// Add a converter to this PatternLayout
		/// </summary>
		/// <param name="name">the name of the conversion pattern for this converter</param>
		/// <param name="type">the type of the converter</param>
		/// <remarks>
		/// <para>
		/// Add a named pattern converter to this instance. This
		/// converter will be used in the formatting of the event.
		/// This method must be called before <see cref="ActivateOptions"/>.
		/// </para>
		/// <para>
		/// The <paramref name="type"/> specified must extend the 
		/// <see cref="PatternConverter"/> type.
		/// </para>
		/// </remarks>
		public void AddConverter(string name, Type type)
		{
            if (name == null) throw new ArgumentNullException("name");
            if (type == null) throw new ArgumentNullException("type");

            ConverterInfo converterInfo = new ConverterInfo();
            converterInfo.Name = name;
            converterInfo.Type = type;

            AddConverter(converterInfo);
		}
	}
}
