/*
 * Copyright 2001,2004 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * $Id: DatatypeValidatorFactory.cpp 191054 2005-06-17 02:56:35Z jberry $
 */


// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/validators/datatype/DatatypeValidatorFactory.hpp>
#include <xercesc/validators/schema/SchemaSymbols.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/util/Janitor.hpp>
#include <xercesc/validators/datatype/StringDatatypeValidator.hpp>
#include <xercesc/validators/datatype/BooleanDatatypeValidator.hpp>
#include <xercesc/validators/datatype/DecimalDatatypeValidator.hpp>
#include <xercesc/validators/datatype/HexBinaryDatatypeValidator.hpp>
#include <xercesc/validators/datatype/Base64BinaryDatatypeValidator.hpp>
#include <xercesc/validators/datatype/IDDatatypeValidator.hpp>
#include <xercesc/validators/datatype/IDREFDatatypeValidator.hpp>
#include <xercesc/validators/datatype/NOTATIONDatatypeValidator.hpp>
#include <xercesc/validators/datatype/ENTITYDatatypeValidator.hpp>
#include <xercesc/validators/datatype/QNameDatatypeValidator.hpp>
#include <xercesc/validators/datatype/NameDatatypeValidator.hpp>
#include <xercesc/validators/datatype/NCNameDatatypeValidator.hpp>
#include <xercesc/validators/datatype/ListDatatypeValidator.hpp>
#include <xercesc/validators/datatype/UnionDatatypeValidator.hpp>
#include <xercesc/validators/datatype/DoubleDatatypeValidator.hpp>
#include <xercesc/validators/datatype/FloatDatatypeValidator.hpp>
#include <xercesc/validators/datatype/AnyURIDatatypeValidator.hpp>
#include <xercesc/validators/datatype/AnySimpleTypeDatatypeValidator.hpp>
#include <xercesc/validators/datatype/DateTimeDatatypeValidator.hpp>
#include <xercesc/validators/datatype/DateDatatypeValidator.hpp>
#include <xercesc/validators/datatype/TimeDatatypeValidator.hpp>
#include <xercesc/validators/datatype/DayDatatypeValidator.hpp>
#include <xercesc/validators/datatype/MonthDatatypeValidator.hpp>
#include <xercesc/validators/datatype/MonthDayDatatypeValidator.hpp>
#include <xercesc/validators/datatype/YearDatatypeValidator.hpp>
#include <xercesc/validators/datatype/YearMonthDatatypeValidator.hpp>
#include <xercesc/validators/datatype/DurationDatatypeValidator.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLRegisterCleanup.hpp>
#include <xercesc/util/XMLInitializer.hpp>

#include <xercesc/internal/XTemplateSerializer.hpp>
#include <xercesc/util/HashPtr.hpp>

XERCES_CPP_NAMESPACE_BEGIN


// ---------------------------------------------------------------------------
//  DatatypeValidatorFactory: Local const data
// ---------------------------------------------------------------------------
const XMLCh fgTokPattern[] =
{
    chBackSlash, chLatin_c, chPlus, chNull
};

//E2-43
//[+\-]?[0-9]+
const XMLCh fgIntegerPattern[] =
{
    chOpenSquare, chPlus, chBackSlash, chDash, chCloseSquare, chQuestion,
    chOpenSquare, chDigit_0, chDash, chDigit_9, chCloseSquare, chPlus, chNull
};

//"\\i\\c*"
const XMLCh fgNamePattern[] =
{
    chBackSlash, chLatin_i, chBackSlash, chLatin_c, chAsterisk, chNull
};

//"[\\i-[:]][\\c-[:]]*"
const XMLCh fgNCNamePattern[] =
{
    chOpenSquare, chBackSlash, chLatin_i, chDash, chOpenSquare, chColon, chCloseSquare,
    chCloseSquare, chOpenSquare, chBackSlash, chLatin_c, chDash, chOpenSquare,
    chColon, chCloseSquare, chCloseSquare, chAsterisk, chNull
};



const XMLCh fgP0Y[] =
{
    chLatin_P, chDigit_0, chLatin_Y, chNull
};

const XMLCh fgP1Y[] =
{
    chLatin_P, chDigit_1, chLatin_Y, chNull
};

const XMLCh fgP100Y[] =
{
    chLatin_P, chDigit_1, chDigit_0, chDigit_0, chLatin_Y, chNull
};

