/*
 * 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) 1999, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

package simpletype;

import org.apache.xerces.impl.dv.SchemaDVFactory;
import org.apache.xerces.impl.dv.XSSimpleType;
import org.apache.xerces.impl.dv.XSAtomicSimpleType;
import org.apache.xerces.impl.dv.XSListSimpleType;
import org.apache.xerces.impl.dv.XSUnionSimpleType;
import org.apache.xerces.impl.dv.XSFacets;
import org.apache.xerces.impl.dv.ValidatedInfo;
import org.apache.xerces.impl.dv.InvalidDatatypeFacetException;
import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
import org.apache.xerces.impl.xs.XSTypeDecl;
import org.apache.xerces.impl.xs.SchemaSymbols;
import org.apache.xerces.impl.validation.ValidationContext;
import org.apache.xerces.impl.validation.ValidationState;

import java.util.Vector;

/**
 *  It demonstrates how to use the interfaces defined in 'org.apache.xerces.impl.dv'
 *  package for the purpose of
 * 1. how to query property information of Simple Type Definition Schema Component.
 * 2. how to get instance of SchemaDVFactory implementation.
 * 3. how to get built-in type/s and create new types as derived by restriction, list
 *      or union, using factory methods of SchemaDVFactory.
 * 4. how to use those simple type (built-in/created) to validate the values.
 *    This class is  useful for any application which wants to use the simple type
 * implementation directly as separate module.
 *
 * @author Neeraj Bajaj     Sun Microsystems, inc.
 *
 */

