xmlSchemaBuildAContentModel(xmlSchemaParserCtxtPtr pctxt,
			    xmlSchemaParticlePtr particle)
{
    int ret = 0, tmp2;

    if (particle == NULL) {
	PERROR_INT("xmlSchemaBuildAContentModel", "particle is NULL");
	return(1);
    }
    if (particle->children == NULL) {
	/*
	* Just return in this case. A missing "term" of the particle
	* might arise due to an invalid "term" component.
	*/
	return(1);
    }

    switch (particle->children->type) {
	case XML_SCHEMA_TYPE_ANY: {
	    xmlAutomataStatePtr start, end;
	    xmlSchemaWildcardPtr wild;
	    xmlSchemaWildcardNsPtr ns;

	    wild = (xmlSchemaWildcardPtr) particle->children;

	    start = pctxt->state;
	    end = xmlAutomataNewState(pctxt->am);

	    if (particle->maxOccurs == 1) {
		if (wild->any == 1) {
		    /*
		    * We need to add both transitions:
		    *
		    * 1. the {"*", "*"} for elements in a namespace.
		    */
		    pctxt->state =
			xmlAutomataNewTransition2(pctxt->am,
			start, NULL, BAD_CAST "*", BAD_CAST "*", wild);
		    xmlAutomataNewEpsilon(pctxt->am, pctxt->state, end);
		    /*
		    * 2. the {"*"} for elements in no namespace.
		    */
		    pctxt->state =
			xmlAutomataNewTransition2(pctxt->am,
			start, NULL, BAD_CAST "*", NULL, wild);
		    xmlAutomataNewEpsilon(pctxt->am, pctxt->state, end);

		} else if (wild->nsSet != NULL) {
		    ns = wild->nsSet;
		    do {
			pctxt->state = start;
			pctxt->state = xmlAutomataNewTransition2(pctxt->am,
			    pctxt->state, NULL, BAD_CAST "*", ns->value, wild);
			xmlAutomataNewEpsilon(pctxt->am, pctxt->state, end);
			ns = ns->next;
		    } while (ns != NULL);

		} else if (wild->negNsSet != NULL) {
		    pctxt->state = xmlAutomataNewNegTrans(pctxt->am,
			start, end, BAD_CAST "*", wild->negNsSet->value,
			wild);
		}
	    } else {
		int counter;
		xmlAutomataStatePtr hop;
		int maxOccurs =
		    particle->maxOccurs == UNBOUNDED ? UNBOUNDED :
                                           particle->maxOccurs - 1;
		int minOccurs =
		    particle->minOccurs < 1 ? 0 : particle->minOccurs - 1;

		counter = xmlAutomataNewCounter(pctxt->am, minOccurs, maxOccurs);
		hop = xmlAutomataNewState(pctxt->am);
		if (wild->any == 1) {
		    pctxt->state =
			xmlAutomataNewTransition2(pctxt->am,
			start, NULL, BAD_CAST "*", BAD_CAST "*", wild);
		    xmlAutomataNewEpsilon(pctxt->am, pctxt->state, hop);
		    pctxt->state =
			xmlAutomataNewTransition2(pctxt->am,
			start, NULL, BAD_CAST "*", NULL, wild);
		    xmlAutomataNewEpsilon(pctxt->am, pctxt->state, hop);
		} else if (wild->nsSet != NULL) {
		    ns = wild->nsSet;
		    do {
			pctxt->state =
			    xmlAutomataNewTransition2(pctxt->am,
				start, NULL, BAD_CAST "*", ns->value, wild);
			xmlAutomataNewEpsilon(pctxt->am, pctxt->state, hop);
			ns = ns->next;
		    } while (ns != NULL);

		} else if (wild->negNsSet != NULL) {
		    pctxt->state = xmlAutomataNewNegTrans(pctxt->am,
			start, hop, BAD_CAST "*", wild->negNsSet->value,
			wild);
		}
		xmlAutomataNewCountedTrans(pctxt->am, hop, start, counter);
		xmlAutomataNewCounterTrans(pctxt->am, hop, end, counter);
	    }
	    if (particle->minOccurs == 0) {
		xmlAutomataNewEpsilon(pctxt->am, start, end);
                ret = 1;
	    }
	    pctxt->state = end;
            break;
	}
        case XML_SCHEMA_TYPE_ELEMENT:
	    ret = xmlSchemaBuildContentModelForElement(pctxt, particle);
	    break;
        case XML_SCHEMA_TYPE_SEQUENCE:{
            xmlSchemaTreeItemPtr sub;

            ret = 1;
            /*
             * If max and min occurances are default (1) then
             * simply iterate over the particles of the <sequence>.
             */
            if ((particle->minOccurs == 1) && (particle->maxOccurs == 1)) {
                sub = particle->children->children;

                while (sub != NULL) {
                    tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                        (xmlSchemaParticlePtr) sub);
                    if (tmp2 != 1) ret = 0;
                    sub = sub->next;
                }
            } else {
                xmlAutomataStatePtr oldstate = pctxt->state;

                if (particle->maxOccurs >= UNBOUNDED) {
                    if (particle->minOccurs > 1) {
                        xmlAutomataStatePtr tmp;
                        int counter;

                        pctxt->state = xmlAutomataNewEpsilon(pctxt->am,
                            oldstate, NULL);
                        oldstate = pctxt->state;

                        counter = xmlAutomataNewCounter(pctxt->am,
                            particle->minOccurs - 1, UNBOUNDED);

                        sub = particle->children->children;
                        while (sub != NULL) {
                            tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                            (xmlSchemaParticlePtr) sub);
                            if (tmp2 != 1) ret = 0;
                            sub = sub->next;
                        }
                        tmp = pctxt->state;
                        xmlAutomataNewCountedTrans(pctxt->am, tmp,
                                                   oldstate, counter);
                        pctxt->state =
                            xmlAutomataNewCounterTrans(pctxt->am, tmp,
                                                       NULL, counter);
                        if (ret == 1)
                            xmlAutomataNewEpsilon(pctxt->am,
                                                oldstate, pctxt->state);

                    } else {
                        pctxt->state = xmlAutomataNewEpsilon(pctxt->am,
                            oldstate, NULL);
                        oldstate = pctxt->state;

                        sub = particle->children->children;
                        while (sub != NULL) {
                            tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                        (xmlSchemaParticlePtr) sub);
                            if (tmp2 != 1) ret = 0;
                            sub = sub->next;
                        }
                        xmlAutomataNewEpsilon(pctxt->am, pctxt->state,
                                              oldstate);
                        /*
                         * epsilon needed to block previous trans from
                         * being allowed to enter back from another
                         * construct
                         */
                        pctxt->state = xmlAutomataNewEpsilon(pctxt->am,
                                            pctxt->state, NULL);
                        if (particle->minOccurs == 0) {
                            xmlAutomataNewEpsilon(pctxt->am,
                                oldstate, pctxt->state);
                            ret = 1;
                        }
                    }
                } else if ((particle->maxOccurs > 1)
                           || (particle->minOccurs > 1)) {
                    xmlAutomataStatePtr tmp;
                    int counter;

                    pctxt->state = xmlAutomataNewEpsilon(pctxt->am,
                        oldstate, NULL);
                    oldstate = pctxt->state;

                    counter = xmlAutomataNewCounter(pctxt->am,
                        particle->minOccurs - 1,
                        particle->maxOccurs - 1);

                    sub = particle->children->children;
                    while (sub != NULL) {
                        tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                        (xmlSchemaParticlePtr) sub);
                        if (tmp2 != 1) ret = 0;
                        sub = sub->next;
                    }
                    tmp = pctxt->state;
                    xmlAutomataNewCountedTrans(pctxt->am,
                        tmp, oldstate, counter);
                    pctxt->state =
                        xmlAutomataNewCounterTrans(pctxt->am, tmp, NULL,
                                                   counter);
                    if ((particle->minOccurs == 0) || (ret == 1)) {
                        xmlAutomataNewEpsilon(pctxt->am,
                                            oldstate, pctxt->state);
                        ret = 1;
                    }
                } else {
                    sub = particle->children->children;
                    while (sub != NULL) {
                        tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                        (xmlSchemaParticlePtr) sub);
                        if (tmp2 != 1) ret = 0;
                        sub = sub->next;
                    }

		    /*
		     * epsilon needed to block previous trans from
		     * being allowed to enter back from another
		     * construct
		     */
		    pctxt->state = xmlAutomataNewEpsilon(pctxt->am,
					pctxt->state, NULL);

                    if (particle->minOccurs == 0) {
                        xmlAutomataNewEpsilon(pctxt->am, oldstate,
                                              pctxt->state);
                        ret = 1;
                    }
                }
            }
            break;
        }
        case XML_SCHEMA_TYPE_CHOICE:{
            xmlSchemaTreeItemPtr sub;
            xmlAutomataStatePtr start, end;

            ret = 0;
            start = pctxt->state;
            end = xmlAutomataNewState(pctxt->am);

            /*
             * iterate over the subtypes and remerge the end with an
             * epsilon transition
             */
            if (particle->maxOccurs == 1) {
                sub = particle->children->children;
                while (sub != NULL) {
                    pctxt->state = start;
                    tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                        (xmlSchemaParticlePtr) sub);
                    if (tmp2 == 1) ret = 1;
                    xmlAutomataNewEpsilon(pctxt->am, pctxt->state, end);
                    sub = sub->next;
                }
            } else {
                int counter;
                xmlAutomataStatePtr hop, base;
                int maxOccurs = particle->maxOccurs == UNBOUNDED ?
                    UNBOUNDED : particle->maxOccurs - 1;
                int minOccurs =
                    particle->minOccurs < 1 ? 0 : particle->minOccurs - 1;

                /*
                 * use a counter to keep track of the number of transtions
                 * which went through the choice.
                 */
                counter =
                    xmlAutomataNewCounter(pctxt->am, minOccurs, maxOccurs);
                hop = xmlAutomataNewState(pctxt->am);
                base = xmlAutomataNewState(pctxt->am);

                sub = particle->children->children;
                while (sub != NULL) {
                    pctxt->state = base;
                    tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                        (xmlSchemaParticlePtr) sub);
                    if (tmp2 == 1) ret = 1;
                    xmlAutomataNewEpsilon(pctxt->am, pctxt->state, hop);
                    sub = sub->next;
                }
                xmlAutomataNewEpsilon(pctxt->am, start, base);
                xmlAutomataNewCountedTrans(pctxt->am, hop, base, counter);
                xmlAutomataNewCounterTrans(pctxt->am, hop, end, counter);
                if (ret == 1)
                    xmlAutomataNewEpsilon(pctxt->am, base, end);
            }
            if (particle->minOccurs == 0) {
                xmlAutomataNewEpsilon(pctxt->am, start, end);
                ret = 1;
            }
            pctxt->state = end;
            break;
        }
        case XML_SCHEMA_TYPE_ALL:{
            xmlAutomataStatePtr start, tmp;
            xmlSchemaParticlePtr sub;
            xmlSchemaElementPtr elemDecl;

            ret = 1;

            sub = (xmlSchemaParticlePtr) particle->children->children;
            if (sub == NULL)
                break;

            ret = 0;

            start = pctxt->state;
            tmp = xmlAutomataNewState(pctxt->am);
            xmlAutomataNewEpsilon(pctxt->am, pctxt->state, tmp);
            pctxt->state = tmp;
            while (sub != NULL) {
                pctxt->state = tmp;

                elemDecl = (xmlSchemaElementPtr) sub->children;
                if (elemDecl == NULL) {
                    PERROR_INT("xmlSchemaBuildAContentModel",
                        "<element> particle has no term");
                    return(ret);
                };
                /*
                * NOTE: The {max occurs} of all the particles in the
                * {particles} of the group must be 0 or 1; this is
                * already ensured during the parse of the content of
                * <all>.
                */
                if (elemDecl->flags & XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD) {
                    int counter;

                    /*
                     * This is an abstract group, we need to share
                     * the same counter for all the element transitions
                     * derived from the group
                     */
                    counter = xmlAutomataNewCounter(pctxt->am,
                                       sub->minOccurs, sub->maxOccurs);
                    xmlSchemaBuildContentModelForSubstGroup(pctxt,
                                       sub, counter, pctxt->state);
                } else {
                    if ((sub->minOccurs == 1) &&
                        (sub->maxOccurs == 1)) {
                        xmlAutomataNewOnceTrans2(pctxt->am, pctxt->state,
                                                pctxt->state,
                                                elemDecl->name,
                                                elemDecl->targetNamespace,
                                                1, 1, elemDecl);
                    } else if ((sub->minOccurs == 0) &&
                        (sub->maxOccurs == 1)) {

                        xmlAutomataNewCountTrans2(pctxt->am, pctxt->state,
                                                 pctxt->state,
                                                 elemDecl->name,
                                                 elemDecl->targetNamespace,
                                                 0,
                                                 1,
                                                 elemDecl);
                    }
                }
                sub = (xmlSchemaParticlePtr) sub->next;
            }
            pctxt->state =
                xmlAutomataNewAllTrans(pctxt->am, pctxt->state, NULL, 0);
            if (particle->minOccurs == 0) {
                xmlAutomataNewEpsilon(pctxt->am, start, pctxt->state);
                ret = 1;
            }
            break;
        }
	case XML_SCHEMA_TYPE_GROUP:
	    /*
	    * If we hit a model group definition, then this means that
	    * it was empty, thus was not substituted for the containing
	    * model group. Just do nothing in this case.
	    * TODO: But the group should be substituted and not occur at
	    * all in the content model at this point. Fix this.
	    */
            ret = 1;
	    break;
        default:
	    xmlSchemaInternalErr2(ACTXT_CAST pctxt,
		"xmlSchemaBuildAContentModel",
		"found unexpected term of type '%s' in content model",
		WXS_ITEM_TYPE_NAME(particle->children), NULL);
            return(ret);
    }
    return(ret);
}