/*
 * 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.
 */
#if defined(_MSC_VER)
	#pragma warning ( disable: 4231 4251 4275 4786 )
#endif


#include <log4cxx/logstring.h>
#include <log4cxx/rolling/fixedwindowrollingpolicy.h>
#include <log4cxx/helpers/pool.h>
#include <log4cxx/helpers/integer.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/optionconverter.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/helpers/exception.h>
#include <log4cxx/rolling/rolloverdescription.h>
#include <log4cxx/rolling/filerenameaction.h>
#include <log4cxx/rolling/gzcompressaction.h>
#include <log4cxx/rolling/zipcompressaction.h>
#include <log4cxx/pattern/integerpatternconverter.h>

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

IMPLEMENT_LOG4CXX_OBJECT(FixedWindowRollingPolicy)

FixedWindowRollingPolicy::FixedWindowRollingPolicy() :
	minIndex(1), maxIndex(7)
{
}

void FixedWindowRollingPolicy::setMaxIndex(int maxIndex1)
{
	this->maxIndex = maxIndex1;
}

void FixedWindowRollingPolicy::setMinIndex(int minIndex1)
{
	this->minIndex = minIndex1;
}



void FixedWindowRollingPolicy::setOption(const LogString& option,
	const LogString& value)
{
	if (StringHelper::equalsIgnoreCase(option,
			LOG4CXX_STR("MININDEX"),
			LOG4CXX_STR("minindex")))
	{
		minIndex = OptionConverter::toInt(value, 1);
	}
	else if (StringHelper::equalsIgnoreCase(option,
			LOG4CXX_STR("MAXINDEX"),
			LOG4CXX_STR("maxindex")))
	{
		maxIndex = OptionConverter::toInt(value, 7);
	}
	else
	{
		RollingPolicyBase::setOption(option, value);
	}
}

/**
 * {@inheritDoc}
 */
void FixedWindowRollingPolicy::activateOptions(Pool& p)
{
	RollingPolicyBase::activateOptions(p);

	if (maxIndex < minIndex)
	{
		LogLog::warn(
			LOG4CXX_STR("MaxIndex  cannot be smaller than MinIndex."));
		maxIndex = minIndex;
	}

	if ((maxIndex - minIndex) > MAX_WINDOW_SIZE)
	{
		LogLog::warn(LOG4CXX_STR("Large window sizes are not allowed."));
		maxIndex = minIndex + MAX_WINDOW_SIZE;
	}

	PatternConverterPtr itc = getIntegerPatternConverter();

	if (itc == NULL)
	{
		throw IllegalStateException();
	}
}

/**
 * {@inheritDoc}
 */
RolloverDescriptionPtr FixedWindowRollingPolicy::initialize(
	const   LogString&  currentActiveFile,
	const   bool        append,
	Pool&       pool)
{
	LogString newActiveFile(currentActiveFile);
	explicitActiveFile = false;

	if (currentActiveFile.length() > 0)
	{
		explicitActiveFile = true;
		newActiveFile = currentActiveFile;
	}

	if (!explicitActiveFile)
	{
		LogString buf;
		ObjectPtr obj(new Integer(minIndex));
		formatFileName(obj, buf, pool);
		newActiveFile = buf;
	}

	ActionPtr noAction;

	return new RolloverDescription(newActiveFile, append, noAction, noAction);
}

/**
 * {@inheritDoc}
 */
RolloverDescriptionPtr FixedWindowRollingPolicy::rollover(
	const   LogString&  currentActiveFile,
	const   bool        append,
	Pool&       pool)
{
	RolloverDescriptionPtr desc;

	if (maxIndex < 0)
	{
		return desc;
	}

	int purgeStart = minIndex;

	if (!explicitActiveFile)
	{
		purgeStart++;
	}

	if (!purge(purgeStart, maxIndex, pool))
	{
		return desc;
	}

	LogString buf;
	ObjectPtr obj(new Integer(purgeStart));
	formatFileName(obj, buf, pool);

	LogString renameTo(buf);
	LogString compressedName(renameTo);
	ActionPtr compressAction ;

	if (StringHelper::endsWith(renameTo, LOG4CXX_STR(".gz")))
	{
		renameTo.resize(renameTo.size() - 3);
		compressAction =
			new GZCompressAction(
			File().setPath(renameTo),
			File().setPath(compressedName),
			true);
	}
	else if (StringHelper::endsWith(renameTo, LOG4CXX_STR(".zip")))
	{
		renameTo.resize(renameTo.size() - 4);
		compressAction =
			new ZipCompressAction(
			File().setPath(renameTo),
			File().setPath(compressedName),
			true);
	}

	FileRenameActionPtr renameAction =
		new FileRenameAction(
		File().setPath(currentActiveFile),
		File().setPath(renameTo),
		false);

	desc = new RolloverDescription(
		currentActiveFile,  append,
		renameAction,       compressAction);

	return desc;
}

