/*
 * 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 "logunit.h"
#include "testchar.h"
#include "util/compare.h"
#include "util/transformer.h"
#include "util/absolutedateandtimefilter.h"
#include "util/iso8601filter.h"
#include "util/absolutetimefilter.h"
#include "util/relativetimefilter.h"
#include "util/controlfilter.h"
#include "util/threadfilter.h"
#include "util/linenumberfilter.h"
#include "util/filenamefilter.h"
#include "vectorappender.h"
#include <log4cxx/fmtlayout.h>
#include <log4cxx/propertyconfigurator.h>
#include <log4cxx/helpers/date.h>
#include <log4cxx/spi/loggingevent.h>
#include <iostream>
#include <iomanip>

#define REGEX_STR(x) x
#define PAT0 REGEX_STR("\\[[0-9A-FXx]*]\\ (DEBUG|INFO|WARN|ERROR|FATAL) .* - Message [0-9]\\{1,2\\}")
#define PAT1 ISO8601_PAT REGEX_STR(" ") PAT0
#define PAT2 ABSOLUTE_DATE_AND_TIME_PAT REGEX_STR(" ") PAT0
#define PAT3 ABSOLUTE_TIME_PAT REGEX_STR(" ") PAT0
#define PAT4 RELATIVE_TIME_PAT REGEX_STR(" ") PAT0
#define PAT5 REGEX_STR("\\[[0-9A-FXx]*]\\ (DEBUG|INFO|WARN|ERROR|FATAL) .* : Message [0-9]\\{1,2\\}")
#define PAT6 REGEX_STR("\\[[0-9A-FXx]*]\\ (DEBUG|INFO |WARN |ERROR|FATAL) .*patternlayouttest.cpp\\([0-9]\\{1,4\\}\\): Message [0-9]\\{1,3\\}")
#define PAT11a REGEX_STR("^(DEBUG|INFO |WARN |ERROR|FATAL) \\[[0-9A-FXx]*]\\ log4j.PatternLayoutTest: Message [0-9]\\{1,2\\}")
#define PAT11b REGEX_STR("^(DEBUG|INFO |WARN |ERROR|FATAL) \\[[0-9A-FXx]*]\\ root: Message [0-9]\\{1,2\\}")
#define PAT12 REGEX_STR("^\\[[0-9A-FXx]*]\\ (DEBUG|INFO |WARN |ERROR|FATAL) ")\
	REGEX_STR(".*patternlayouttest.cpp([0-9]\\{1,4\\}): ")\
	REGEX_STR("Message [0-9]\\{1,2\\}")
#define PAT_MDC_1 REGEX_STR("")

using namespace log4cxx;
using namespace log4cxx::helpers;

LOGUNIT_CLASS(FMTTestCase)
{
	LOGUNIT_TEST_SUITE(FMTTestCase);
	LOGUNIT_TEST(test1);
	LOGUNIT_TEST(test1_expanded);
	LOGUNIT_TEST(test10);
//	LOGUNIT_TEST(test_date);
	LOGUNIT_TEST_SUITE_END();

	LoggerPtr root;
	LoggerPtr logger;

public:
	void setUp()
	{
		root = Logger::getRootLogger();
		MDC::clear();
		logger = Logger::getLogger(LOG4CXX_TEST_STR("java.org.apache.log4j.PatternLayoutTest"));
	}

	void tearDown()
	{
		MDC::clear();
		auto rep = root->getLoggerRepository();

		if (rep)
		{
			rep->resetConfiguration();
		}
	}

	void test1()
	{
		auto status = PropertyConfigurator::configure(LOG4CXX_FILE("input/fmtLayout1.properties"));
		LOGUNIT_ASSERT_EQUAL(status, spi::ConfigurationStatus::Configured);
		common();
		LOGUNIT_ASSERT(Compare::compare(TEMP, LOG4CXX_FILE("witness/patternLayout.1")));
	}

	void test1_expanded()
	{
		auto status = PropertyConfigurator::configure(LOG4CXX_FILE("input/fmtLayout1_expanded.properties"));
		LOGUNIT_ASSERT_EQUAL(status, spi::ConfigurationStatus::Configured);
		common();
		LOGUNIT_ASSERT(Compare::compare(TEMP, LOG4CXX_FILE("witness/patternLayout.1")));
	}

	void test10()
	{
		auto status = PropertyConfigurator::configure(LOG4CXX_FILE("input/fmtLayout10.properties"));
		LOGUNIT_ASSERT_EQUAL(status, spi::ConfigurationStatus::Configured);
		common();

		ControlFilter filter1;
		filter1 << PAT6;
		ThreadFilter filter2;
		LineNumberFilter filter3;
		FilenameFilter filenameFilter(__FILE__, "patternlayouttest.cpp");


		std::vector<Filter*> filters;
		filters.push_back(&filenameFilter);
		filters.push_back(&filter1);
		filters.push_back(&filter2);
		filters.push_back(&filter3);


		try
		{
			Transformer::transform(TEMP, FILTERED, filters);
		}
		catch (UnexpectedFormatException& e)
		{
			std::cout << "UnexpectedFormatException :" << e.what() << std::endl;
			throw;
		}

		LOGUNIT_ASSERT(Compare::compare(FILTERED, LOG4CXX_FILE("witness/patternLayout.10")));
	}

	void test_date(){
		std::tm tm = {};
		std::stringstream ss("2013-04-11 08:35:34");
		ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
		auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
		uint64_t micros = std::chrono::duration_cast<std::chrono::microseconds>(tp.time_since_epoch()).count();

		log4cxx::helpers::Date::setGetCurrentTimeFunction([micros](){
			return micros;
		});

		log4cxx::spi::LoggingEventPtr logEvt = std::make_shared<log4cxx::spi::LoggingEvent>(LOG4CXX_STR("foo"),
																							 Level::getInfo(),
																							 LOG4CXX_STR("A Message"),
																							 log4cxx::spi::LocationInfo::getLocationUnavailable());
		FMTLayout layout(LOG4CXX_STR("{d:%Y-%m-%d %H:%M:%S} {message}"));
		LogString output;
		log4cxx::helpers::Pool pool;
		layout.format( output, logEvt, pool);

		log4cxx::helpers::Date::setGetCurrentTimeFunction(nullptr);

		LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("2013-04-11 09:35:34 A Message"), output);
	}

	std::string createMessage(Pool & pool, int i)
	{
		std::string msg("Message ");
		msg.append(pool.itoa(i));
		return msg;
	}

	void common()
	{
		int i = -1;

		Pool pool;


		LOG4CXX_DEBUG(logger, createMessage(pool, ++i));
		LOG4CXX_DEBUG(root, createMessage(pool, i));

		LOG4CXX_INFO(logger, createMessage(pool, ++i));
		LOG4CXX_INFO(root, createMessage(pool, i));

		LOG4CXX_WARN(logger, createMessage(pool, ++i));
		LOG4CXX_WARN(root, createMessage(pool, i));

		LOG4CXX_ERROR(logger, createMessage(pool, ++i));
		LOG4CXX_ERROR(root, createMessage(pool, i));

		LOG4CXX_FATAL(logger, createMessage(pool, ++i));
		LOG4CXX_FATAL(root, createMessage(pool, i));
	}

	private:
		static const LogString FILTERED;
		static const LogString TEMP;

};

const LogString FMTTestCase::TEMP(LOG4CXX_STR("output/fmtlayout"));
const LogString FMTTestCase::FILTERED(LOG4CXX_STR("output/fmtlayoutfiltered"));


LOGUNIT_TEST_SUITE_REGISTRATION(FMTTestCase);
