/*
* DateRollingFileAppender.hh
*
* See the COPYING file for the terms of usage and distribution.
*/
#include "PortabilityImpl.hh"
#ifdef LOG4CPP_HAVE_IO_H
#    include <io.h>
#endif
#ifdef LOG4CPP_HAVE_UNISTD_H
#    include <unistd.h>
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <log4cpp/DateRollingFileAppender.hh>
#include <log4cpp/Category.hh>
#include <log4cpp/FactoryParams.hh>
#include <memory>
#include <stdio.h>
#include <iomanip>

#ifdef LOG4CPP_HAVE_SSTREAM
#include <sstream>
#endif

#include "Localtime.hh"

namespace log4cpp {

	short _get_current_value(DateRollingFileAppender::TypePeriod PerType)
	{
		time_t _time;
		time(&_time);
		tm _tm ;
		localtime(&_time,&_tm);
		switch (PerType)
		{
		case DateRollingFileAppender::TP_MONTHLY:	return _tm.tm_mon;
		case DateRollingFileAppender::TP_HOURLY:	return _tm.tm_hour;
		case DateRollingFileAppender::TP_WEEKLY:	return _tm.tm_yday/7;
		case DateRollingFileAppender::TP_DAILY:
		default:									return _tm.tm_yday;
		}
	}

	std::string _makeFileName(const std::string & base_name, DateRollingFileAppender::TypePeriod typePeriod )
	{
		time_t _time;
		time(&_time);
		tm _tm ;
		localtime(&_time,&_tm);

		std::string::size_type sStartFileName = base_name.find_last_of("\\/");
		if(sStartFileName != std::string::npos )
		{
			if (sStartFileName < base_name.length()) ++sStartFileName; 
		}
		else 
			sStartFileName = 0;
		std::ostringstream oSt;

		oSt.fill('0');
		oSt << base_name.substr(0,sStartFileName);

		switch(typePeriod)
		{
		case DateRollingFileAppender::TP_MONTHLY:
			oSt << 1900 + _tm.tm_year << "-" << std::setw(2) << _tm.tm_mon + 1;
			break;
		case DateRollingFileAppender::TP_WEEKLY:
			oSt << 1900 + _tm.tm_year << "-" << std::setw(2) << _tm.tm_mon + 1 << "-W" << std::setw(2) << _tm.tm_yday / 7;
			break;
		case DateRollingFileAppender::TP_HOURLY:
			oSt << 1900 + _tm.tm_year << "-" << std::setw(2) << _tm.tm_mon + 1 << "-" << std::setw(2) << _tm.tm_mday << "-" << std::setw(2) << _tm.tm_hour;
			break;
		case DateRollingFileAppender::TP_DAILY:
		default:
			oSt << 1900 + _tm.tm_year << "-" << std::setw(2) << _tm.tm_mon + 1 << "-" << std::setw(2) << _tm.tm_mday;
		}
		if(sStartFileName != std::string::npos)
			oSt << "-" <<base_name.substr(sStartFileName,std::string::npos);
		return oSt.str();
	}

	DateRollingFileAppender::DateRollingFileAppender(const std::string& name,
		const std::string& fileName, 
		TypePeriod per,
		bool append,
		mode_t mode) :

	FileAppender(name, fileName, append, mode),
		_perType(per),_lastValue(-1)
	{
		rollOver();
		::remove(fileName.c_str());
	}


	void DateRollingFileAppender::rollOver() {
		::close(_fd);
		_fd = ::open( _makeFileName(_fileName,_perType).c_str() , _flags, _mode);
	}

	void DateRollingFileAppender::_append(const LoggingEvent& event) {
		short _curValue = _get_current_value(_perType);
		if(_curValue != _lastValue) 
		{
			rollOver();
			_lastValue = _curValue;
		}
		FileAppender::_append(event);
	}

	DateRollingFileAppender::TypePeriod DateRollingFileAppender::getTypePerFromString(const std::string & Parameter)
	{
		if(Parameter == "Daily") // most popular choise
		{
			return TP_DAILY;
		}
		else if (Parameter == "Hourly")
		{
			return TP_HOURLY;
		}
		else if (Parameter == "Weekly")
		{
			return TP_WEEKLY;
		}
		else if (Parameter == "Monthly")
		{
			return TP_MONTHLY;
		}
		else return TP_DAILY; 
	 
	}	


	std::auto_ptr<Appender> create_date_roll_file_appender(const FactoryParams& params)
	{
		std::string name, filename, per;
		bool append = true;
		mode_t mode = 664;
		int max_file_size = 0, max_backup_index = 0;
		params.get_for("date rool file appender").required("name", name)("filename", filename)("period_type",per)
			.optional("append", append)("mode", mode);

		return std::auto_ptr<Appender>(new DateRollingFileAppender(name, filename, DateRollingFileAppender::getTypePerFromString(per), append, mode));
	}
}
