/**
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 */
package net.sourceforge.pmd.lang.java.rule.logging;

import java.util.List;
import java.util.logging.Level;

import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;

public class GuardLogStatementJavaUtilRule extends GuardLogStatementRule {

	private static final String GUARD_METHOD_NAME = "isLoggable";

	private static String extendedXPath = "//PrimaryPrefix[ends-with(Name/@Image, '.log')]\n" + 
	        "[following-sibling::PrimarySuffix\n" + 
	        "    [ends-with(.//PrimaryPrefix/Name/@Image, 'LOG_LEVEL_UPPERCASE')]\n" + 
	        "    [count(../descendant::AdditiveExpression) > 0]\n" + 
	        "]\n" + 
	        "[count(ancestor::IfStatement/Expression/descendant::PrimaryExpression\n" + 
	        "    [ends-with(descendant::PrimaryPrefix[1]/Name/@Image,'GUARD')]) = 0\n" + 
	        "or\n" + 
	        "count(ancestor::IfStatement/Expression/descendant::PrimaryExpression\n" + 
	        "    [ends-with(descendant::PrimaryPrefix[2]/Name/@Image,'LOG_LEVEL_UPPERCASE')]) = 0]";
	
	@Override
	public Object visit(ASTCompilationUnit unit, Object data) {
	    if (isSlf4jOrLog4jImported(unit)) {
	        return data;
	    }

	    String[] logLevels = getProperty(LOG_LEVELS);
	    String[] guardMethods = getProperty(GUARD_METHODS);

        if (super.guardStmtByLogLevel.isEmpty() && logLevels.length > 0 && guardMethods.length > 0) {
            configureGuards(logLevels, guardMethods);
        } else if ( super.guardStmtByLogLevel.isEmpty() ) {
            configureDefaultGuards();
        }

        findViolationForEachLogStatement(unit, data, extendedXPath);
		return super.visit(unit,data);
	}

    private boolean isSlf4jOrLog4jImported(ASTCompilationUnit unit) {
        List<ASTImportDeclaration> imports = unit.findChildrenOfType(ASTImportDeclaration.class);
        for (ASTImportDeclaration i : imports) {
            if (i.getImportedName().startsWith("org.slf4j") || i.getImportedName().startsWith("org.apache.log4j")) {
                return true;
            }
        }
        return false;
    }

    private void configureGuards(String[] logLevels, String[] guardMethods) {
        String[] methods = guardMethods;
        if (methods.length != logLevels.length) {
            String firstMethodName = guardMethods[0];
            methods = new String[logLevels.length];
            for (int i = 0; i < logLevels.length; i++) {
                methods[i] = firstMethodName;
            }
        }
        for (int i = 0; i < logLevels.length; i++) {
            super.guardStmtByLogLevel.put("." + logLevels[i], methods[i]);
        }
    }

    private void configureDefaultGuards() {
        super.guardStmtByLogLevel.put(formatLogLevelString(Level.FINEST), GUARD_METHOD_NAME);
        super.guardStmtByLogLevel.put(formatLogLevelString(Level.FINER), GUARD_METHOD_NAME);
        super.guardStmtByLogLevel.put(formatLogLevelString(Level.FINE), GUARD_METHOD_NAME);
        super.guardStmtByLogLevel.put(formatLogLevelString(Level.INFO), GUARD_METHOD_NAME);
        super.guardStmtByLogLevel.put(formatLogLevelString(Level.WARNING), GUARD_METHOD_NAME);
        super.guardStmtByLogLevel.put(formatLogLevelString(Level.SEVERE), GUARD_METHOD_NAME);
    }

	private String formatLogLevelString(Level logLevel) {
		return "." + logLevel.toString().toLowerCase();
	}
}