const XMLCh fgPT24H[] =
{
    chLatin_P, chLatin_T, chDigit_2, chDigit_4, chLatin_H, chNull
};

const XMLCh fgP1M[] =
{
    chLatin_P, chDigit_1, chLatin_M, chNull
};


// ---------------------------------------------------------------------------
//  Local static data
// ---------------------------------------------------------------------------
static bool               sBuiltInRegistryMutexRegistered = false;
static XMLMutex*          sBuiltInRegistryMutex = 0;
static XMLRegisterCleanup builtInRegistryCleanup;


// ---------------------------------------------------------------------------
//  DatatypeValidatorFactory: Static member data
// ---------------------------------------------------------------------------
RefHashTableOf<DatatypeValidator>* DatatypeValidatorFactory::fBuiltInRegistry = 0;
RefHashTableOf<XMLCanRepGroup>*    DatatypeValidatorFactory::fCanRepRegistry = 0;

// ---------------------------------------------------------------------------
//  DatatypeValidatorFactory: Constructors and Destructor
// ---------------------------------------------------------------------------
DatatypeValidatorFactory::DatatypeValidatorFactory(MemoryManager* const manager)
    : fUserDefinedRegistry(0)
    , fMemoryManager(manager)
{
}

DatatypeValidatorFactory::~DatatypeValidatorFactory()
{
	cleanUp();
}


// ---------------------------------------------------------------------------
//  DatatypeValidatorFactory: Reset methods
// ---------------------------------------------------------------------------
void DatatypeValidatorFactory::resetRegistry() {

    if (fUserDefinedRegistry != 0) {
        fUserDefinedRegistry->removeAll();
    }

}


// -----------------------------------------------------------------------
//  Notification that lazy data has been deleted
// -----------------------------------------------------------------------
void DatatypeValidatorFactory::reinitRegistry() {

    delete fBuiltInRegistry;
    fBuiltInRegistry = 0;

    delete fCanRepRegistry;
    fCanRepRegistry = 0;

    // delete local static data
    delete sBuiltInRegistryMutex;
    sBuiltInRegistryMutex = 0;
    sBuiltInRegistryMutexRegistered = false;
}

void XMLInitializer::initializeDVFactory()
{
    DatatypeValidatorFactory *dvFactory = new DatatypeValidatorFactory();
    if (dvFactory) {
        dvFactory->expandRegistryToFullSchemaSet();
        delete dvFactory;
    }
}

