/*
 * 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_HELPER_PATTERN_CONVERTER_H
#define _LOG4CXX_HELPER_PATTERN_CONVERTER_H

#include <map>
#include <vector>
#include <functional>
#include <log4cxx/helpers/class.h>
#include <log4cxx/pattern/patternconverter.h>
#include <log4cxx/pattern/formattinginfo.h>

namespace LOG4CXX_NS
{
namespace pattern
{

typedef std::function<PatternConverterPtr(const std::vector<LogString>& options)> PatternConstructor;
typedef std::map<LogString, PatternConstructor> PatternMap;


// Contributors:   Nelson Minar <(nelson@monkey.org>
//                 Igor E. Poteryaev <jah@mail.ru>
//                 Reinhard Deschler <reinhard.deschler@web.de>

/**
 * Most of the work of the {@link log4cxx::PatternLayout PatternLayout} class
 * is delegated to the PatternParser class.
 * <p>It is this class that parses conversion patterns and creates
 * a chained list of {@link PatternConverter PatternConverters}.
 *
 *
*/
class LOG4CXX_EXPORT PatternParser
{
		/**
		 * Escape character for format specifier.
		 */
		static const logchar ESCAPE_CHAR;

		enum
		{
			LITERAL_STATE = 0,
			CONVERTER_STATE = 1,
			DOT_STATE = 3,
			MIN_STATE = 4,
			MAX_STATE = 5
		};

		/**
		 * Private constructor.
		 */
		PatternParser();

	private:
		/** Extract the converter identifier found at position i.
		 *
		 * After this function returns, the variable i will point to the
		 * first char after the end of the converter identifier.
		 *
		 * If i points to a char which is not a character acceptable at the
		 * start of a unicode identifier, the value null is returned.
		 *
		 * @param lastChar last processed character.
		 * @param pattern format string.
		 * @param i current index into pattern format.
		 * @param convBuf buffer to receive conversion specifier.
		 * @param currentLiteral literal to be output in case format specifier in unrecognized.
		 * @return position in pattern after converter.
		 */
		static size_t extractConverter(
			logchar lastChar, const LogString& pattern,
			LogString::size_type i, LogString& convBuf,
			LogString& currentLiteral);

		/**
		 * Extract options.
		 * @param pattern conversion pattern.
		 * @param i start of options.
		 * @param options array to receive extracted options
		 * @return position in pattern after options.
		 */
		static size_t extractOptions(const LogString& pattern, LogString::size_type i,
			std::vector<LogString>& options);

	public:
		/**
		 * Parse a format specifier.
		 * @param pattern pattern to parse.
		 * @param patternConverters list to receive pattern converters.
		 * @param formattingInfos list to receive field specifiers corresponding to pattern converters.
		 * @param rules map of stock pattern converters keyed by format specifier.
		 */
		static void parse(
			const LogString& pattern,
			std::vector<PatternConverterPtr>& patternConverters,
			std::vector<FormattingInfoPtr>& formattingInfos,
			const PatternMap& rules);

	private:
		/**
		 * Creates a new PatternConverter.
		 *
		 *
		 * @param converterId converterId.
		 * @param currentLiteral literal to be used if converter is unrecognized or following converter
		 *    if converterId contains extra characters.
		 * @param rules map of stock pattern converters keyed by format specifier.
		 * @param options converter options.
		 * @return  converter or null.
		 */
		static PatternConverterPtr createConverter(
			const LogString& converterId,
			LogString& currentLiteral,
			const PatternMap& rules,
			std::vector<LogString>& options);

		/**
		 * Processes a format specifier sequence.
		 *
		 * @param c initial character of format specifier.
		 * @param pattern conversion pattern
		 * @param i current position in conversion pattern.
		 * @param currentLiteral current literal.
		 * @param formattingInfo current field specifier.
		 * @param rules map of stock pattern converters keyed by format specifier.
		 * @param patternConverters list to receive parsed pattern converter.
		 * @param formattingInfos list to receive corresponding field specifier.
		 * @return position after format specifier sequence.
		 */
		static size_t finalizeConverter(
			logchar c, const LogString& pattern, size_t i,
			LogString& currentLiteral, const FormattingInfoPtr& formattingInfo,
			const PatternMap&  rules,
			std::vector<PatternConverterPtr>& patternConverters,
			std::vector<FormattingInfoPtr>&  formattingInfos);

		static bool isUnicodeIdentifierStart(logchar c);
		static bool isUnicodeIdentifierPart(logchar c);


};

}
}


#endif
