/***************************************************************************

    supportware
    Copyright (C) 2001-2008 by c.holzheuer
    c.holzheuer@sourceworx.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/


#include <ddlogmanager.h>
#include <ddmailmanager.h>
#include <ddbaseobject.h>
#include <ddbasetime.h>
#include <ddthreadmutex.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

       
/**
	Constructor.
*/

ddlogdevice::ddlogdevice()
: _logmutex( 0 )
{
	// create dummy streams	
	for( size_t i=0; i<ddlogdevice::lg_size; ++i ) 
	{
		_streams.push_back( 0 );
		_filenames.push_back( "xx" );
	}
	_logmutex = new ddthreadmutex();	
}


/**
	Destructor.
*/

ddlogdevice::~ddlogdevice()
{
	delete _logmutex;
}


/**
	Create a logfile message.Writes an entry to the logfile.
*/

void ddlogdevice::log_message( int level, const ddstring& message )
{	
	
	if( level < 0 || level >= ddlogdevice::lg_size || message.empty() )
		return;		
	
	ddthreadautomutex tmplock( *_logmutex );
 
	ddstring tmp;	
	// datum _nicht_ ins main log -> apache ELF logformat 
	// nicht schreddern
	if( level != ddlogdevice::lg_main )	 
	 	tmp += "["+ddbasedate::now().to_string() + "] ";
	
	tmp += message;
	
	if( level == ddlogdevice::lg_error && errno != 0 )
	{		
		tmp += ": ";
		tmp += ::strerror( errno );		
	}

	// log message, if stream present
	if( _streams[level] )
		(*_streams[level]) << tmp << endl;	
	
	// log to screen also
	cerr << tmp << endl;	
	
}	


/**
	daily log rotation.
*/

void ddlogdevice::rotate_log_streams( time_t lasttime )
{
	
	struct tm tm_now;
	char buf[50];
	::localtime_r( &lasttime, &tm_now );
	::strftime( buf, 49, ".%F", &tm_now );
	
	for( size_t i=0; i<ddlogdevice::lg_size; ++i ) 
	{
		if( _streams[i] )
		{
			// close ...
			_streams[i]->close();
			// move ...
			ddstring newname = _filenames[i]+buf;
			newname += ".old";
			if( ::rename( _filenames[i].c_str(), newname.c_str() ) < 0 )
			{
				ddstring erttxt = "ddlogdevice::rotate_log_streams: rename: " + _filenames[i] + ": " + newname;
				perror( erttxt.c_str() );
			}
			// reopen
			_streams[i]->open( _filenames[i].c_str(), ios::out|ios::app );
		}	
	}
	
}


/**
 Init a log stream.
*/

void ddlogdevice::add_log_stream( int idx, const ddstring& name )
{
	
		
	// name empty: no logging for this level
	if( name.empty() )
		return;
	ofstream* logger = new ofstream( name.c_str(), ios::out|ios::app );	
	
	// kein log_fatal, weil das logging ja nicht geht ;-)
	// allerdings ist ein Fehler hier trotzdem eine
	// exception wert.
	 
	//if( !(*logger) )
	//	throw runtime_error( "add_log_stream failed:" + name );	
	
	_streams[idx] = logger;
	_filenames[idx] = name;

}


/***************************************************************************

    supportware
    Copyright (C) 2001-2008 by c.holzheuer
    c.holzheuer@sourceworx.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/


/**
	Constructor.
*/

ddlogmanager::ddlogmanager()
{
	// das main log braucht keinen pfad und hat
	// nur 2 streams: debug & error
	_mainlog.add_log_stream( ddlogdevice::lg_debug, "livelogs/supportware.debug.log" );
	_mainlog.add_log_stream( ddlogdevice::lg_error, "livelogs/supportware.error.log" );
}


/**
	Destructor.
*/

ddlogmanager::~ddlogmanager()
{
	ddlogmap::iterator pos = _domainlogs.begin();
	for( ; pos != _domainlogs.end(); ++pos )
		delete (*pos).second;
}


/**
	Schreibt eine message ins main log.
*/

void ddlogmanager::log_message( int level, const ddstring& message )
{	
	_mainlog.log_message( level, message );
}	


/**
	Schreibt eine message in das angegebene domain log.
*/

void ddlogmanager::log_message( const ddstring& domainname, int level, const ddstring& message )
{
	ddlogdevice* domainlog = _domainlogs[ domainname ];
	if( domainlog )
		domainlog->log_message( level, message );
}


/**
	daily log rotation.
*/

void ddlogmanager::rotate_log_streams( time_t lasttime )
{
	_mainlog.rotate_log_streams( lasttime );
	ddlogmap::iterator pos = _domainlogs.begin();
	for( ; pos != _domainlogs.end(); ++pos )
		(*pos).second->rotate_log_streams( lasttime );
}


/**
 Eine Log-Domain (entspricht einer site) hinzufügen. 
 Jede log domain hat folgende streams:
  - log main
  - log admin
  - log chat
*/

void ddlogmanager::add_log_domain( const ddstring& domainname, const ddstring& path )
{
	// FIX! unsicher
	ddlogdevice* newlog = new ddlogdevice();
	ddstring fullpath = path + "livelogs/" + domainname;
	//QUARK! Die werden gar nicht angesprochen! 
	//newlog->add_log_stream( ddlogdevice::lg_debug, path + domainname + ".debug.log" );
	//newlog->add_log_stream( ddlogdevice::lg_error, path + domainname + ".error.log" );
	newlog->add_log_stream( ddlogdevice::lg_main,  fullpath + ".main.log" );
	newlog->add_log_stream( ddlogdevice::lg_admin, fullpath + ".admin.log" );
	//newlog->add_log_stream( ddlogdevice::lg_chat,  fullpath + ".chat.log" );
	newlog->add_log_stream( ddlogdevice::lg_search,  fullpath + ".search.log" );

	_domainlogs[ domainname ] = newlog;
	
}



