/*
 *  Copyright 2008 biaoping.yin
 *
 *  Licensed 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.frameworkset.web.util;

import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;

import org.frameworkset.util.Assert;

/**
 * <p>Title: TagUtils.java</p> 
 * <p>Description: </p>
 * <p>bboss workgroup</p>
 * <p>Copyright (c) 2008</p>
 * @Date 2010-10-10
 * @author biaoping.yin
 * @version 1.0
 */
public abstract class TagUtils {
	

		/** Constant identifying the page scope */
		public static final String SCOPE_PAGE = "page";

		/** Constant identifying the request scope */
		public static final String SCOPE_REQUEST = "request";

		/** Constant identifying the session scope */
		public static final String SCOPE_SESSION = "session";

		/** Constant identifying the application scope */
		public static final String SCOPE_APPLICATION = "application";


		/**
		 * Determines the scope for a given input <code>String</code>.
		 * <p>If the <code>String</code> does not match 'request', 'session',
		 * 'page' or 'application', the method will return {@link PageContext#PAGE_SCOPE}.
		 * @param scope the <code>String</code> to inspect
		 * @return the scope found, or {@link PageContext#PAGE_SCOPE} if no scope matched
		 * @throws IllegalArgumentException if the supplied <code>scope</code> is <code>null</code> 
		 */
		public static int getScope(String scope) {
			Assert.notNull(scope, "Scope to search for cannot be null");
			if (scope.equals(SCOPE_REQUEST)) {
				return PageContext.REQUEST_SCOPE;
			}
			else if (scope.equals(SCOPE_SESSION)) {
				return PageContext.SESSION_SCOPE;
			}
			else if (scope.equals(SCOPE_APPLICATION)) {
				return PageContext.APPLICATION_SCOPE;
			}
			else {
				return PageContext.PAGE_SCOPE;
			}
		}

		/**
		 * Determine whether the supplied {@link Tag} has any ancestor tag
		 * of the supplied type.
		 * @param tag the tag whose ancestors are to be checked
		 * @param ancestorTagClass the ancestor {@link Class} being searched for
		 * @return <code>true</code> if the supplied {@link Tag} has any ancestor tag
		 * of the supplied type
		 * @throws IllegalArgumentException if either of the supplied arguments is <code>null</code>;
		 * or if the supplied <code>ancestorTagClass</code> is not type-assignable to
		 * the {@link Tag} class 
		 */
		public static boolean hasAncestorOfType(Tag tag, Class ancestorTagClass) {
			Assert.notNull(tag, "Tag cannot be null");
			Assert.notNull(ancestorTagClass, "Ancestor tag class cannot be null");
			if (!Tag.class.isAssignableFrom(ancestorTagClass)) {
				throw new IllegalArgumentException(
						"Class '" + ancestorTagClass.getName() + "' is not a valid Tag type");
			}
			Tag ancestor = tag.getParent();
			while (ancestor != null) {
				if (ancestorTagClass.isAssignableFrom(ancestor.getClass())) {
					return true;
				}
				ancestor = ancestor.getParent();
			}
			return false;
		}

		/**
		 * Determine whether the supplied {@link Tag} has any ancestor tag
		 * of the supplied type, throwing an {@link IllegalStateException}
		 * if not.
		 * @param tag the tag whose ancestors are to be checked
		 * @param ancestorTagClass the ancestor {@link Class} being searched for
		 * @param tagName the name of the <code>tag</code>; for example '<code>option</code>'
		 * @param ancestorTagName the name of the ancestor <code>tag</code>; for example '<code>select</code>'
		 * @throws IllegalStateException if the supplied <code>tag</code> does not
		 * have a tag of the supplied <code>parentTagClass</code> as an ancestor
		 * @throws IllegalArgumentException if any of the supplied arguments is <code>null</code>,
		 * or in the case of the {@link String}-typed arguments, is composed wholly
		 * of whitespace; or if the supplied <code>ancestorTagClass</code> is not
		 * type-assignable to the {@link Tag} class 
		 * @see #hasAncestorOfType(javax.servlet.jsp.tagext.Tag, Class)
		 */
		public static void assertHasAncestorOfType(Tag tag, Class ancestorTagClass, String tagName, String ancestorTagName) {
			Assert.hasText(tagName, "'tagName' must not be empty");
			Assert.hasText(ancestorTagName, "'ancestorTagName' must not be empty");
			if (!TagUtils.hasAncestorOfType(tag, ancestorTagClass)) {
				throw new IllegalStateException("The '" + tagName + "' tag can only be used inside a valid '" + ancestorTagName + "' tag.");
			}
		}

}