// ---------------------------------------------------------------------------
//  DatatypeValidatorFactory: Registry initialization methods
// ---------------------------------------------------------------------------
void DatatypeValidatorFactory::expandRegistryToFullSchemaSet()
{
    if (!sBuiltInRegistryMutexRegistered)
    {
        if (!sBuiltInRegistryMutex)
        {
            XMLMutexLock lock(XMLPlatformUtils::fgAtomicMutex);
            if (!sBuiltInRegistryMutex)
                sBuiltInRegistryMutex = new XMLMutex(XMLPlatformUtils::fgMemoryManager);
        }

        // Use a faux scope to synchronize while we do this
        {
            XMLMutexLock lock(sBuiltInRegistryMutex);

            // If we got here first, then register it and set the registered flag
            if (!sBuiltInRegistryMutexRegistered)
            {
                //Initialize common Schema/DTD Datatype validator set
                fBuiltInRegistry = new RefHashTableOf<DatatypeValidator>(29);

                DatatypeValidator *dv = new StringDatatypeValidator(); 
                dv->setTypeName(SchemaSymbols::fgDT_STRING, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_STRING, dv);
            
                dv = new NOTATIONDatatypeValidator();
                dv->setTypeName(XMLUni::fgNotationString, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) XMLUni::fgNotationString, dv);

                dv = new AnySimpleTypeDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_ANYSIMPLETYPE, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_ANYSIMPLETYPE, dv);

                dv = new BooleanDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_BOOLEAN, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_BOOLEAN, dv);

                dv = new DecimalDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_DECIMAL, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_DECIMAL, dv);

                dv = new HexBinaryDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_HEXBINARY, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_HEXBINARY, dv);

                dv = new Base64BinaryDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_BASE64BINARY, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_BASE64BINARY, dv);

                dv = new DoubleDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_DOUBLE, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_DOUBLE, dv);

                dv = new FloatDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_FLOAT, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_FLOAT, dv);

                dv = new AnyURIDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_ANYURI, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_ANYURI, dv);

                dv = new QNameDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_QNAME, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_QNAME, dv);

                dv = new DateTimeDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_DATETIME, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_DATETIME, dv);

                dv = new DateDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_DATE, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_DATE, dv);

                dv = new TimeDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_TIME, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_TIME, dv);

                dv = new DayDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_DAY, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_DAY, dv);

                dv = new MonthDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_MONTH, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_MONTH, dv);

                dv = new MonthDayDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_MONTHDAY, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_MONTHDAY, dv);

                dv = new YearDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_YEAR, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_YEAR, dv);

                dv = new YearMonthDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_YEARMONTH, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_YEARMONTH, dv);

                dv = new DurationDatatypeValidator();
                dv->setTypeName(SchemaSymbols::fgDT_DURATION, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_DURATION, dv);

                // REVISIT
                // We are creating a lot of Hashtables for the facets of the different
                // validators. It's better to have some kind of a memory pool and ask
                // the pool to give us a new instance of the hashtable.
                RefHashTableOf<KVStringPair>* facets = new RefHashTableOf<KVStringPair>(3);

                // Create 'normalizedString' datatype validator
                facets->put((void*) SchemaSymbols::fgELT_WHITESPACE,
                            new KVStringPair(SchemaSymbols::fgELT_WHITESPACE, SchemaSymbols::fgWS_REPLACE));

                createDatatypeValidator(SchemaSymbols::fgDT_NORMALIZEDSTRING,
                                        getDatatypeValidator(SchemaSymbols::fgDT_STRING),
                                        facets, 0, false, 0, false);

                // Create 'token' datatype validator
                facets = new RefHashTableOf<KVStringPair>(3);
                facets->put((void*) SchemaSymbols::fgELT_WHITESPACE,
                            new KVStringPair(SchemaSymbols::fgELT_WHITESPACE, SchemaSymbols::fgWS_COLLAPSE));

                createDatatypeValidator(SchemaSymbols::fgDT_TOKEN,
                              getDatatypeValidator(SchemaSymbols::fgDT_NORMALIZEDSTRING),
                              facets, 0, false, 0, false);


                dv = new NameDatatypeValidator(getDatatypeValidator(SchemaSymbols::fgDT_TOKEN), 0, 0, 0);
                dv->setTypeName(SchemaSymbols::fgDT_NAME, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_NAME, dv);


                dv = new NCNameDatatypeValidator(getDatatypeValidator(SchemaSymbols::fgDT_NAME), 0, 0, 0);
                dv->setTypeName(SchemaSymbols::fgDT_NCNAME, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) SchemaSymbols::fgDT_NCNAME, dv);

                // Create 'NMTOKEN' datatype validator
                facets = new RefHashTableOf<KVStringPair>(3);

                facets->put((void*) SchemaSymbols::fgELT_PATTERN ,
                                new KVStringPair(SchemaSymbols::fgELT_PATTERN,fgTokPattern));
                facets->put((void*) SchemaSymbols::fgELT_WHITESPACE,
                                new KVStringPair(SchemaSymbols::fgELT_WHITESPACE, SchemaSymbols::fgWS_COLLAPSE));

                createDatatypeValidator(XMLUni::fgNmTokenString,
                                getDatatypeValidator(SchemaSymbols::fgDT_TOKEN),facets, 0, false, 0, false);

                // Create 'NMTOKENS' datatype validator
                createDatatypeValidator(XMLUni::fgNmTokensString,
        	                     getDatatypeValidator(XMLUni::fgNmTokenString), 0, 0, true, 0, false);

                // Create 'language' datatype validator
                facets = new RefHashTableOf<KVStringPair>(3);

                facets->put((void*) SchemaSymbols::fgELT_PATTERN,
                    new KVStringPair(SchemaSymbols::fgELT_PATTERN, XMLUni::fgLangPattern));

                createDatatypeValidator(SchemaSymbols::fgDT_LANGUAGE,
                              getDatatypeValidator(SchemaSymbols::fgDT_TOKEN),
                              facets, 0, false, 0, false);

                // Create 'integer' datatype validator
                facets = new RefHashTableOf<KVStringPair>(3);

                facets->put((void*) SchemaSymbols::fgELT_FRACTIONDIGITS,
                    new KVStringPair(SchemaSymbols::fgELT_FRACTIONDIGITS, XMLUni::fgValueZero));

                facets->put((void*) SchemaSymbols::fgELT_PATTERN,
                            new KVStringPair(SchemaSymbols::fgELT_PATTERN, fgIntegerPattern));

                createDatatypeValidator(SchemaSymbols::fgDT_INTEGER,
                              getDatatypeValidator(SchemaSymbols::fgDT_DECIMAL),
                              facets, 0, false, 0, false);

                // Create 'nonPositiveInteger' datatype validator
                facets = new RefHashTableOf<KVStringPair>(2);

                facets->put((void*) SchemaSymbols::fgELT_MAXINCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MAXINCLUSIVE, XMLUni::fgValueZero));

                createDatatypeValidator(SchemaSymbols::fgDT_NONPOSITIVEINTEGER,
                              getDatatypeValidator(SchemaSymbols::fgDT_INTEGER),
                              facets, 0, false, 0, false);

                // Create 'negativeInteger' datatype validator
                facets = new RefHashTableOf<KVStringPair>(2);

                facets->put((void*) SchemaSymbols::fgELT_MAXINCLUSIVE,
    			            new KVStringPair(SchemaSymbols::fgELT_MAXINCLUSIVE, XMLUni::fgNegOne));

                createDatatypeValidator(SchemaSymbols::fgDT_NEGATIVEINTEGER,
                              getDatatypeValidator(SchemaSymbols::fgDT_NONPOSITIVEINTEGER),
                              facets, 0, false, 0, false);

                // Create 'long' datatype validator
                facets = new RefHashTableOf<KVStringPair>(2);

                facets->put((void*) SchemaSymbols::fgELT_MAXINCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MAXINCLUSIVE, XMLUni::fgLongMaxInc));
                facets->put((void*) SchemaSymbols::fgELT_MININCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MININCLUSIVE, XMLUni::fgLongMinInc));

                createDatatypeValidator(SchemaSymbols::fgDT_LONG,
                              getDatatypeValidator(SchemaSymbols::fgDT_INTEGER),
                              facets, 0, false, 0, false);

                // Create 'int' datatype validator
                facets = new RefHashTableOf<KVStringPair>(2);

                facets->put((void*) SchemaSymbols::fgELT_MAXINCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MAXINCLUSIVE, XMLUni::fgIntMaxInc));
                facets->put((void*) SchemaSymbols::fgELT_MININCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MININCLUSIVE, XMLUni::fgIntMinInc));

                createDatatypeValidator(SchemaSymbols::fgDT_INT,
                              getDatatypeValidator(SchemaSymbols::fgDT_LONG),
                              facets, 0, false, 0, false);

                // Create 'short' datatype validator
                facets = new RefHashTableOf<KVStringPair>(2);

                facets->put((void*) SchemaSymbols::fgELT_MAXINCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MAXINCLUSIVE, XMLUni::fgShortMaxInc));
                facets->put((void*) SchemaSymbols::fgELT_MININCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MININCLUSIVE, XMLUni::fgShortMinInc));

                createDatatypeValidator(SchemaSymbols::fgDT_SHORT,
                              getDatatypeValidator(SchemaSymbols::fgDT_INT),
                              facets, 0, false, 0 ,false);

                // Create 'byte' datatype validator
                facets = new RefHashTableOf<KVStringPair>(2);

                facets->put((void*) SchemaSymbols::fgELT_MAXINCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MAXINCLUSIVE, XMLUni::fgByteMaxInc));
                facets->put((void*) SchemaSymbols::fgELT_MININCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MININCLUSIVE, XMLUni::fgByteMinInc));

                createDatatypeValidator(SchemaSymbols::fgDT_BYTE,
                              getDatatypeValidator(SchemaSymbols::fgDT_SHORT),
                              facets, 0, false, 0, false);

                // Create 'nonNegativeInteger' datatype validator
                facets = new RefHashTableOf<KVStringPair>(2);

                facets->put((void*) SchemaSymbols::fgELT_MININCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MININCLUSIVE, XMLUni::fgValueZero));

                createDatatypeValidator(SchemaSymbols::fgDT_NONNEGATIVEINTEGER,
                              getDatatypeValidator(SchemaSymbols::fgDT_INTEGER),
                              facets, 0, false, 0, false);

                // Create 'unsignedLong' datatype validator
                facets = new RefHashTableOf<KVStringPair>(2);

                facets->put((void*) SchemaSymbols::fgELT_MAXINCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MAXINCLUSIVE, XMLUni::fgULongMaxInc));

                createDatatypeValidator(SchemaSymbols::fgDT_ULONG,
                              getDatatypeValidator(SchemaSymbols::fgDT_NONNEGATIVEINTEGER),
                              facets, 0, false, 0, false);

                // Create 'unsignedInt' datatype validator
                facets = new RefHashTableOf<KVStringPair>(2);

                facets->put((void*) SchemaSymbols::fgELT_MAXINCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MAXINCLUSIVE, XMLUni::fgUIntMaxInc));

                createDatatypeValidator(SchemaSymbols::fgDT_UINT,
                              getDatatypeValidator(SchemaSymbols::fgDT_ULONG),
                              facets, 0, false, 0, false);

                // Create 'unsignedShort' datatypeValidator
                facets = new RefHashTableOf<KVStringPair>(2);

                facets->put((void*) SchemaSymbols::fgELT_MAXINCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MAXINCLUSIVE, XMLUni::fgUShortMaxInc));

                createDatatypeValidator(SchemaSymbols::fgDT_USHORT,
                              getDatatypeValidator(SchemaSymbols::fgDT_UINT),
                              facets, 0, false, 0, false);

                // Create 'unsignedByte' datatype validator
                facets = new RefHashTableOf<KVStringPair>(2);

                facets->put((void*) SchemaSymbols::fgELT_MAXINCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MAXINCLUSIVE, XMLUni::fgUByteMaxInc));

                createDatatypeValidator(SchemaSymbols::fgDT_UBYTE,
                              getDatatypeValidator(SchemaSymbols::fgDT_USHORT),
                              facets, 0, false, 0, false);

                // Create 'positiveInteger' datatype validator
                facets = new RefHashTableOf<KVStringPair>(2);

                facets->put((void*) SchemaSymbols::fgELT_MININCLUSIVE,
                            new KVStringPair(SchemaSymbols::fgELT_MININCLUSIVE, XMLUni::fgValueOne));

                createDatatypeValidator(SchemaSymbols::fgDT_POSITIVEINTEGER,
                              getDatatypeValidator(SchemaSymbols::fgDT_NONNEGATIVEINTEGER),
                              facets, 0, false, 0, false);

                // Create 'ID', 'IDREF' and 'ENTITY' datatype validator
                dv = new IDDatatypeValidator(getDatatypeValidator(SchemaSymbols::fgDT_NCNAME), 0, 0, 0);
                dv->setTypeName(XMLUni::fgIDString, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) XMLUni::fgIDString, dv);

                dv = new IDREFDatatypeValidator(getDatatypeValidator(SchemaSymbols::fgDT_NCNAME), 0, 0, 0);
                dv->setTypeName(XMLUni::fgIDRefString, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) XMLUni::fgIDRefString, dv);

                dv = new ENTITYDatatypeValidator(getDatatypeValidator(SchemaSymbols::fgDT_NCNAME), 0, 0, 0);
                dv->setTypeName(XMLUni::fgEntityString, SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
                fBuiltInRegistry->put((void*) XMLUni::fgEntityString, dv);

                // Create 'IDREFS' datatype validator
                createDatatypeValidator
                (
                    XMLUni::fgIDRefsString
                  , getDatatypeValidator(XMLUni::fgIDRefString)
                  , 0
                  , 0
                  , true
                  , 0
                  , false
                );

               // Create 'ENTITIES' datatype validator
               createDatatypeValidator
               (
                   XMLUni::fgEntitiesString
                 , getDatatypeValidator(XMLUni::fgEntityString)
                 , 0
                 , 0
                 , true
                 , 0
                 , false
               );

                initCanRepRegistory();

                // register cleanup method
                builtInRegistryCleanup.registerCleanup(DatatypeValidatorFactory::reinitRegistry);
                sBuiltInRegistryMutexRegistered = true;
            }
        }
    }
}

