/*
 *  eXist Open Source Native XML Database
 *  Copyright (C) 2001-2009 Wolfgang M. Meier
 *  wolfgang@exist-db.org
 *  http://exist.sourceforge.net
 *
 *  This program 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
 *  of the License, or (at your option) any later version.
 *
 *  This program 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 program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  $Id$
 */
package org.exist.xquery.functions.util;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.dom.QName;
import org.exist.source.StringSource;
import org.exist.storage.serializers.Serializer;
import org.exist.xquery.*;
import org.exist.xquery.value.*;
import org.xml.sax.SAXException;


/**
 * @author Wolfgang Meier (wolfgang@exist-db.org)
 * @author Andrzej Taramina (andrzej@chaeron.com)
 */
public class LogFunction extends BasicFunction {

    protected static final FunctionParameterSequenceType PRIORITY_PARAMETER
            = new FunctionParameterSequenceType("priority", Type.STRING, Cardinality.EXACTLY_ONE, "The logging priority: 'error', 'warn', 'debug', 'info', 'trace'");
    protected static final FunctionParameterSequenceType LOGGER_NAME_PARAMETER
            = new FunctionParameterSequenceType("logger-name", Type.STRING, Cardinality.EXACTLY_ONE, "The name of the logger, eg: my.app.log");
    protected static final FunctionParameterSequenceType MESSAGE_PARAMETER
            = new FunctionParameterSequenceType("message", Type.ITEM, Cardinality.ZERO_OR_MORE, "The message to log");

    protected static final Logger logger = LogManager.getLogger(LogFunction.class);

    public static final String FUNCTION_LOG = "log";
    public static final String FUNCTION_LOGAPP = "log-app";
    public static final String FUNCTION_LOG_SYSTEM_OUT = "log-system-out";
    public static final String FUNCTION_LOG_SYSTEM_ERR = "log-system-err";
    public final static FunctionSignature signatures[] = {
            new FunctionSignature(
                    new QName(FUNCTION_LOG, UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
                    "Logs the message to the current logger.",
                    new SequenceType[]{PRIORITY_PARAMETER, MESSAGE_PARAMETER},
                    new SequenceType(Type.ITEM, Cardinality.EMPTY)
            ),
            new FunctionSignature(
                    new QName(FUNCTION_LOG_SYSTEM_OUT, UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
                    "Logs the message to System.out.",
                    new SequenceType[]{MESSAGE_PARAMETER},
                    new SequenceType(Type.ITEM, Cardinality.EMPTY)
            ),
            new FunctionSignature(
                    new QName(FUNCTION_LOG_SYSTEM_ERR, UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
                    "Logs the message to System.err.",
                    new SequenceType[]{MESSAGE_PARAMETER},
                    new SequenceType(Type.ITEM, Cardinality.EMPTY)
            ),
            new FunctionSignature(
                    new QName(FUNCTION_LOGAPP, UtilModule.NAMESPACE_URI, UtilModule.PREFIX),
                    "Logs the message to the named logger",
                    new SequenceType[]{PRIORITY_PARAMETER, LOGGER_NAME_PARAMETER, MESSAGE_PARAMETER},
                    new SequenceType(Type.ITEM, Cardinality.EMPTY)
            )
    };

    public LogFunction(XQueryContext context, FunctionSignature signature) {
        super(context, signature);
    }

    /* (non-Javadoc)
     * @see org.exist.xquery.BasicFunction#eval(org.exist.xquery.value.Sequence[], org.exist.xquery.value.Sequence)
     */
    public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {

        SequenceIterator i;

        final String calledAs = getName().getLocalPart();

        // Find query parameter with actual data
        switch (calledAs) {
            case FUNCTION_LOG:
                i = args[1].unorderedIterator();
                if (args[1].isEmpty()) {
                    return (Sequence.EMPTY_SEQUENCE);
                }
                break;

            case FUNCTION_LOGAPP:
                i = args[2].unorderedIterator();
                if (args[2].isEmpty()) {
                    return (Sequence.EMPTY_SEQUENCE);
                }
                break;

            default:
                i = args[0].unorderedIterator();
                if (args[0].isEmpty()) {
                    return (Sequence.EMPTY_SEQUENCE);
                }
                break;
        }

        // Add line of the log statement
        final StringBuilder buf = new StringBuilder();
        buf.append("(");

        buf.append("Line: ");
        buf.append(this.getLine());

        // Add source information to the log statement when provided
        if (getSource() != null && getSource().getKey() != null) {
            buf.append(" ");

            // Do not write content of query from String into log.
            if (getSource() instanceof StringSource) {
                buf.append(getSource().type());
            } else {
                buf.append(getSource().getKey());
            }

        }

        buf.append(") ");

        // Iterate over all input
        while (i.hasNext()) {
            final Item next = i.nextItem();
            if (Type.subTypeOf(next.getType(), Type.NODE)) {
                final Serializer serializer = context.getBroker().getSerializer();
                serializer.reset();
                try {
                    buf.append(serializer.serialize((NodeValue) next));
                } catch (final SAXException e) {
                    throw (new XPathException(this, "An exception occurred while serializing node to log: " + e.getMessage(), e));
                }
            } else {
                buf.append(next.getStringValue());
            }
        }

        // Finally write the log
        switch (calledAs) {
            case FUNCTION_LOG:
                final String loglevel = args[0].getStringValue().toLowerCase();
                writeLog(buf, loglevel, logger);
                break;

            case FUNCTION_LOG_SYSTEM_OUT:
                System.out.println(buf);
                break;

            case FUNCTION_LOG_SYSTEM_ERR:
                System.err.println(buf);
                break;

            case FUNCTION_LOGAPP: {
                final String loglevelapp = args[0].getStringValue().toLowerCase();
                final String logname = args[1].getStringValue();

                // Use specific logger when provided
                Logger logger = LOG;
                if (logname != null && logname.length() > 0) {
                    logger = LogManager.getLogger(logname);
                }

                writeLog(buf, loglevelapp, logger);
                break;
            }
        }

        return (Sequence.EMPTY_SEQUENCE);
    }

    /**
     *  Write log message to logger with a priority.
     *
     * @param buffer    The log text
     * @param loglevel  The priority of the log message
     * @param logger    The actual logger
     */
    private void writeLog(StringBuilder buffer, String loglevel, Logger logger) {
        switch (loglevel) {
            case "error":
                logger.error(buffer);
                break;
            case "warn":
                logger.warn(buffer);
                break;
            case "info":
                logger.info(buffer);
                break;
            case "trace":
                logger.trace(buffer);
                break;
            default:
                logger.debug(buffer);
                break;
        }
    }
}
@@ -933,16 +933,61 @@
 .util;%0A%0A
+import org.apache.commons.lang3.StringUtils;%0A
 import o
@@ -7124,104 +7124,44 @@
 r = 
-LOG;%0A                if (logname != null && logname.length() %3E 0) %7B%0A                    logger =
+StringUtils.isBlank(logname) ? LOG :
  Log
@@ -7187,34 +7187,16 @@
 ogname);
-%0A                %7D
 %0A%0A      
@@ -7352,17 +7352,16 @@
 *%0A     *
- 
  Write l
@@ -7424,25 +7424,24 @@
 am buffer   
- 
 The log text
@@ -7464,17 +7464,16 @@
 oglevel 
- 
 The prio
@@ -7519,17 +7519,16 @@
 ogger   
- 
 The actu

Make code even more readable