/*
 * Copyright (c) 2006-2008, Dennis M. Sosnoski All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer. 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. Neither the name of JiBX nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS 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 COPYRIGHT OWNER OR 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.
 */

package org.jibx.schema.validation;

import org.jibx.runtime.QName;
import org.jibx.schema.NameRegister;
import org.jibx.schema.SchemaVisitor;
import org.jibx.schema.TreeWalker;
import org.jibx.schema.elements.AttributeElement;
import org.jibx.schema.elements.AttributeGroupElement;
import org.jibx.schema.elements.ComplexTypeElement;
import org.jibx.schema.elements.SchemaBase;
import org.jibx.schema.elements.ElementElement;
import org.jibx.schema.elements.GroupElement;
import org.jibx.schema.elements.ImportElement;
import org.jibx.schema.elements.IncludeElement;
import org.jibx.schema.elements.RedefineElement;
import org.jibx.schema.elements.SchemaElement;
import org.jibx.schema.elements.SchemaLocationBase;
import org.jibx.schema.elements.SimpleTypeElement;

/**
 * Visitor for handling registration. This records the names for each child
 * element of the schema in the validation context.
 */
public class RegistrationVisitor extends SchemaVisitor
{
    /** Validation context. */
    private final ValidationContext m_context;

    /**
     * Constructor.
     * 
     * @param context
     */
    public RegistrationVisitor(ValidationContext context) {
        m_context = context;
    }
    
    /**
     * Run registration.
     * 
     * @param root schema element to be validated
     * @param tctx tree context
     */
    public void run(SchemaElement root, TreeWalker tctx) {
        tctx.walkSchema(root, this);
    }
    
    //
    // Visitor implementation methods

    /* (non-Javadoc)
     * @see org.jibx.schema.SchemaVisitor#visit(org.jibx.schema.ElementBase)
     */
    public boolean visit(SchemaBase node) {
        // make sure nothing gets expanded by default
        return false;
    }
    
    /* (non-Javadoc)
     * @see org.jibx.schema.SchemaVisitor#visit(org.jibx.schema.AttributeElement)
     */
    public boolean visit(AttributeElement node) {
        QName qname = node.getQName();
        if (qname != null) {
            m_context.registerAttribute(qname, node);
        }
        return false;
    }
    
    /* (non-Javadoc)
     * @see org.jibx.schema.SchemaVisitor#visit(org.jibx.schema.AttributeGroupElement)
     */
    public boolean visit(AttributeGroupElement node) {
        QName qname = node.getQName();
        if (qname != null) {
            m_context.registerAttributeGroup(qname, node);
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.jibx.schema.SchemaVisitor#visit(org.jibx.schema.ComplexTypeElement)
     */
    public boolean visit(ComplexTypeElement node) {
        QName qname = node.getQName();
        if (qname != null) {
            m_context.registerType(qname, node);
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.jibx.schema.SchemaVisitor#visit(org.jibx.schema.ElementElement)
     */
    public boolean visit(ElementElement node) {
        QName qname = node.getQName();
        if (qname != null) {
            m_context.registerElement(qname, node);
        }
        return false;
    }
    
    /* (non-Javadoc)
     * @see org.jibx.schema.SchemaVisitor#visit(org.jibx.schema.GroupElement)
     */
    public boolean visit(GroupElement node) {
        QName qname = node.getQName();
        if (qname != null) {
            m_context.registerGroup(qname, node);
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.jibx.schema.SchemaVisitor#visit(org.jibx.schema.SchemaElement)
     */
    public boolean visit(SchemaElement node) {
        return true;
    }

    /* (non-Javadoc)
     * @see org.jibx.schema.SchemaVisitor#visit(org.jibx.schema.SchemaLocationBase)
     */
    public boolean visit(SchemaLocationBase node) {
        return true;
    }

    /* (non-Javadoc)
     * @see org.jibx.schema.SchemaVisitor#visit(org.jibx.schema.SimpleTypeElement)
     */
    public boolean visit(SimpleTypeElement node) {
        QName qname = node.getQName();
        if (qname != null) {
            m_context.registerType(qname, node);
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.jibx.schema.SchemaVisitor#exit(org.jibx.schema.elements.ImportElement)
     */
    public void exit(ImportElement node) {
        
        // just merge external definitions
        NameRegister register1 = m_context.getCurrentSchema().getRegister();
        NameRegister register2 = node.getReferencedSchema().getRegister();
        register1.mergeImportedDefinitions(register2);
        super.exit(node);
    }

    /* (non-Javadoc)
     * @see org.jibx.schema.SchemaVisitor#exit(org.jibx.schema.elements.IncludeElement)
     */
    public void exit(IncludeElement node) {
        
        // check for special case of importing nonamespace schema into namespace
        SchemaElement schema1 = m_context.getCurrentSchema();
        SchemaElement schema2 = node.getReferencedSchema();
        String tns = schema1.getTargetNamespace();
        NameRegister register1 = schema1.getRegister();
        NameRegister register2 = schema2.getRegister();
        if (schema2.getTargetNamespace() == null && tns != null) {
            
            // merge imported schema definitions into importing namespace
            register1.mergeDefinitionsNamespaced(tns, register2);
            
        } else {
            
            // just merge definitions without effecting namespace
            register1.mergeDefinitions(register2);
            
        }
        super.exit(node);
    }

    /* (non-Javadoc)
     * @see org.jibx.schema.SchemaVisitor#exit(org.jibx.schema.RedefineElement)
     */
    public void exit(RedefineElement node) {
        // TODO add redefined components to this schema
        super.exit(node);
    }
}