public class SimpleTypeUsage{

static SchemaDVFactory factory = null;
XSFacets facets = new XSFacets();

public SimpleTypeUsage(){

	//Any application willing to switch to different implementation should
	//call SchemaDVFactory#setFactoryClass() as the first step before calling
	//SchemaDVFactory#getInstance().
	//suppose application wants to use class 'MySchemaDVFactoryImpl' as SchemaDVFactory
  // implementation which resides in say 'myApp.simpleType' package.

	//SchemaDVFactory.setFactoryClass("myApp.simpleType.MySchemaDVFactoryImpl.class");

	//this will give the instance of default implementation (SchemaDVFactoryImpl)
  // in 'org.apache.xerces.impl.dv.xs_new' package.
	factory = SchemaDVFactory.getInstance();

} //SimpleTypeUsage()

/**
 * this method shows how to create a simple type derived by restriction using factory
 * methods of <code>org.apache.xerces.impl.dv.SchemaDVFactory</code>.Simple type created
 * is
 *  <simpleType name = myString" final = 'restriction'>
 *      <restriction base = string">
 *          <enumeration value = abc"/>
 *          <enumeration value = lmn"/>
 *          <enumeration value = xyz"/>
 *          <minLength value = 3" fixed="true"/>
 *          <maxLength value = 5" fixed="true"/>
 *       </restriction>
 *  </simpleType>
 *
 * @return XSSimpleType returns created simple type.
 *
 */
public  XSSimpleType deriveByRestriction(){

    String name = "myString";
    String targetNameSpace = "foo";
    String basetype = "string";
    String minLength = "3";
    String maxLength = "5";
    String value1 = "abc";
    String value2 = "lmn";
    String value3 = "xyz";

    System.err.println("<simpleType name = " + name + "\" final = 'restriction'>");
    System.err.println("\t<restriction base = " + basetype + "\">");
    System.err.println("\t\t<enumeration value = " + value1 +  "\"/>");
    System.err.println("\t\t<enumeration value = " + value2 + "\"/>");
    System.err.println("\t\t<enumeration value = " + value3 + "\"/>");
    System.err.println("\t\t<minLength value = "   + minLength + "\" fixed=\"true\"/>");
    System.err.println("\t\t<maxLength value = "   + maxLength + "\" fixed=\"true\"/>");
    System.err.println("\t</restriction>");
    System.err.println("</simpleType>");

    //get 'string' datatype as defined by w3c schema spec
    // <a href = "http://www.w3.org/TR/xmlschema-2/#string"> XML Schema
    // part 2: Datatypes </a>
    XSSimpleType baseType = factory.getBuiltInType(basetype);
    //setting 'final' property as restriction, so as to prevent derivation by restriction
    short finalSet  = SchemaSymbols.RESTRICTION ;

    // creating facets information

    //use vector to store the values of enumeration facet.
    Vector enumValues = new Vector();
    enumValues.addElement(value1);
    enumValues.addElement(value2);
    enumValues.addElement(value3);

    //an application should use object of 'XSFacets' class to pass the value of facets.
    facets.minLength  = Integer.parseInt(minLength);
    facets.maxLength  = Integer.parseInt(maxLength);
    facets.enumeration = enumValues;

    // value of defined facet constants ORed together
    // this way an application should pass the  information about the facets present used
    // to constrain the value space.
    short presentFacets = XSSimpleType.FACET_ENUMERATION | XSSimpleType.FACET_MINLENGTH | XSSimpleType.FACET_MAXLENGTH    ;

    //in the same manner an application should pass the information about the fixed facets.
    short fixedFacets = XSSimpleType.FACET_MINLENGTH | XSSimpleType.FACET_MAXLENGTH  ;

    //using SchemaDVFactory#createTypeRestriction to create a simple type derived by restriction.
    XSSimpleType myDecimalType = factory.createTypeRestriction(name, targetNameSpace, finalSet, baseType);

    // create an instance of 'ValidationState' providing the information required for the
    // validation of datatypes id, idref, entity, notation, qname.
    ValidationState validationState = new ValidationState();
    //application should provide the namespace support by calling
    //validationState.setNamespaceSupport(new org.apache.xerces.util.NamespaceSupport());

    //application can also provide 'SymbolTable' (org.apache.xerces.util.SymbolTable) like
    //org.apache.xerces.util.SymbolTable symbolTable = new org.apache.xerces.util.SymbolTable();
    //validationState.setSymbolTable(symbolTable);

    //we set extrachecking to false as we dont need to do extra id/idref/entity checking
    validationState.setExtraChecking(false);

    try{
        myDecimalType.applyFacets(facets, presentFacets, fixedFacets, validationState);
    }catch(InvalidDatatypeFacetException ex){
        System.err.println(ex.getMessage());
    }

    return myDecimalType;
}//deriveByRestriction()

/**
 * this method shows how to validate the content against the given simple type.
 *
 * @param String content to validate
 * @param XSSimpleType SimpleType Definition schema component against which to validate the content.
 *
 */
public ValidatedInfo validateString(String content, XSSimpleType simpleType){
    //create an instance of 'ValidatedInfo' to get back information (like actual value,
    //normalizedValue etc..)after content is validated.
    ValidatedInfo validatedInfo = new ValidatedInfo();

    // create an instance of 'ValidationState' providing the information required for the
    // validation of datatypes id, idref, entity, notation, qname.
    ValidationState validationState = new ValidationState();
    //application should provide the namespace support by calling
    //validationState.setNamespaceSupport(new org.apache.xerces.util.NamespaceSupport());

    //application can also provide 'SymbolTable' (org.apache.xerces.util.SymbolTable) like
    //org.apache.xerces.util.SymbolTable symbolTable = new org.apache.xerces.util.SymbolTable();
    //validationState.setSymbolTable(symbolTable);

    try{
        simpleType.validate(content, validationState, validatedInfo);
    }catch(InvalidDatatypeValueException ex){
        System.err.println(ex.getMessage());
    }

    //now 'validatedInfo' object contains information

    // for number types (decimal, double, float, and types derived from them),
    // Object return is BigDecimal, Double, Float respectively.
    // for some types (string and derived), they just return the string itself
    Object value = validatedInfo.actualValue;
    //so returned Object can be casted to actual java object
    //Boolean booleanDT = (Boolean)value;

    //The normalized value of a string value
    String normalizedValue = validatedInfo.normalizedValue ;

    //If the type is a union type, then the member type which
    //actually validated the string value.
    XSSimpleType memberType = validatedInfo.memberType ;

    return validatedInfo;

}//validateString()

/**
 * this method shows how to query information about the different properties of 'Simple Type'
 * definiton schema component. It prints the values of properties of 'SimpleType Definition
 * Schema Component'.
 *
 * @param simpleType    object of XSSimpleType
 */
public void querySimpleType(XSSimpleType simpleType){

    //getting information about the different properties of 'Simple Type' definiton schema component.
    System.err.println();
    System.err.println( "Properties information of 'Simple Type' definiton schema component" );
    System.err.println();
    // 'name' property
    if( simpleType.isAnonymous() )
        System.err.println( "Anonymous Simple Type" );
    else{
        System.err.println("'name' \t\t\t\t: " + simpleType.getTypeName()  );
    }

    //'target namespace' property
    String targetNameSpace = simpleType.getTargetNamespace() ;
    System.err.println("'target namespace' \t\t: " + targetNameSpace  );

    // 'variety' property
    short variety = simpleType.getVariety();
    printVariety(variety);

    //'base type definition' property
    XSTypeDecl baseType = simpleType.getBaseType() ;
    System.err.println("'base type definition' name \t: " + baseType.getTypeName()   );
    System.err.println("'base type definition' target namespace : " + baseType.getTargetNamespace());

    //check if base type is simple or complex
    if(baseType.getXSType() == XSTypeDecl.SIMPLE_TYPE ){
        //now we can get all the details of base type
        XSSimpleType simpleTypeDecl = (XSSimpleType)baseType;
    }

    // 'facets' property
    // gives bit combination of the constants defined in XSSimpleType interface.
    short facets = simpleType.getDefinedFacets() ;
    printFacets(facets);

    //'final' property
    //the explicit values of this property extension, restriction, list and union prevent further
    //derivations by extension (to yield a complex type) and restriction (to yield a simple type)
    //and use in constructing lists and unions respectively.
    short finalSet = simpleType.getFinalSet() ;
    printFinal(finalSet);

    //if variety is 'list'
    if( variety == XSSimpleType.VARIETY_LIST ){
        // 'Item Type definition' property of List Simple Type Definition Schema Component.
        XSSimpleType listDecl = ((XSListSimpleType)simpleType).getItemType() ;
    }else if(variety == XSSimpleType.VARIETY_UNION ){
        // 'Member Type definitions' property of Union Simple Type Definition Schema Component.
        XSSimpleType [] memberTypes = ((XSUnionSimpleType)simpleType).getMemberTypes() ;
    }


}//getInformation()

void printFacets(short facets){

    System.err.println("'facets' present \t\t: " );

    if(( facets & XSSimpleType.FACET_ENUMERATION) != 0){
        System.err.println("\t\t\t\t ENUMERATION");
    }
    if((facets & XSSimpleType.FACET_LENGTH) != 0){
        System.err.println("\t\t\t\t LENGTH");
    }
    if((facets & XSSimpleType.FACET_MINLENGTH) != 0){
        System.err.println("\t\t\t\t MINLENGTH");
    }
    if((facets & XSSimpleType.FACET_MAXLENGTH) != 0){
        System.err.println("\t\t\t\t MAXLENGTH");
    }
    if((facets & XSSimpleType.FACET_PATTERN) != 0){
        System.err.println("\t\t\t\t PATTERN");
    }
    if((facets & XSSimpleType.FACET_WHITESPACE) != 0){
        System.err.println("\t\t\t\t WHITESPACE");
    }
    if((facets & XSSimpleType.FACET_MAXINCLUSIVE) != 0){
        System.err.println("\t\t\t\t MAXINCLUSIVE");
    }
    if((facets & XSSimpleType.FACET_MAXEXCLUSIVE) != 0){
        System.err.println("\t\t\t\t MAXEXCLUSIVE");
    }
    if((facets & XSSimpleType.FACET_MININCLUSIVE) != 0){
        System.err.println("\t\t\t\t MININCLUSIVE");
    }
    if((facets & XSSimpleType.FACET_MINEXCLUSIVE) != 0){
        System.err.println("\t\t\t\t MINEXCLUSIVE");
    }
    if((facets & XSSimpleType.FACET_TOTALDIGITS) != 0){
        System.err.println("\t\t\t\t TOTALDIGITS");
    }
    if((facets & XSSimpleType.FACET_FRACTIONDIGITS) != 0){
        System.err.println("\t\t\t\t FRACTIONDIGITS");
    }

}//printFacets()

void printFinal(short finalSet){

    System.err.println("'final' values \t\t\t: " );

    if ((finalSet & SchemaSymbols.EXTENSION ) != 0){
        System.err.println("\t\t\t\t Extension");
    }
    if ((finalSet & SchemaSymbols.RESTRICTION) != 0){
        System.err.println("\t\t\t\t Restriction");
    }
    if((finalSet & SchemaSymbols.LIST ) != 0){
        System.err.println("\t\t\t\t List");
    }
    if((finalSet & SchemaSymbols.UNION ) != 0){
        System.err.println("\t\t\t\t Union");
    }
    if((finalSet & SchemaSymbols.EMPTY_SET ) != 0){
        System.err.println("\t\t\t\t EMPTY");
    }

}

void printVariety(short variety){

    switch(variety){

    case XSSimpleType.VARIETY_ATOMIC:
        System.err.println("'variety' \t\t\t: ATOMIC");
        break;

    case XSSimpleType.VARIETY_LIST:
        System.err.println("'variety' \t\t\t: LIST");
        break;

    case XSSimpleType.VARIETY_UNION:
        System.err.println("'variety' \t\t\t: UNION");
        break;

    default:
        System.err.println("Invalid value of 'Variety' property , it should be one of atomic, list or union.");
        break;
    }


} //printVariety()


public static void main(String [] args){

    SimpleTypeUsage usage = new SimpleTypeUsage();

    if(args.length == 1 ){
        if(args[0].startsWith("sampleType")){
            //querying the property information of Simple Type Definition Schema Component as derived by restriction
            XSSimpleType st = usage.deriveByRestriction() ;
            usage.querySimpleType(st);

        }else{
            XSSimpleType stringType = factory.getBuiltInType(args[0]);
            if(stringType == null){
                System.err.println("Invalid built-in Simple datatype given as argument.");
            }
            else {
                usage.querySimpleType(stringType);
            }
        }

    }else{
        printUsage();
    }

}//main()

static void printUsage(){
        System.err.println("usage: java simpletype.SimpleTypeUsage  (options) ");
        System.err.println();
        System.err.println("options :");

        System.err.println("  built-inType  \t\tprints information about built-in datatype.");
        System.err.println("  sampleType    \t\tprints information about a simple type derived by restriction.");

        System.err.println();
        System.err.println(" For example  'java simpletype.SimpleTypeUsage  decimal' gives");
        System.err.println(" information about the built-in datatype 'decimal' as defined by w3c-spec");
        System.err.println(" http://www.w3.org/TR/xmlschema-2/#decimal");
        System.err.println();
}

}//class SimpleTypeUsage
