/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.wicket.markup.parser.filter;

import java.text.ParseException;

import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupElement;
import org.apache.wicket.markup.WicketParseException;
import org.apache.wicket.markup.parser.AbstractMarkupFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * This is a markup inline filter which by default is not added to the list of markup filter. It can
 * be added by means of subclassing Application.newMarkupParser() like
 * 
 * <pre>
 * Application#init() {
 *   getMarkupSettings().setMarkupParserFactory() {
 *      new MarkupParserFactory() {
 *      	MarkupParser newMarkupParser(final MarkupResourceStream resource) {
 *        	  MarkupParser parser=super.newMarkupParser(resource);
 *            parser.appendMarkupFilter(new HtmlProblemFinder(HtmlProblemFinder.ERR_THROW_EXCEPTION));
 *            return parser;
 *          }
 *       }
 *    }
 * }
 * </pre>
 * 
 * The purpose of the filter is to find possible HTML issues and to log a warning.
 * 
 * @author Juergen Donnerstag
 */
public final class HtmlProblemFinder extends AbstractMarkupFilter
{
	/** Logging */
	private static final Logger log = LoggerFactory.getLogger(HtmlProblemFinder.class);

	/** Ignore the issue detected */
	public static final int ERR_INGORE = 3;

	/** Log a warning on the issue detected */
	public static final int ERR_LOG_WARN = 2;

	/** Log an error on the issue detected */
	public static final int ERR_LOG_ERROR = 1;

	/** Throw an exception on the issue detected */
	public static final int ERR_THROW_EXCEPTION = 0;

	/** Default behavior in case of a potential HTML issue detected */
	private final int problemEscalation;

	/**
	 * Construct.
	 * 
	 * @param problemEscalation
	 *            How to escalate the issue found.
	 */
	public HtmlProblemFinder(final int problemEscalation)
	{
		this.problemEscalation = problemEscalation;
	}

	@Override
	protected final MarkupElement onComponentTag(ComponentTag tag) throws ParseException
	{
		// Make sure some typical and may be tricky problems are detected and
		// logged.
		if ("img".equals(tag.getName()) && (tag.isOpen() || tag.isOpenClose()))
		{
			String src = tag.getAttributes().getString("src");
			if ((src != null) && (src.trim().length() == 0))
			{
				escalateWarning("Attribute 'src' should not be empty. Location: ", tag);
			}
		}

		// Some people are using a dot "wicket.xxx" instead of a colon
		// "wicket:xxx"
		for (String key : tag.getAttributes().keySet())
		{
			if (key != null)
			{
				key = key.toLowerCase();
				if (key.startsWith("wicket."))
				{
					escalateWarning(
						"You probably want 'wicket:xxx' rather than 'wicket.xxx'. Location: ", tag);
				}
			}
		}

		return tag;
	}

	/**
	 * Handle the issue. Depending the setting either log a warning, an error, throw an exception or
	 * ignore it.
	 * 
	 * @param msg
	 *            The message
	 * @param tag
	 *            The current tag
	 * @throws WicketParseException
	 */
	private void escalateWarning(final String msg, final ComponentTag tag)
		throws WicketParseException
	{
		if (problemEscalation == ERR_LOG_WARN)
		{
			log.warn(msg + tag.toUserDebugString());
		}
		else if (problemEscalation == ERR_LOG_ERROR)
		{
			log.error(msg + tag.toUserDebugString());
		}
		else if (problemEscalation == ERR_INGORE)
		{
			// no action required
		}
		else
		// if (problemEscalation == ERR_THROW_EXCEPTION)
		{
			throw new WicketParseException(msg, tag);
		}
	}
}

@@ -3391,16 +3391,70 @@
 Case();%0A
+%09%09%09%09String namespaceDot = getWicketNamespace() + '.';%0A
 %09%09%09%09if (
@@ -3472,17 +3472,20 @@
 ith(
-%22wicket.%22
+namespaceDot
 ))%0A%09
@@ -3517,16 +3517,30 @@
 (%0A%09%09%09%09%09%09
+String.format(
 %22You pro
@@ -3551,22 +3551,18 @@
 y want '
-wicket
+%25s
 :xxx' ra
@@ -3572,22 +3572,18 @@
 r than '
-wicket
+%25s
 .xxx'. L
@@ -3586,32 +3586,68 @@
 '. Location: %22, 
+namespaceDot, namespaceDot),%0A%09%09%09%09%09%09%09
 tag);%0A%09%09%09%09%7D%0A%09%09%09%7D

Improve HtmlProblemFinder to use the correct wicket namespace