/***
 *
 *   For Decimal-derivated, an instance of DecimalDatatypeValidator
 *   can be used by the primitive datatype, decimal, or any one of 
 *   the derivated datatypes, such as int, long, unsighed short, just
 *   name a few, or any user-defined datatypes, which may derivate from
 *   either the primitive datatype, decimal, or from any one of those 
 *   decimal derivated datatypes, or other user-defined datatypes, which
 *   in turn, indirectly derivate from decimal or decimal-derived.
 *
 *   fCanRepRegisty captures deciaml dv and its derivatives.
 *
 ***/
void DatatypeValidatorFactory::initCanRepRegistory()
{

     /***
      * key:  dv
      * data: XMLCanRepGroup
      ***/
     fCanRepRegistry  = new RefHashTableOf<XMLCanRepGroup>(29, true, new HashPtr() );

     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_DECIMAL),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal));

     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_INTEGER),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal_Derivated_signed));
     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_LONG),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal_Derivated_signed));
     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_INT),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal_Derivated_signed));
     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_SHORT),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal_Derivated_signed));
     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_BYTE),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal_Derivated_signed));
     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_NONNEGATIVEINTEGER),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal_Derivated_signed));
     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_POSITIVEINTEGER),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal_Derivated_signed));

     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_NEGATIVEINTEGER),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal_Derivated_unsigned));
     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_ULONG),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal_Derivated_unsigned));
     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_UINT),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal_Derivated_unsigned));
     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_USHORT),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal_Derivated_unsigned));        
     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_UBYTE),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal_Derivated_unsigned));

     fCanRepRegistry->put((void*) getDatatypeValidator(SchemaSymbols::fgDT_NONPOSITIVEINTEGER),
                        new  XMLCanRepGroup(XMLCanRepGroup::Decimal_Derivated_npi));
}

