package net.sf.saxon.instruct;

import net.sf.saxon.event.ReceiverOptions;
import net.sf.saxon.event.SequenceReceiver;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.trans.Err;
import net.sf.saxon.type.SimpleType;
import net.sf.saxon.type.ValidationFailure;
import net.sf.saxon.type.ValidationException;
import net.sf.saxon.type.UnresolvedReferenceException;
import net.sf.saxon.om.Validation;
import net.sf.saxon.om.NamePool;
import net.sf.saxon.om.StandardNames;
import net.sf.saxon.value.Whitespace;

/**
 * Abstract class for fixed and computed attribute constructor expressions
 */

public abstract class AttributeCreator extends SimpleNodeConstructor {

    private SimpleType schemaType;
    private int annotation;
    private int validationAction;
    private int options;

    /**
     * Set the required schema type of the attribute
     * @param type the required schema type, if validation against a specific type is required
     */

    public void setSchemaType(SimpleType type) {
        schemaType = type;
    }

    /**
     * Return the required schema type of the attribute
     * @return if validation against a schema type was requested, return the schema type (always a simple type).
     * Otherwise, if validation against a specific type was not requested, return null
     */

    public SimpleType getSchemaType() {
        return schemaType;
    }

    /**
     * Set the validation action required
     * @param action the validation action required, for example strict or lax
     */

    public void setValidationAction(int action) {
        validationAction = action;
    }

    /**
     * Get the validation action requested
     * @return the validation action, for example strict or lax
     */

    public int getValidationAction() {
        return validationAction;
    }

    /**
     * Set the options to be used on the attribute event
     * @param options
     */

    public void setOptions(int options) {
        this.options = options;
    }

    /**
     * Indicate that two attributes with the same name are not acceptable.
     * (This option is set in XQuery, but not in XSLT)
     */

    public void setRejectDuplicates() {
        options |= ReceiverOptions.REJECT_DUPLICATES;
    }

    /**
     * Indicate that the attribute value contains no special characters that
     * might need escaping
     */

    public void setNoSpecialChars() {
        options |= ReceiverOptions.NO_SPECIAL_CHARS;
    }    

    /**
     * Get the options to be used on the attribute event
     * @return the option flags to be used
     */

    public int getOptions() {
        return options;
    }

    /**
     * Set the type annotation fingerprint to be used on the attribute event
     * @param type the fingerprint of the type annotation to be used
     */

    public void setAnnotation(int type) {
        annotation = type;
    }

    /**
     * Get the type annotation fingerprint to be used on the attribute event
     * @return the fingerprint of the type annotation to be used
     */

    public int getAnnotation() {
        return annotation;
    }

    /**
     * Process the value of the node, to create the new node.
     * @param value the string value of the new node
     * @param context the dynamic evaluation context
     * @throws XPathException
     */

    protected final void processValue(CharSequence value, XPathContext context) throws XPathException {
        int nameCode = evaluateNameCode(context);
//        if (nameCode == -1) {
//            return null;
//        }
        SequenceReceiver out = context.getReceiver();
        int opt = getOptions();
        int ann = getAnnotation();

    	// we may need to change the namespace prefix if the one we chose is
    	// already in use with a different namespace URI: this is done behind the scenes
    	// by the ComplexContentOutputter

        //CharSequence value = expandChildren(context).toString();
        SimpleType schemaType = getSchemaType();
        int validationAction = getValidationAction();
        if (schemaType != null) {
            // test whether the value actually conforms to the given type
            try {
                ValidationFailure err = schemaType.validateContent(
                        value, DummyNamespaceResolver.getInstance(), context.getConfiguration().getNameChecker());
                if (err != null) {
                    ValidationException ve = new ValidationException(
                            "Attribute value " + Err.wrap(value, Err.VALUE) +
                                               " does not match the required type " +
                                               schemaType.getDescription() + ". " +
                                               err.getMessage());
                    ve.setErrorCode("XTTE1540");
                    throw ve;
                }
            } catch (UnresolvedReferenceException ure) {
                throw new ValidationException(ure);
            }
        } else if (validationAction== Validation.STRICT ||
                validationAction==Validation.LAX) {
            try {
                ann = context.getConfiguration().validateAttribute(nameCode, value, validationAction);
            } catch (ValidationException e) {
                XPathException err = XPathException.makeXPathException(e);
                err.maybeSetErrorCode((validationAction==Validation.STRICT ? "XTTE1510" : "XTTE1515"));
                err.setXPathContext(context);
                err.maybeSetLocation(this);
                err.setIsTypeError(true);
                throw err;
            }
        }
        if ((nameCode & NamePool.FP_MASK) == StandardNames.XML_ID) {
            value = Whitespace.collapseWhitespace(value);
        }
        try {
            out.attribute(nameCode, ann, value, locationId, opt);
        } catch (XPathException err) {
            throw dynamicError(this, err, context);
        }

        //return null;
    }

}

//
// The contents of this file are subject to the Mozilla Public License Version
// 1.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.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is: all this file.
//
// The Initial Developer of the Original Code is Michael Kay,
//
// Portions created by (your name) are Copyright (C) (your legal entity). All
// Rights Reserved.
//
// Contributor(s): none.
//



