/*
 * 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/logstring.h>
#include <log4cxx/rollingfileappender.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/helpers/optionconverter.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/rolling/rollingfileappenderskeleton.h>
#include <log4cxx/rolling/sizebasedtriggeringpolicy.h>
#include <log4cxx/rolling/fixedwindowrollingpolicy.h>


using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::spi;

namespace log4cxx
{
class ClassRollingFileAppender : public Class
{
	public:
		ClassRollingFileAppender() : helpers::Class() {}
		virtual LogString getName() const
		{
			return LOG4CXX_STR("org.apache.log4j.RollingFileAppender");
		}
		virtual ObjectPtr newInstance() const
		{
			return new RollingFileAppender();
		}
};
}

const log4cxx::helpers::Class& RollingFileAppender::getClass() const
{
	return getStaticClass();
}
const log4cxx::helpers::Class& RollingFileAppender::getStaticClass()
{
	static ClassRollingFileAppender theClass;
	return theClass;
}
const log4cxx::helpers::ClassRegistration& RollingFileAppender::registerClass()
{
	static log4cxx::helpers::ClassRegistration classReg(RollingFileAppender::getStaticClass);
	return classReg;
}
namespace log4cxx
{
namespace classes
{
const log4cxx::helpers::ClassRegistration& ObsoleteRollingFileAppenderRegistration =
	RollingFileAppender::registerClass();
}
}



RollingFileAppender::RollingFileAppender()
	: maxFileSize(10 * 1024 * 1024), maxBackupIndex(1)
{
}

RollingFileAppender::RollingFileAppender(
	const LayoutPtr& newLayout,
	const LogString& filename,
	bool append)
	: maxFileSize(10 * 1024 * 1024), maxBackupIndex(1)
{
	setLayout(newLayout);
	setFile(filename);
	setAppend(append);
	Pool p;
	activateOptions(p);
}

RollingFileAppender::RollingFileAppender(const LayoutPtr& newLayout,
	const LogString& filename)
	: maxFileSize(10 * 1024 * 1024), maxBackupIndex(1)
{
	setLayout(newLayout);
	setFile(filename);
	Pool p;
	activateOptions(p);
}

RollingFileAppender::~RollingFileAppender()
{
}


void RollingFileAppender::setOption(const LogString& option,
	const LogString& value)
{
	if (StringHelper::equalsIgnoreCase(option,
			LOG4CXX_STR("MAXFILESIZE"), LOG4CXX_STR("maxfilesize"))
		|| StringHelper::equalsIgnoreCase(option,
			LOG4CXX_STR("MAXIMUMFILESIZE"), LOG4CXX_STR("maximumfilesize")))
	{
		setMaxFileSize(value);
	}
	else if (StringHelper::equalsIgnoreCase(option,
			LOG4CXX_STR("MAXBACKUPINDEX"), LOG4CXX_STR("maxbackupindex"))
		|| StringHelper::equalsIgnoreCase(option,
			LOG4CXX_STR("MAXIMUMBACKUPINDEX"), LOG4CXX_STR("maximumbackupindex")))
	{
		maxBackupIndex = StringHelper::toInt(value);
	}
	else
	{
		using namespace log4cxx::rolling;
		RollingFileAppenderSkeleton::setOption(option, value);
	}
}


int RollingFileAppender::getMaxBackupIndex() const
{
	return maxBackupIndex;
}

long RollingFileAppender::getMaximumFileSize() const
{
	return maxFileSize;
}

void RollingFileAppender::setMaxBackupIndex(int maxBackups)
{
	maxBackupIndex = maxBackups;
}

void RollingFileAppender::setMaximumFileSize(int maxFileSize1)
{
	maxFileSize = maxFileSize1;
}

void RollingFileAppender::setMaxFileSize(const LogString& value)
{
	maxFileSize = OptionConverter::toFileSize(value, maxFileSize + 1);
}

void RollingFileAppender::activateOptions(Pool& p)
{
	log4cxx::rolling::SizeBasedTriggeringPolicyPtr trigger(
		new log4cxx::rolling::SizeBasedTriggeringPolicy());
	trigger->setMaxFileSize(maxFileSize);
	trigger->activateOptions(p);
	setTriggeringPolicy(trigger);

	log4cxx::rolling::FixedWindowRollingPolicyPtr rolling(
		new log4cxx::rolling::FixedWindowRollingPolicy());
	rolling->setMinIndex(1);
	rolling->setMaxIndex(maxBackupIndex);
	rolling->setFileNamePattern(getFile() + LOG4CXX_STR(".%i"));
	rolling->activateOptions(p);
	setRollingPolicy(rolling);

	using namespace log4cxx::rolling;
	RollingFileAppenderSkeleton::activateOptions(p);
}


