/*
 * 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/pattern/filedatepatternconverter.h>
#include <log4cxx/pattern/integerpatternconverter.h>
#include <log4cxx/pattern/patternparser.h>
#include <log4cxx/helpers/pool.h>
#include <log4cxx/helpers/date.h>
#include <log4cxx/helpers/integer.h>
#include "../util/compare.h"
#include "../logunit.h"
#include "../insertwide.h"
#include <apr_time.h>

using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::pattern;


/**
 * Tests for FileNamePattern.
 *
 *
 *
 *
 */
LOGUNIT_CLASS(FileNamePatternTestCase)
{
	LOGUNIT_TEST_SUITE(FileNamePatternTestCase);
	LOGUNIT_TEST(testFormatInteger1);
	LOGUNIT_TEST(testFormatInteger2);
	LOGUNIT_TEST(testFormatInteger3);
	LOGUNIT_TEST(testFormatInteger4);
	LOGUNIT_TEST(testFormatInteger5);
	LOGUNIT_TEST(testFormatInteger6);
	LOGUNIT_TEST(testFormatInteger7);
	LOGUNIT_TEST(testFormatInteger8);
	LOGUNIT_TEST(testFormatInteger9);
	LOGUNIT_TEST(testFormatInteger10);
	LOGUNIT_TEST(testFormatInteger11);
	LOGUNIT_TEST(testFormatDate1);
	//
	//   TODO: Problem with timezone offset
	//  LOGUNIT_TEST(testFormatDate2);
	//  LOGUNIT_TEST(testFormatDate3);
	LOGUNIT_TEST(testFormatDate4);
	LOGUNIT_TEST(testFormatDate5);
	LOGUNIT_TEST_SUITE_END();

public:
	LogString format(const LogString & pattern,
		const ObjectPtr & obj)
	{
		PatternMap rules;
		rules.insert(PatternMap::value_type(LOG4CXX_STR("d"), (PatternConstructor) FileDatePatternConverter::newInstance));
		rules.insert(PatternMap::value_type(LOG4CXX_STR("i"), (PatternConstructor) IntegerPatternConverter::newInstance));
		auto converters = PatternParser::parse(pattern, rules);
		LogString result;

		for (auto item :  converters)
		{
			auto fieldStart = result.length();
			item->format(obj, result);
			item->getFormattingInfo().adjustField(fieldStart, result);
		}

		return result;
	}



	void assertDatePattern(const LogString & pattern,
		int year,
		int month,
		int day, int hour,
		int min,
		const LogString & expected)
	{
		apr_time_exp_t tm;
		memset(&tm, 0, sizeof(tm));
		apr_time_exp_lt(&tm, 0); // set tm_gmtoff
		tm.tm_min = min;
		tm.tm_hour = hour;
		tm.tm_mday = day;
		tm.tm_mon = month;
		tm.tm_year = year - 1900;
		apr_time_t n;
		apr_time_exp_gmt_get(&n, &tm);
		ObjectPtr obj(new Date(n));
		LOGUNIT_ASSERT_EQUAL(expected, format(pattern, obj));
	}

	void assertIntegerPattern(const LogString & pattern, int value,
		const LogString & expected)
	{
		ObjectPtr obj(new Integer(value));
		LOGUNIT_ASSERT_EQUAL(expected, format(pattern, obj));
	}

	void testFormatInteger1()
	{
		assertIntegerPattern(LOG4CXX_STR("t"),  3, LOG4CXX_STR("t"));
	}

	void testFormatInteger2()
	{
		assertIntegerPattern(LOG4CXX_STR("foo"),  3, LOG4CXX_STR("foo"));
	}

	void testFormatInteger3()
	{
		assertIntegerPattern(LOG4CXX_STR("foo%"),  3, LOG4CXX_STR("foo%"));
	}

	void testFormatInteger4()
	{
		assertIntegerPattern(LOG4CXX_STR("%ifoo"),  3, LOG4CXX_STR("3foo"));
	}

	void testFormatInteger5()
	{
		assertIntegerPattern(LOG4CXX_STR("foo%ixixo"),  3, LOG4CXX_STR("foo3xixo"));
	}

	void testFormatInteger6()
	{
		assertIntegerPattern(LOG4CXX_STR("foo%i.log"),  3, LOG4CXX_STR("foo3.log"));
	}

	void testFormatInteger7()
	{
		assertIntegerPattern(LOG4CXX_STR("foo.%i.log"),  3, LOG4CXX_STR("foo.3.log"));
	}

	void testFormatInteger8()
	{
		assertIntegerPattern(LOG4CXX_STR("%ifoo%"),  3, LOG4CXX_STR("3foo%"));
	}

	void testFormatInteger9()
	{
		assertIntegerPattern(LOG4CXX_STR("%ifoo%%"),  3, LOG4CXX_STR("3foo%"));
	}

	void testFormatInteger10()
	{
		assertIntegerPattern(LOG4CXX_STR("%%foo"),  3, LOG4CXX_STR("%foo"));
	}

	void testFormatInteger11()
	{
		assertIntegerPattern(LOG4CXX_STR("foo%ibar%i"),  3, LOG4CXX_STR("foo3bar3"));
	}

	void testFormatDate1()
	{
		assertDatePattern(LOG4CXX_STR("foo%d{yyyy.MM.dd}"),  2003, 4, 20, 17, 55,
			LOG4CXX_STR("foo2003.05.20"));
	}

	void testFormatDate2()
	{
		assertDatePattern(LOG4CXX_STR("foo%d{yyyy.MM.dd HH:mm}"),  2003, 4, 20, 17, 55,
			LOG4CXX_STR("foo2003.05.20 17:55"));
	}

	void testFormatDate3()
	{
		assertDatePattern(LOG4CXX_STR("%d{yyyy.MM.dd HH:mm} foo"),  2003, 4, 20, 17, 55,
			LOG4CXX_STR("2003.05.20 17:55 foo"));
	}

	void testFormatDate4()
	{
		assertDatePattern(LOG4CXX_STR("foo%dyyyy.MM.dd}"),  2003, 4, 20, 17, 55,
			LOG4CXX_STR("foo2003-05-20yyyy.MM.dd}"));
	}

	void testFormatDate5()
	{
		assertDatePattern(LOG4CXX_STR("foo%d{yyyy.MM.dd"),  2003, 4, 20, 17, 55,
			LOG4CXX_STR("foo2003-05-20{yyyy.MM.dd"));
	}

};

//
//   See bug LOGCXX-204
//
#if !defined(_MSC_VER) || _MSC_VER > 1200
	LOGUNIT_TEST_SUITE_REGISTRATION(FileNamePatternTestCase);
#endif
