// 
// The Waveset SPML General License 
// 
// Version 0.1, April 2003
// Copyright (C) 2003 Waveset Technologies, Inc..
// 6034 West Courtyard Drive, Suite 210, Austin, Texas 78730
// All rights reserved.
// 
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
// 
// 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 disclaimers in Sections 6
//    and 7 below.
// 
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the disclaimers in Sections 6
//    and 7 below 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 
//     Waveset Technologies, Inc. (www.waveset.com)."
// 
//    Alternately, this acknowledgment may appear in the software itself, if
//    and wherever such third-party acknowledgments normally appear.
//  
// 4. The names "Waveset" and "Waveset Technologies, Inc." must not be
//    used to endorse or promote products derived from this software
//    without the prior written permission of Waveset. For written
//    permission, please contact www.waveset.com.
//  
// 5. Products derived from this software may not be called "Waveset",
//    nor may "Waveset" appear in their name, without the prior written
//    permission of Waveset.
//  
// 6. NO WARRANTY 
// 
//    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.
// 
// 7.  LIMITATION OF LIABILITY
// 
//    IN NO EVENT SHALL THE WAVESET OR ITS LICENSORS 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.
// 
// End of Terms and Conditions
// ====================================================================
//
// Component Name: org.openspml.message.Schema
//
// Author(s): Jeff Larson
//
// Description:
//
// Memory representation for a <schema> element.
//
//

package org.openspml.message;

import org.w3c.dom.Document;


import java.util.*;
import org.openspml.util.*;

/**
 * A class representing a <code>schema</code> element.
 */
public class Schema {

    //////////////////////////////////////////////////////////////////////
    //
    // Fields
    //
    //////////////////////////////////////////////////////////////////////

    static final String ELEMENT = "schema";

    /**
     * Major version.
     * Presumably the string representation of a number.
     */
    String _majorVersion;

    /**
     * Minor version.
     */
    String _minorVersion;

    ProviderIdentifier _providerIdentifier;
    SchemaIdentifier _schemaIdentifier;

    /**
     * List of ObjectClassDefinition objects.
     */
    List _classes;

    /**
     * List of AttributeDefinition objects.
     */
    List _attributes;

    /**
     * List of ExtendedRequestDefinition objects.
     */
    List _requests;


    // NOTE: Spec has:
    // <xsd:anyAttribute namespace="##other" processContents="lax" />
    // potentially need to maintain an arbitrary attribute map
    //
    // Spec has:
    // <xsd:any minOccurs="0" maxOccurs="unbounded" processContents="lax" />
    // potentially need to maintain list of DOM elements?

    //////////////////////////////////////////////////////////////////////
    //
    // Constructors
    //
    //////////////////////////////////////////////////////////////////////

    public Schema() {
    }

    /**
     * Build a Schema object from an XML string.
     */
    public Schema(String xml) throws SpmlException {

	Document doc = XmlParser.parse(xml, false);
	XmlElement e = new XmlElement(doc.getDocumentElement());
	parseXml(e);
    }

    Schema(XmlElement e) {
	parseXml(e);
    }

    public void setMajorVersion(String s) {
	_majorVersion = s;
    }

    public void setMinorVersion(String s) {
	_minorVersion = s;
    }

    public void setProviderIdentifier(ProviderIdentifier id) {
        _providerIdentifier = id;
    }

    public void setProviderIdentifier(String id) {
        _providerIdentifier = new ProviderIdentifier(id);
    }

    public void setSchemaIdentifier(SchemaIdentifier id) {
        _schemaIdentifier = id;
    }

    public void setSchemaIdentifier(String s) {
        _schemaIdentifier = new SchemaIdentifier(s);
    }

    public void setObjectClassDefinitions(List l) {
	_classes = l;
    }

    public void addObjectClassDefinition(ObjectClassDefinition obj) {
	if (_classes == null)
	    _classes = new ArrayList();
	_classes.add(obj);
        obj.setSchema(this);
    }

    public void setAttributeDefinitions(List l) {
	_attributes = l;
    }

    public void addAttributeDefinition(AttributeDefinition obj) {
	if (_attributes == null)
	    _attributes = new ArrayList();
	_attributes.add(obj);
    }

    public void setExtendedRequestDefinitions(List l) {
	_attributes = l;
    }

    public void addExtendedRequestDefinition(ExtendedRequestDefinition obj) {
	if (_requests == null)
	    _requests = new ArrayList();
	_requests.add(obj);
        obj.setSchema(this);
    }

    //////////////////////////////////////////////////////////////////////
    //
    // Accessors
    //
    //////////////////////////////////////////////////////////////////////
    
    public String getMajorVersion() {
	return _majorVersion;
    }

    public String getMinorVersion() {
	return _minorVersion;
    }

