
/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
package org.apache.xerces.impl.v2;

import  org.apache.xerces.impl.XMLErrorReporter;
import org.apache.xerces.util.DOMUtil;
import org.apache.xerces.xni.QName;
import  org.w3c.dom.Element;

/**
 * The attribute group definition schema component traverser.
 *
 * <attributeGroup
 *   id = ID
 *   name = NCName
 *   ref = QName
 *   {any attributes with non-schema namespace . . .}>
 *   Content: (annotation?, ((attribute | attributeGroup)*, anyAttribute?))
 * </attributeGroup>
 * @version $Id: XSDAttributeGroupTraverser.java,v 1.6 2001/09/07 16:46:14 sandygao Exp $
 * @author Rahul Srivastava, Sun Microsystems Inc.
 */
class  XSDAttributeGroupTraverser extends XSDAbstractTraverser{

    XSDAttributeGroupTraverser (XSDHandler handler,
                                XMLErrorReporter errorReporter,
                                XSAttributeChecker gAttrCheck) {

        super(handler, errorReporter, gAttrCheck);
    }

    int traverseLocal(Element elmNode,
                      XSDocumentInfo schemaDoc,
                      SchemaGrammar grammar) {

        // General Attribute Checking for elmNode declared locally
        Object[] attrValues = fAttrChecker.checkAttributes(elmNode, false, schemaDoc.fNamespaceSupport);
        int elemIdx = traverseAttributeGroupDecl(elmNode, attrValues, schemaDoc, grammar, false);
        fAttrChecker.returnAttrArray(attrValues, schemaDoc.fNamespaceSupport);

        return elemIdx;
    }

    int traverseGlobal(Element elmNode,
                       XSDocumentInfo schemaDoc,
                       SchemaGrammar grammar) {

        // General Attribute Checking for elmNode declared globally
        Object[] attrValues = fAttrChecker.checkAttributes(elmNode, true, schemaDoc.fNamespaceSupport);
        int groupIdx = traverseAttributeGroupDecl(elmNode, attrValues, schemaDoc, grammar, true);
        fAttrChecker.returnAttrArray(attrValues, schemaDoc.fNamespaceSupport);

        return groupIdx;
    }
    
    /**
     * Traverse the attributeGroup element.
     *
     * @param  elmNode
     * @param  attrValues
     * @param  schemaDoc
     * @param  grammar
     * @param  isGlobal
     * @return the element declaration index
     */
    int traverseAttributeGroupDecl(Element elmNode,
                          Object[] attrValues,
                          XSDocumentInfo schemaDoc,
                          SchemaGrammar grammar,
                          boolean isGlobal)
    {

        String  l_strNameAttr   = (String)  attrValues[XSAttributeChecker.ATTIDX_NAME];
        QName   l_qnRefAttr	= (QName)   attrValues[XSAttributeChecker.ATTIDX_REF];

        int l_nReturnIndex = -1;
        String l_strChildName = null;

        // get targetNamespace
        String l_strNamespace = XSDHandler.EMPTY_STRING;
        if (isGlobal)
        {
            l_strNamespace = schemaDoc.fTargetNamespace;
        }
        else if (schemaDoc.fAreLocalElementsQualified)
        {
            l_strNamespace = schemaDoc.fTargetNamespace;
        }

        // check for the constraints on the attributeGroup element.
        //REVISIT: when parent of attributeGroup is <redifine>
        //REVISIT: when parent of attributeGroup is <complexType>
        //REVISIT: check for circular references
        if (isGlobal)
        {
        	// global declaration must have a name
        	if (l_strNameAttr.length() == 0)
        	{
                	reportGenericSchemaError("Global attributeGroup declaration must have a name.");
                }
                
                // global attributeGroup declaration cannot have ref
                if (l_qnRefAttr != null)
                {
                	reportGenericSchemaError("An attributeGroup with \"ref\" present must not have <schema> or <redefine> as its parent");
                }
                
                // check the content viz. childs
                Element l_elmChild = DOMUtil.getFirstChildElement(elmNode);
                
                //REVISIT: Is it valid for a global attributeGroup decl to have NO childs
                if (l_elmChild == null)
                {
                	reportGenericSchemaError("Global attributeGroup declaration must have a child.");
                }
                else
                {
                	if (l_elmChild.equals(SchemaSymbols.ELT_ANNOTATION))
                	{
                		traverseAnnotationDecl(l_elmChild, attrValues, isGlobal, schemaDoc);
                		l_elmChild = DOMUtil.getNextSiblingElement(l_elmChild);
                	}
                	
                	for (; l_elmChild != null; l_elmChild = DOMUtil.getNextSiblingElement(l_elmChild))
                	{
                		l_strChildName = l_elmChild.getLocalName();
                		
                		if (l_strChildName.equals(SchemaSymbols.ELT_ATTRIBUTE))
                		{
                			fSchemaHandler.fAttributeTraverser.traverseLocal(l_elmChild, schemaDoc, grammar);
                			l_elmChild = DOMUtil.getNextSiblingElement(l_elmChild);
                		}
                		else if (l_strChildName.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP))
                		{
                			//REVISIT: do we need to save some state at this point??
                			traverseLocal(l_elmChild, schemaDoc, grammar);
                		}
                		else
                			break;
                	} // for
                	
                	if (l_elmChild != null)
                	{
                		l_strChildName = l_elmChild.getLocalName();
                		if (l_strChildName.equals(SchemaSymbols.ELT_ANYATTRIBUTE))
                		{
                			fSchemaHandler.fWildCardTraverser.traverseAnyAttribute(l_elmChild, schemaDoc, grammar);
                			l_elmChild = DOMUtil.getNextSiblingElement(l_elmChild);
                			l_strChildName = l_elmChild.getLocalName();
                		}
                		
                		if (l_elmChild != null)
                		{
                			Object[] args = new Object [] { "attributeGroup", l_strChildName};
                			fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
                							"AttributeGroupContentRestricted",
                							args,
                							XMLErrorReporter.SEVERITY_ERROR);

                		}
                	} // if
                } // if
        }
        else
        {
            // ref should be here.
            if (l_qnRefAttr == null)
            {
                reportGenericSchemaError("Local attributeGroup declaration should have ref.");
                return l_nReturnIndex;
            }
            
            // local attributeGroup declaration cannot have a name. It only ref(ers).
            if (l_strNameAttr.length() !=0)
            {
                reportGenericSchemaError ( "attributeGroup " + l_strNameAttr + " cannot refer to another attributeGroup, but it refers to " + l_qnRefAttr.localpart);
            }

            // get global decl
            l_nReturnIndex = fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.ATTRIBUTEGROUP_TYPE, l_qnRefAttr);

            // no children are allowed here except annotation, which is optional.
            Element l_elmChild = DOMUtil.getFirstChildElement(elmNode);
            if (l_elmChild != null)
            {
            	if (l_elmChild.equals(SchemaSymbols.ELT_ANNOTATION))
                {
                	traverseAnnotationDecl(l_elmChild, attrValues, isGlobal, schemaDoc);
                	l_elmChild = DOMUtil.getNextSiblingElement(l_elmChild);
                }
                
                if (l_elmChild != null)
                {
                	reportGenericSchemaError("local attributeGroup declaration cannot have content other than <annotation>");
                }
            } // if

        } // if

        return l_nReturnIndex;

    } // traverseAttributeGroupDecl()

}
