/*
 * 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.xs.traversers;

import  org.apache.xerces.impl.XMLErrorReporter;
import org.apache.xerces.impl.xs.SchemaGrammar;
import org.apache.xerces.impl.xs.SchemaSymbols;
import org.apache.xerces.impl.xs.SchemaNamespaceSupport;

import  org.apache.xerces.util.DOMUtil;
import  org.w3c.dom.Element;
import org.apache.xerces.impl.xs.identity.*;
import org.apache.xerces.impl.xpath.*;

/**
 * This class contains code that all three IdentityConstraint
 * traversers (the XSDUniqueTraverser, XSDKeyTraverser and
 * XSDKeyrefTraverser) rely upon.
 *
 * @version $Id$
 */
class XSDAbstractIDConstraintTraverser extends XSDAbstractTraverser {

    public XSDAbstractIDConstraintTraverser (XSDHandler handler,
                                  XSAttributeChecker gAttrCheck) {
        super(handler, gAttrCheck);
    }

    void traverseIdentityConstraint(IdentityConstraint ic,
            Element icElem, XSDocumentInfo schemaDoc, Object [] icElemAttrs) {

        // General Attribute Checking will have been done on icElem by caller

        // check for <annotation> and get selector
        Element sElem = DOMUtil.getFirstChildElement(icElem);
        if(sElem == null) {
            // REVISIT: localize
            reportGenericSchemaError("The content of an identity constraint must match (annotation?, selector, field+)");
            return;
        }

        // General Attribute Checking on sElem
        // first child could be an annotation
        if (DOMUtil.getLocalName(sElem).equals(SchemaSymbols.ELT_ANNOTATION)) {
            traverseAnnotationDecl(sElem, icElemAttrs, false, schemaDoc);
            sElem = DOMUtil.getNextSiblingElement(sElem);
        }
        // if no more children report an error
        if(sElem == null) {
            // REVISIT: localize
            reportGenericSchemaError("The content of an identity constraint must match (annotation?, selector, field+)");
            return;
        }
        Object [] attrValues = fAttrChecker.checkAttributes(sElem, false, schemaDoc);
        
        // if more than one annotation report an error
        if(!DOMUtil.getLocalName(sElem).equals(SchemaSymbols.ELT_SELECTOR)) {
            // REVISIT: localize
            reportGenericSchemaError("The content of an identity constraint must match (annotation?, selector, field+)");
        }
        // and make sure <selector>'s content is fine:
        Element selChild = DOMUtil.getFirstChildElement(sElem);
        
        if (selChild !=null) {
            // traverse annotation if any
            if (DOMUtil.getLocalName(selChild).equals(SchemaSymbols.ELT_ANNOTATION)) {
                traverseAnnotationDecl(selChild, attrValues, false, schemaDoc);
                selChild = DOMUtil.getNextSiblingElement(selChild);
            }
            else {
                reportGenericSchemaError("The content of an identity constraint must match (annotation?, selector, field+)");
            }
            if (selChild != null) {
                reportSchemaError("src-identity-constraint.1", new Object [] {icElemAttrs[XSAttributeChecker.ATTIDX_NAME]});
            }
        }

        String sText = ((String)attrValues[XSAttributeChecker.ATTIDX_XPATH]);
        if(sText == null) {
            reportSchemaError("s4s-att-must-appear", new Object [] {SchemaSymbols.ELT_SELECTOR, SchemaSymbols.ATT_XPATH});
            return;
        }
        sText = sText.trim();

        Selector.XPath sXpath = null;
        try {
            sXpath = new Selector.XPath(sText, fSymbolTable,
                                        schemaDoc.fNamespaceSupport);
            Selector selector = new Selector(sXpath, ic);
            ic.setSelector(selector);
        }
        catch (XPathException e) {
            // REVISIT: Add error message.
            reportGenericSchemaError(e.getMessage());
            // put back attr values...
            fAttrChecker.returnAttrArray(attrValues, schemaDoc);
            return;
        }

        // put back attr values...
        fAttrChecker.returnAttrArray(attrValues, schemaDoc);

        // get fields
        Element fElem = DOMUtil.getNextSiblingElement(sElem);
        if(fElem == null) {
            // REVISIT:  localize
            reportGenericSchemaError("The content of an identity constraint must match (annotation?, selector, field+)");
        }
        while (fElem != null) {
            // General Attribute Checking
            attrValues = fAttrChecker.checkAttributes(fElem, false, schemaDoc);

            if(!DOMUtil.getLocalName(fElem).equals(SchemaSymbols.ELT_FIELD))
                // REVISIT: localize
                reportGenericSchemaError("The content of an identity constraint must match (annotation?, selector, field+)");
            
            // and make sure <field>'s content is fine:
            Element fieldChild = DOMUtil.getFirstChildElement(fElem);
            if (fieldChild != null) {            
                // traverse annotation
                if (DOMUtil.getLocalName(fieldChild).equals(SchemaSymbols.ELT_ANNOTATION)) {
                    traverseAnnotationDecl(fieldChild, attrValues, false, schemaDoc);
                    fieldChild = DOMUtil.getNextSiblingElement(fieldChild);
                }
            }
            if (fieldChild != null) {
                reportSchemaError("src-identity-constraint.1", new Object [] {icElemAttrs[XSAttributeChecker.ATTIDX_NAME]});
            }
            String fText = ((String)attrValues[XSAttributeChecker.ATTIDX_XPATH]);
            if(fText == null) {
                reportSchemaError("s4s-att-must-appear", new Object [] {SchemaSymbols.ELT_FIELD, SchemaSymbols.ATT_XPATH});
                return;
            }
            fText = fText.trim();
            try {
                Field.XPath fXpath = new Field.XPath(fText, fSymbolTable,
                                                     schemaDoc.fNamespaceSupport);
                Field field = new Field(fXpath, ic);
                ic.addField(field);
            }
            catch (XPathException e) {
                // REVISIT: Add error message.
                reportGenericSchemaError(e.getMessage());
                // put back attr values...
                fAttrChecker.returnAttrArray(attrValues, schemaDoc);
                return;
            }
            fElem = DOMUtil.getNextSiblingElement(fElem);
            // put back attr values...
            fAttrChecker.returnAttrArray(attrValues, schemaDoc);
        }

    } // traverseIdentityConstraint(IdentityConstraint,Element, XSDocumentInfo)
} // XSDAbstractIDConstraintTraverser