/***
 *
 *   For any dv other than Decimaldv, return String only.
 *   Later on if support to dv other than Decimaldv arise, we may
 *   add them fCanRepRegistry during DatatypeValidatorFactory::initCanRepRegistory()
 *
 ***/
XMLCanRepGroup::CanRepGroup DatatypeValidatorFactory::getCanRepGroup(const DatatypeValidator* const dv)
{
    if (!dv)
        return XMLCanRepGroup::String;

    DatatypeValidator *curdv = (DatatypeValidator*) dv;

    while (curdv)
    {
        if (fCanRepRegistry->containsKey(curdv))
            return fCanRepRegistry->get(curdv)->getGroup();
        else
            curdv = curdv->getBaseValidator();
    }

    return XMLCanRepGroup::String;
}

DatatypeValidator* DatatypeValidatorFactory::getBuiltInBaseValidator(const DatatypeValidator* const dv)
{
    DatatypeValidator *curdv = (DatatypeValidator*)dv;

    while (curdv)
    {
        if (curdv == getBuiltInRegistry()->get(curdv->getTypeLocalName()))
            return curdv;
        else
            curdv = curdv->getBaseValidator();
     }

     return 0;
}

// ---------------------------------------------------------------------------
//  DatatypeValidatorFactory: factory methods
// ---------------------------------------------------------------------------
DatatypeValidator* DatatypeValidatorFactory::createDatatypeValidator
(
      const XMLCh* const                  typeName
	, DatatypeValidator* const            baseValidator
    , RefHashTableOf<KVStringPair>* const facets
    , RefArrayVectorOf<XMLCh>* const      enums
    , const bool                          isDerivedByList
    , const int                           finalSet
    , const bool                          isUserDefined
    , MemoryManager* const                userManager
)
{
	if (baseValidator == 0) {

        if (facets) {
            Janitor<KVStringPairHashTable> janFacets(facets);
        }

        if (enums) {
            Janitor<XMLChRefVector> janEnums(enums);
        }

        return 0;
    }

	DatatypeValidator* datatypeValidator = 0;
    MemoryManager* const manager = (isUserDefined)
        ? userManager : XMLPlatformUtils::fgMemoryManager;

    if (isDerivedByList) {
        datatypeValidator = new (manager) ListDatatypeValidator(baseValidator, facets, enums, finalSet, manager);

        // Set PSVI information for Ordered, Numeric, Bounded & Finite
        datatypeValidator->setOrdered(XSSimpleTypeDefinition::ORDERED_FALSE);
        datatypeValidator->setNumeric(false);
        if (facets &&
             ((facets->get(SchemaSymbols::fgELT_LENGTH) || 
              (facets->get(SchemaSymbols::fgELT_MINLENGTH) && facets->get(SchemaSymbols::fgELT_MAXLENGTH)))))
        {
            datatypeValidator->setBounded(true);
            datatypeValidator->setFinite(true);
        }
        else
        {
            datatypeValidator->setBounded(false);
            datatypeValidator->setFinite(false);
        }
    }
    else {

        if ((baseValidator->getType() != DatatypeValidator::String) && facets) {

            KVStringPair* value = facets->get(SchemaSymbols::fgELT_WHITESPACE);

            if (value != 0) {
                facets->removeKey(SchemaSymbols::fgELT_WHITESPACE);
            }
        }

        datatypeValidator = baseValidator->newInstance
        (
            facets
            , enums
            , finalSet
            , manager
        );

        // Set PSVI information for Ordered, Numeric, Bounded & Finite
        datatypeValidator->setOrdered(baseValidator->getOrdered());
        datatypeValidator->setNumeric(baseValidator->getNumeric());
        RefHashTableOf<KVStringPair>* baseFacets = baseValidator->getFacets();
        if (facets  && 
            ((facets->get(SchemaSymbols::fgELT_MININCLUSIVE) || 
              facets->get(SchemaSymbols::fgELT_MINEXCLUSIVE) ||
              (baseFacets && (baseFacets->get(SchemaSymbols::fgELT_MININCLUSIVE) || 
                              baseFacets->get(SchemaSymbols::fgELT_MINEXCLUSIVE))))) &&
             (facets->get(SchemaSymbols::fgELT_MAXINCLUSIVE) || 
              facets->get(SchemaSymbols::fgELT_MAXEXCLUSIVE) || 
              (baseFacets && ((baseFacets->get(SchemaSymbols::fgELT_MAXINCLUSIVE) || 
                               baseFacets->get(SchemaSymbols::fgELT_MAXEXCLUSIVE))))))
        {
            datatypeValidator->setBounded(true);
        }
        else
        {
            datatypeValidator->setBounded(false);
        }
        if (baseValidator->getFinite())
        {
            datatypeValidator->setFinite(true);
        }
        else if (!facets)
        {
            datatypeValidator->setFinite(false);
        }
        else if (facets->get(SchemaSymbols::fgELT_LENGTH) || facets->get(SchemaSymbols::fgELT_MAXLENGTH) ||
                 facets->get(SchemaSymbols::fgELT_TOTALDIGITS))
        {
            datatypeValidator->setFinite(true);
        }
        //for efficiency use this instead of rechecking...
        //else if ((facets->get(SchemaSymbols::fgELT_MININCLUSIVE) || facets->get(SchemaSymbols::fgELT_MINEXCLUSIVE)) &&
        //         (facets->get(SchemaSymbols::fgELT_MAXINCLUSIVE) || facets->get(SchemaSymbols::fgELT_MAXEXCLUSIVE)))
        else if (datatypeValidator->getBounded() ||
                 datatypeValidator->getType() == DatatypeValidator::Date      || 
                 datatypeValidator->getType() == DatatypeValidator::YearMonth ||
                 datatypeValidator->getType() == DatatypeValidator::Year      ||
                 datatypeValidator->getType() == DatatypeValidator::MonthDay  ||
                 datatypeValidator->getType() == DatatypeValidator::Day       ||
                 datatypeValidator->getType() == DatatypeValidator::Month)
        {
            if (facets->get(SchemaSymbols::fgELT_FRACTIONDIGITS))
            {
                datatypeValidator->setFinite(true);
            }
            else 
            {
                datatypeValidator->setFinite(false);
            }
        }
        else 
        {
            datatypeValidator->setFinite(false);
        }      
    }

    if (datatypeValidator != 0) {

        if (isUserDefined) {

            if (!fUserDefinedRegistry) {
                fUserDefinedRegistry = new (userManager) RefHashTableOf<DatatypeValidator>(29, userManager);
            }

            fUserDefinedRegistry->put((void *)typeName, datatypeValidator);
        }
        else {
            fBuiltInRegistry->put((void *)typeName, datatypeValidator);
        }

        datatypeValidator->setTypeName(typeName);
    }

    return datatypeValidator;
}

