/*****************************************************************************
 * \file non-ors.cc                                                          *
 *                                                                           *
 * Description: Contains the matchNonORs() functions for the EntList descen- *
 *              dants.  matchNonORs() functions loop through the EntList     *
 *              children of this whose JoinType != OR (and check a Simple-   *
 *              List itself) to determine how well they match an EntNode.    *
 *                                                                           *
 * Created by:  David Rosenfeld                                              *
 * Date:        10/17/96                                                     *
 *****************************************************************************/

#include "clstepcore/complexSupport.h"

/**
 * Checks if we match the nodes of ents.  If only one unmarked is left
 * and we match it, return MATCHALL.  More likely, we'll return one of the
 * other return values.  (See descript of MatchType values in complex-
 * Support.h.)
 */
MatchType SimpleList::matchNonORs( EntNode * ents ) {
    EntNode * eptr = ents;
    int comp;

    while( eptr != NULL ) {
        if( ( comp = strcmp( name, eptr->name ) ) == 0 ) {
            if( ! eptr->marked( MARK ) ) {
                // NOTE - this cond also returns true if eptr did have an OR-
                // MARK.  We don't want to remark now (since we're also trying
                // out OR choices -- we know this because no OR's are done
                // until after all the non-OR's).  But, we do want to return
                // MATCHSOME, as below.  Since The prev OR which marked this
                // may one time later try another path, we want to record that
                // our OR can also mark it.  So we return MATCHSOME saying
                // this is a viable option we may one time want to try.
                if( eptr->mark == NOMARK ) {
                    eptr->setmark();
                    I_marked = MARK;
                    // Remember that we're the one who marked this.  (Nec. in
                    // case we have to unmark later to try out another OR
                    // branch.)
                    if( ents->allMarked() ) {
                        // If this was the only unmarked left,
                        viable = MATCHALL;
                        return MATCHALL;
                    }
                }
                viable = MATCHSOME;
                return MATCHSOME;
            }
            viable = SATISFIED;
            return SATISFIED;
            // Couldn't mark any more, but at least we're not placing a re-
            // quirement ents couldn't meet.
        }
        if( comp < 0 ) {
            // We're beyond name in the ents list.  No more checking to do.
            break;
        }
        eptr = eptr->next;
    }

    // At this point, we went through the list without finding a match.  Result
    // = UNSATISFIED - no match.
    viable = UNSATISFIED;
    return UNSATISFIED;
}

/**
 * Loop through the children of this matching as many of the nodes of ents
 * as we can.  We skip all OrList descendants.  Those are processed later
 * only after all the non-conditional descendants, so that when we start
 * processing them we'll be able to tell which OR choices are viable, and
 * which are unnec.
 */
MatchType AndOrList::matchNonORs( EntNode * ents ) {
    EntList * child = childList->firstNot( OR );
    MatchType retval;

    while( child != NULL ) {
        if( ( retval = child->matchNonORs( ents ) ) == MATCHALL ) {
            if( prevKnown( child ) ) {
                viable = MATCHALL;
                return MATCHALL;
                // We found a good solution.  Nothing else to do.  (Some higher
                // AND may have some other req's ents can't meet, but that's
                // not our problem.  If that happens, AND will return UNSATIS-
                // FIED, or an even higher OR will undo all and will try
                // another path.)
                // The prevKnown() fn is used to check that we haven't come
                // across any UNKNOWNs yet.  If we have, we can't be sure the
                // MATCHALL is valid.  An illustration:  One of our previous
                // children was an AND who had a SIMPLE child and an OR child.
                // The SIMPLE child matched one EntNode.  The OR child is
                // UNKNOWN, since we haven't matchOR()'ed yet.  Possibly, our
                // retval of MATCHALL is in part due to the SIMPLE child of
                // the AND.  But if the OR child of the AND returns UNSAT when
                // we run matchOR(), we'll unmark the SIMPLE child too.  Thus,
                // we can only be sure of a MATCHALL if nothing is UNKNOWN.
                // (Note that future UNKNOWN children don't bother us (in fact
                // all future children are UNKNOWN by default since they have
                // not been touched).  This is because we're an ANDOR and can
                // skip them altogether.  But previous children we have visi-
                // ted already, and we can't ignore, as above.  Compare to
                // AndOrList::matchORs(), where since all children had been
                // visited already in matchNonORs(), we were not able to stop
                // in process as here at all.)
            }
        } else if( retval == UNSATISFIED ) {
            // Unmark whatever we may have marked.  (E.g., there may have
            // been an AND beneath and it started marking and then found one
            // it couldn't match.)
            child->unmarkAll( ents );
        }
        child = child->nextNot( OR );
    }
    setViableVal( ents );
    return viable;
}

/**
 * Checks if the AndList contains the set of nodes in ents.  Skip OrList
 * descendants.
 */
MatchType AndList::matchNonORs( EntNode * ents ) {
    EntList * child = childList->firstNot( OR );

    while( child != NULL ) {
        if( child->matchNonORs( ents ) == UNSATISFIED ) {
            viable = UNSATISFIED;
            return UNSATISFIED;
            // This means the whole AndList has failed, by definition.
        }
        child = child->nextNot( OR );
        // Note - we loop through all even if one of our children returned
        // MATCHALL.  Since we're an AND, we must look through all branches -
        // to search for any other conditions we can't meet.  If one of our
        // children did MATCHALL, its viable val will be set to MATCHALL and
        // we'll catch it in setViableVal() called below.
    }
    setViableVal( ents );
    return viable;
}