    public ProviderIdentifier getProviderIdentifier() {
	return _providerIdentifier;
    }

    public String getProviderIdentifierString() {
	return (_providerIdentifier != null) ? 
            _providerIdentifier.getId() : null;
    }

    public SchemaIdentifier getSchemaIdentifier() {
	return _schemaIdentifier;
    }

    public String getSchemaIdentifierString() {
	return (_schemaIdentifier != null) ? 
            _schemaIdentifier.getId() : null;
    }

    public List getObjectClassDefinitions() {
	return _classes;
    }

    public ObjectClassDefinition getObjectClassDefinition(String name) {
        ObjectClassDefinition found = null;
        if (_classes != null) {
            for (int i = 0 ; i < _classes.size() ; i++) {
                ObjectClassDefinition ocd = (ObjectClassDefinition)
                    _classes.get(i);
                if (name != null && name.equals(ocd.getName())) {
                    found = ocd;
                    break;
                }
            }
        }
        return found;
    }

    public List getAttributeDefinitions() {
	return _attributes;
    }

    public AttributeDefinition getAttributeDefinition(String name) {
        AttributeDefinition found = null;
        if (_attributes != null) {
            for (int i = 0 ; i < _attributes.size() ; i++) {
                AttributeDefinition ad = (AttributeDefinition)
                    _attributes.get(i);
                if (name != null && name.equals(ad.getName())) {
                    found = ad;
                    break;
                }
            }
        }
        return found;
    }

    /**
     * Convenience accessor to return a list of resolved
     * AttributeDefinition objects.
     */
    public List getAttributeDefinitions(List refs) {

        List defs = null;
        if (refs != null) {
            for (int i = 0 ; i < refs.size() ; i++) {
                AttributeDefinitionReference ref = 
                    (AttributeDefinitionReference)
                    refs.get(i);

                // in theory we may need to jump to another schema,
                // assume for now we're self contained
                AttributeDefinition def = 
                    getAttributeDefinition(ref.getName());

                if (def != null) {
                    if (defs == null)
                        defs = new ArrayList();
                    defs.add(def);
                }
            }
        }
        return defs;
    }

    public List getExtendedRequestDefinitions() {
	return _requests;
    }

    //////////////////////////////////////////////////////////////////////
    //
    // XML
    //
    //////////////////////////////////////////////////////////////////////

    void toXml(SpmlBuffer b) {

        b.addOpenStartTag(ELEMENT);
	b.addAttribute("majorVersion", _majorVersion);
	b.addAttribute("minorVersion", _minorVersion);
        b.closeStartTag();
        b.incIndent();

	// spec uses <xsd:sequence> so they must be
	// in this order

	if (_providerIdentifier != null)
	    _providerIdentifier.toXml(b);

	if (_schemaIdentifier != null)
	    _schemaIdentifier.toXml(b);

        if (_classes != null) {
            Iterator it = _classes.iterator();
            while (it.hasNext()) {
                ObjectClassDefinition obj = 
		    (ObjectClassDefinition)it.next();
                obj.toXml(b);
            }
        }

        if (_attributes != null) {
            Iterator it = _attributes.iterator();
            while (it.hasNext()) {
                AttributeDefinition obj = 
		    (AttributeDefinition)it.next();
                obj.toXml(b);
            }
        }

        if (_requests != null) {
            Iterator it = _requests.iterator();
            while (it.hasNext()) {
                ExtendedRequestDefinition obj = 
		    (ExtendedRequestDefinition)it.next();
                obj.toXml(b);
            }
        }

        b.decIndent();
        b.addEndTag(ELEMENT);
    }

    void parseXml(XmlElement e) {

	// in theory, need to recognize and maintain 
	// other arbitrary elements

	_majorVersion = e.getAttribute("majorVersion");
	_minorVersion = e.getAttribute("minorVersion");

	for (XmlElement child = e.getChildElement() ; 
	     child != null ; child = child.next()) {

	    String tag = child.getLocalName();

	    if (tag.equals(ProviderIdentifier.ELEMENT))
                _providerIdentifier = new ProviderIdentifier(child);

	    else if (tag.equals(SchemaIdentifier.ELEMENT))
                _schemaIdentifier = new SchemaIdentifier(child);

	    else if (tag.equals(ObjectClassDefinition.ELEMENT))
                addObjectClassDefinition(new ObjectClassDefinition(child));

	    else if (tag.equals(AttributeDefinition.ELEMENT))
                addAttributeDefinition(new AttributeDefinition(child));

	    else if (tag.equals(ExtendedRequestDefinition.ELEMENT))
                addExtendedRequestDefinition(new ExtendedRequestDefinition(child));
	    
	    // in theory, need to recognize and maintain 
	    // other arbitrary elements

        }
    }

}