/**
 * Get index of oldest log file to be retained.
 * @return index of oldest log file.
 */
int FixedWindowRollingPolicy::getMaxIndex() const
{
	return maxIndex;
}

/**
 * Get index of most recent log file.
 * @return index of oldest log file.
 */
int FixedWindowRollingPolicy::getMinIndex() const
{
	return minIndex;
}


/**
 * Purge and rename old log files in preparation for rollover
 * @param lowIndex low index
 * @param highIndex high index.  Log file associated with high
 * index will be deleted if needed.
 * @return true if purge was successful and rollover should be attempted.
 */
bool FixedWindowRollingPolicy::purge(int lowIndex, int highIndex, Pool& p) const
{
	int suffixLength = 0;

	std::vector<FileRenameActionPtr> renames;
	LogString buf;
	ObjectPtr obj = new Integer(lowIndex);
	formatFileName(obj, buf, p);

	LogString lowFilename(buf);

	if (lowFilename.compare(lowFilename.length() - 3, 3, LOG4CXX_STR(".gz")) == 0)
	{
		suffixLength = 3;
	}
	else if (lowFilename.compare(lowFilename.length() - 4, 4, LOG4CXX_STR(".zip")) == 0)
	{
		suffixLength = 4;
	}

	for (int i = lowIndex; i <= highIndex; i++)
	{
		File toRenameCompressed;
		toRenameCompressed.setPath(lowFilename);
		File toRenameBase;
		toRenameBase.setPath(lowFilename.substr(0, lowFilename.length() - suffixLength));
		File* toRename = &toRenameCompressed;
		bool isBase = false;
		bool exists = toRenameCompressed.exists(p);

		if (suffixLength > 0)
		{
			if (exists)
			{
				if (toRenameBase.exists(p))
				{
					toRenameBase.deleteFile(p);
				}
			}
			else
			{
				toRename = &toRenameBase;
				exists = toRenameBase.exists(p);
				isBase = true;
			}
		}

		if (exists)
		{
			//
			//    if at upper index then
			//        attempt to delete last file
			//        if that fails then abandon purge
			if (i == highIndex)
			{
				if (!toRename->deleteFile(p))
				{
					return false;
				}

				break;
			}

			//
			//   if intermediate index
			//     add a rename action to the list
			buf.erase(buf.begin(), buf.end());
			obj = new Integer(i + 1);
			formatFileName(obj, buf, p);

			LogString highFilename(buf);
			LogString renameTo(highFilename);

			if (isBase)
			{
				renameTo =
					highFilename.substr(0, highFilename.length() - suffixLength);
			}

			renames.push_back(new FileRenameAction(*toRename, File().setPath(renameTo), true));
			lowFilename = highFilename;
		}
		else
		{
			break;
		}
	}

	//
	//   work renames backwards
	//
	for (std::vector<FileRenameActionPtr>::reverse_iterator iter = renames.rbegin();
		iter != renames.rend();
		iter++)
	{

		try
		{
			if (!(*iter)->execute(p))
			{
				return false;
			}
		}
		catch (std::exception&)
		{
			LogLog::warn(LOG4CXX_STR("Exception during purge in RollingFileAppender"));

			return false;
		}
	}

	return true;
}

#define RULES_PUT(spec, cls) \
	specs.insert(PatternMap::value_type(LogString(LOG4CXX_STR(spec)), (PatternConstructor) cls ::newInstance))


log4cxx::pattern::PatternMap FixedWindowRollingPolicy::getFormatSpecifiers() const
{
	PatternMap specs;
	RULES_PUT("i", IntegerPatternConverter);
	RULES_PUT("index", IntegerPatternConverter);
	return specs;
}
