// Copyright (c) 1999-2001  David Muse
// See the file COPYING for more information

#include <rudiments/logger.h>
#include <rudiments/datetime.h>
#include <rudiments/permissions.h>
#include <rudiments/charstring.h>
#include <rudiments/error.h>
#include <rudiments/process.h>

#include <stdio.h>
#ifdef RUDIMENTS_HAVE_UNISTD_H
	#include <unistd.h>
#endif

#ifdef RUDIMENTS_NAMESPACE
namespace rudiments {
#endif

logdestination::~logdestination() {}

class filedestinationprivate {
	friend class filedestination;
	private:
		file	_logfile;
};

filedestination::filedestination() : logdestination() {
	pvt=new filedestinationprivate;
}

filedestination::filedestination(const filedestination &f) :
						logdestination(f) {
	pvt=new filedestinationprivate;
	pvt->_logfile=f.pvt->_logfile;
}

filedestination &filedestination::operator=(const filedestination &f) {
	if (this!=&f) {
		pvt->_logfile=f.pvt->_logfile;
	}
	return *this;
}

filedestination::~filedestination() {
	close();
	delete pvt;
}

bool filedestination::open(const char *filename) {
	return pvt->_logfile.open(filename,O_CREAT|O_WRONLY|O_APPEND,
				permissions::ownerReadWrite());
}

void filedestination::close() {
	pvt->_logfile.close();
}

void filedestination::write(const char *string) {
	pvt->_logfile.write(string);
}

void stdoutdestination::write(const char *string) {
	int	result;
	do {
		result=::write(1,string,charstring::length(string));
	} while (result==-1 && error::getErrorNumber()==EINTR);
}

void stderrdestination::write(const char *string) {
	int	result;
	do {
		result=::write(2,string,charstring::length(string));
	} while (result==-1 && error::getErrorNumber()==EINTR);
}

class syslogdestinationprivate {
	friend class syslogdestination;
	private:
		int	_priority;
};

syslogdestination::syslogdestination() : logdestination() {
	pvt=new syslogdestinationprivate;
}

syslogdestination::syslogdestination(const syslogdestination &s) :
						logdestination(s) {
	pvt=new syslogdestinationprivate;
}

syslogdestination &syslogdestination::operator=(const syslogdestination &s) {
	if (this!=&s) {
		pvt->_priority=s.pvt->_priority;
	}
	return *this;
}

syslogdestination::~syslogdestination() {
	close();
	delete pvt;
}

void syslogdestination::open(const char *ident, int option,
					int facility, int priority) {
	openlog(ident,option,facility);
	pvt->_priority=priority;
}

void syslogdestination::close() {
	closelog();
}

void syslogdestination::write(const char *string) {
	syslog(pvt->_priority,string);
}

class loggerprivate {
	friend class logger;
	private:
		loggerlist	_logdestlist;
};

logger::logger() {
	pvt=new loggerprivate;
}

logger::~logger() {
	removeAllLogDestinations();
	delete pvt;
}

void logger::addLogDestination(logdestination *logdest) {
	pvt->_logdestlist.append(logdest);
}

void logger::removeLogDestination(logdestination *logdest) {
	pvt->_logdestlist.removeByData(logdest);
}

void logger::removeAllLogDestinations() {
	pvt->_logdestlist.clear();
}

char *logger::logHeader(const char *name) {
	datetime	dt;
	dt.getSystemDateAndTime();
	pid_t		pid=process::getProcessId();
	const char	*dtstring=dt.getString();
	size_t		retvallen=charstring::length(dtstring)+1+
				charstring::length(name)+2+
				charstring::integerLength((uint64_t)pid)+2;
	char		*retval=new char[retvallen];
	snprintf(retval,retvallen,"%s %s [%d]",dtstring,name,pid);
	return retval;
}

void logger::write(const char *header, int32_t tabs, const char *string) {
	size_t	logentrylen=charstring::length(header)+3+tabs+
				charstring::length(string)+2+1;
	char	*logentry=new char[logentrylen];
	snprintf(logentry,logentrylen,"%s : ",header);
	for (int32_t i=0; i<tabs; i++) {
		snprintf(logentry,logentrylen,"%s%c",logentry,'	');
	}
	snprintf(logentry,logentrylen,"%s%s\n\n",logentry,string);
	write(logentry);
	delete[] logentry;
}

void logger::write(const char *header, int32_t tabs, char character) {
	size_t	logentrylen=charstring::length(header)+3+tabs+1+2+1;
	char	*logentry=new char[logentrylen];
	snprintf(logentry,logentrylen,"%s : ",header);
	for (int32_t i=0; i<tabs; i++) {
		snprintf(logentry,logentrylen,"%s%c",logentry,'	');
	}
	snprintf(logentry,logentrylen,"%s%c\n\n",logentry,character);
	write(logentry);
	delete[] logentry;
}

void logger::write(const char *header, int32_t tabs, int32_t number) {
	size_t	logentrylen=charstring::length(header)+3+tabs+20+2+1;
	char	*logentry=new char[logentrylen];
	snprintf(logentry,logentrylen,"%s : ",header);
	for (int32_t i=0; i<tabs; i++) {
		snprintf(logentry,logentrylen,"%s%c",logentry,'	');
	}
	snprintf(logentry,logentrylen,"%s%d\n\n",logentry,number);
	write(logentry);
	delete[] logentry;
}

void logger::write(const char *header, int32_t tabs, double number) {
	size_t	logentrylen=charstring::length(header)+3+tabs+21+2+1;
	char	*logentry=new char[logentrylen];
	snprintf(logentry,logentrylen,"%s : ",header);
	for (int32_t i=0; i<tabs; i++) {
		snprintf(logentry,logentrylen,"%s%c",logentry,'	');
	}
	snprintf(logentry,logentrylen,"%s%f\n\n",logentry,number);
	write(logentry);
	delete[] logentry;
}

void logger::write(const char *logentry) {
	loggerlistnode	*current=pvt->_logdestlist.getNodeByIndex(0);
	while (current) {
		current->getData()->write(logentry);
		current=(loggerlistnode *)current->getNext();
	}
}

#ifdef RUDIMENTS_NAMESPACE
}
#endif


syntax highlighted by Code2HTML, v. 0.9.1