static DatatypeValidator::ValidatorType getPrimitiveDV(DatatypeValidator::ValidatorType validationDV)
{
    if (validationDV == DatatypeValidator::ID    || 
        validationDV == DatatypeValidator::IDREF || 
        validationDV == DatatypeValidator::ENTITY)
    {
        return DatatypeValidator::String;
    }
    return validationDV;
}

DatatypeValidator* DatatypeValidatorFactory::createDatatypeValidator
(
      const XMLCh* const                    typeName
    , RefVectorOf<DatatypeValidator>* const validators
    , const int                             finalSet
    , const bool                            userDefined
    , MemoryManager* const                  userManager
)
{
    if (validators == 0)
        return 0;

    DatatypeValidator* datatypeValidator = 0;
    MemoryManager* const manager = (userDefined)
        ? userManager : XMLPlatformUtils::fgMemoryManager;

    datatypeValidator = new (manager) UnionDatatypeValidator(validators, finalSet, manager);

    if (datatypeValidator != 0) {

        if (userDefined) {

            if (!fUserDefinedRegistry) {
                fUserDefinedRegistry = new (userManager) RefHashTableOf<DatatypeValidator>(29, userManager);
            }

            fUserDefinedRegistry->put((void *)typeName, datatypeValidator);
        }
        else {
            fBuiltInRegistry->put((void *)typeName, datatypeValidator);
        }
        datatypeValidator->setTypeName(typeName);

        // Set PSVI information for Ordered, Numeric, Bounded & Finite
        unsigned int valSize = validators->size();
        if (valSize) 
        {
            DatatypeValidator::ValidatorType ancestorId = getPrimitiveDV(validators->elementAt(0)->getType());

            // For a union the ORDERED {value} is partial unless one of the following:
            // 1. If every member of {member type definitions} is derived from a common ancestor other than the simple ur-type, then {value} is the same as that ancestor's ordered facet.
            // 2. If every member of {member type definitions} has a {value} of false for the ordered facet, then {value} is false.
            bool allOrderedFalse = true;
            bool commonAnc = ancestorId != DatatypeValidator::AnySimpleType;
            bool allNumeric = true;
            bool allBounded = true;
            bool allFinite  = true;
        
            for(unsigned int i = 0 ; (i < valSize) && (commonAnc || allOrderedFalse || allNumeric || allBounded || allFinite); i++)
            {
                // for the other member types, check whether the value is false
                // and whether they have the same ancestor as the first one
                if (commonAnc)
                    commonAnc = ancestorId == getPrimitiveDV(validators->elementAt(i)->getType());
                if (allOrderedFalse)
                    allOrderedFalse = validators->elementAt(i)->getOrdered() == XSSimpleTypeDefinition::ORDERED_FALSE;
           
                if (allNumeric && !validators->elementAt(i)->getNumeric())
                {
                    allNumeric = false;
                }
                if (allBounded && (!validators->elementAt(i)->getBounded() ||
                                   ancestorId != getPrimitiveDV(validators->elementAt(i)->getType())))
                {
                    allBounded = false;
                }
                if (allFinite && !validators->elementAt(i)->getFinite())
                {
                    allFinite = false;
                }        
            }
            if (commonAnc) 
            {
                datatypeValidator->setOrdered(validators->elementAt(0)->getOrdered());
            } 
            else if (allOrderedFalse) 
            {
                datatypeValidator->setOrdered(XSSimpleTypeDefinition::ORDERED_FALSE);
            } 
            else 
            {
                datatypeValidator->setOrdered(XSSimpleTypeDefinition::ORDERED_PARTIAL);
            }
            datatypeValidator->setNumeric(allNumeric);
            datatypeValidator->setBounded(allBounded);
            datatypeValidator->setFinite(allFinite);
        }
        else // size = 0
        {
            datatypeValidator->setOrdered(XSSimpleTypeDefinition::ORDERED_PARTIAL);
            datatypeValidator->setNumeric(true);
            datatypeValidator->setBounded(true);
            datatypeValidator->setFinite(true);
        }
    }
    return datatypeValidator;
}

/***
 * Support for Serialization/De-serialization
 ***/

IMPL_XSERIALIZABLE_TOCREATE(DatatypeValidatorFactory)

void DatatypeValidatorFactory::serialize(XSerializeEngine& serEng)
{
      
    // Need not to serialize static data member, fBuiltInRegistry

    if (serEng.isStoring())
    {
        /***
         * Serialize RefHashTableOf<DatatypeValidator>
         ***/
        XTemplateSerializer::storeObject(fUserDefinedRegistry, serEng);
    }
    else
    {
        /***
         * DV in the UserDefinedRegistry rely on the fBuiltInRegistry
         * to resolve their built-in baseValidator
         ***/
        expandRegistryToFullSchemaSet();

        /***
         * Deserialize RefHashTableOf<DatatypeValidator>
         ***/
        XTemplateSerializer::loadObject(&fUserDefinedRegistry, 29, true, serEng);
    }

}

XERCES_CPP_NAMESPACE_END

/**
  * End of file DatatypeValidatorFactory.cpp
  */

