# Copyright 2020 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this library.  If not, see <http://www.gnu.org/licenses/>.

# A wrapper class around logging to make it easier to use

# for a syslog logger:
# from vyos.logger import syslog
# syslog.critical('message')

# for a stderr logger:
# from vyos.logger import stderr
# stderr.critical('message')

# for a custom logger (syslog and file):
# from vyos.logger import getLogger
# combined = getLogger(__name__, syslog=True, stream=sys.stdout, filename='/tmp/test')
# combined.critical('message')

import sys
import logging
import logging.handlers as handlers

TIMED = '%(asctime)s: %(message)s'
SHORT = '%(filename)s: %(message)s'
CLEAR = '%(levelname) %(asctime)s %(filename)s: %(message)s'

_levels = {
    'CRITICAL': logging.CRITICAL,
   	'ERROR': logging.CRITICAL,
   	'WARNING': logging.WARNING,
   	'INFO': logging.INFO,
   	'DEBUG': logging.DEBUG,
   	'NOTSET': logging.NOTSET,
}

# prevent recreation of already created logger
_created = {}

def getLogger(name=None, **kwargs):
	if name in _created:
		if len(kwargs) == 0:
			return _created[name]
		raise ValueError('a logger with the name "{name} already exists')

	logger = logging.getLogger(name)
	logger.setLevel(_levels[kwargs.get('level', 'DEBUG')])

	if 'address' in kwargs or kwargs.get('syslog', False):
		logger.addHandler(_syslog(**kwargs))
	if 'stream' in kwargs:
		logger.addHandler(_stream(**kwargs))
	if 'filename' in kwargs:
		logger.addHandler(_file(**kwargs))

	_created[name] = logger
	return logger


def _syslog(**kwargs):
	formating = kwargs.get('format', SHORT)
	handler = handlers.SysLogHandler(
		address=kwargs.get('address', '/dev/log'),
		facility=kwargs.get('facility', 'syslog'),
	)
	handler.setFormatter(logging.Formatter(formating))
	return handler


def _stream(**kwargs):
	formating = kwargs.get('format', CLEAR)
	handler = logging.StreamHandler(
		stream=kwargs.get('stream', sys.stderr),
	)
	handler.setFormatter(logging.Formatter(formating))
	return handler


def _file(**kwargs):
	formating = kwargs.get('format', CLEAR)
	handler = handlers.RotatingFileHandler(
		filename=kwargs.get('filename', 1048576),
		maxBytes=kwargs.get('maxBytes', 1048576),
		backupCount=kwargs.get('backupCount', 3),
	)
	handler.setFormatter(logging.Formatter(formating))
	return handler


# exported pre-built logger, please keep in mind that the names
# must be unique otherwise the logger are shared

# a logger for stderr
stderr = getLogger(
	'VyOS Syslog',
	format=SHORT,
	stream=sys.stderr,
	address='/dev/log'
)

# a logger to syslog
syslog = getLogger(
	'VyOS StdErr',
	format='%(message)s',
	address='/dev/log'
)


# testing
if __name__ == '__main__':
	# from vyos.logger import getLogger
	formating = '%(asctime)s (%(filename)s) %(levelname)s: %(message)s'

	# syslog logger
	# syslog=True if no 'address' field is provided
	syslog = getLogger(__name__ + '.1', syslog=True, format=formating)
	syslog.info('syslog test')

	# steam logger
	stream = getLogger(__name__ + '.2', stream=sys.stdout, level='ERROR')
	stream.info('steam test')

	# file logger
	filelog = getLogger(__name__ + '.3', filename='/tmp/test')
	filelog.info('file test')

	# create a combined logger
	getLogger('VyOS', syslog=True, stream=sys.stdout, filename='/tmp/test')

	# recover the created logger from name
	combined = getLogger('VyOS')
	combined.info('combined test')