/* search.c
 *
 * Written by Matt Levy
 * Modified 20 Aug 1999 by Neil Moore <neil@cs.uky.edu>
 * Modified  5 Sep 1999 by Neil Moore <neil@cs.uky.edu>
 *
 * Part of lderes.  See COPYRIGHT for copyright information.
 *
 */

#ifndef _SEARCH_C
#define _SEARCH_C	1

#include "default_types.h"
#include "SimpleDefaultTheory.h"
#include "search.h"
#include "global.h"
#include "hash.h"
#include <time.h>


inline void printCandidate(SimpleDefaultTheory *theory, Set candidate)
{
	Atom atom;
	int *formula,i;
	int atomCount = 1;
	Element *location;

	if(verbosity <= -1)
		return;
	
	printf ("Cn(W + {");
	location = (Element *) memchr(candidate+1, TRUE, MAX_SET_SIZE(candidate)*sizeof(Element));
	while ((location!=NULL) && (location-candidate)<=MAX_SET_SIZE(candidate)) {
		formula = theory->formulae[theory->DefaultTable[(int) (location - candidate)].consequent];
		for (i=1; i <= formula[0]; i++){
			if (formula[i] < 0)
				printf("!");
			atom = ATOM(formula[i]);
			printf ("%s", lookupName(atom));
			if (i < formula[0])
				printf (", ");
			atomCount++;
		}
		location = (Element *) memchr (location+1,TRUE,
					       (MAX_SET_SIZE(candidate)-(location-candidate))*sizeof(Element));
		if (location != NULL)
			printf(", ");
	}
	printf(" })\n");
}

int FindExtensions(SimpleDefaultTheory *theory, int numberExtensions)
{
  int numberStrata,stratumIndex, numberDefaults;
  int *strata;
  int extensionNumber = 0;
  Set generatingDefaults;
  Stack candidates = CreateStack(2*(theory->DefaultTable[0].prerequisite+1));
  double markerTime;
  int numberCandidates = 0;
  clock_t StartTime;
  double timeTook;
  int currentCandidate,pair;
  
  if (numberExtensions < 0){
	 DISPLAY(printf("Finding all extensions.\n"));
  } else {
	 DISPLAY(printf("Finding up to %d extension", numberExtensions));
	 if (numberExtensions > 1){
		DISPLAY(printf("s.\n\n"));
	 } else{
		DISPLAY(printf(".\n\n"));
	 }
  }
  numberStrata = theory->strata[0];
  strata = (int *) malloc(sizeof(int)*(numberStrata+1));
  /* Set strata so that each entry points to the starting rule of the next
  stratum */
  strata[0] = 1;
  for (stratumIndex=1; stratumIndex <= numberStrata; stratumIndex++)
    strata[stratumIndex] = strata[stratumIndex-1]+theory->strata[stratumIndex];
  numberDefaults = theory->DefaultTable[0].prerequisite;
  generatingDefaults = CreateSet(numberDefaults,0);
  Push(candidates,0);
  StartTime = clock();
  /* The trick here is that the search is done depth-first.  Hence, the
  generatingDefaults set is always correct upto the place we've done so far.
  The only information we need is which stratum we're working on and where in
  the stratum we're working.  This is encoded into a pair which is pushed on
  the stack. */
  while (!STACK_EMPTY(candidates) ){
     int startRule, endRule;
     Boolean result;

     /* Get another candidate */
     pair = Pop(candidates);
     EXTRACT_PAIR(SET_DEPTH(generatingDefaults),
	 SET_STRATUM(generatingDefaults),pair);
     startRule = strata[SET_STRATUM(generatingDefaults)];
     endRule = strata[SET_STRATUM(generatingDefaults)+1]-1;
     if (SET_DEPTH(generatingDefaults) >= 0){
	if (SET_DEPTH(generatingDefaults) == (startRule-1)
	 || (MEMBER(SET_DEPTH(generatingDefaults),generatingDefaults))){
	      numberCandidates++;
	      if ((result = CandidateIsExtension(theory, startRule,
		      endRule,generatingDefaults)) == TRUE){
		 if (SET_STRATUM(generatingDefaults) == (numberStrata-1)){
		    markerTime = clock();
		    ++extensionNumber;
		    if(verbosity > -1) {
			    printf("Extension %d: ", extensionNumber);
			    printCandidate(theory,generatingDefaults);
		    }
		    timeTook = (double) (markerTime - StartTime)/CLOCKS_PER_SEC;
		    if(timex) {
			    printf("Extension %d: %f seconds",
				   extensionNumber, timeTook);
			    if(verbosity > 1)
				    printf("    # Cand.: %d", numberCandidates);
			    
			    printf("\n");
		    }
		    if(verbosity > -1)
			    printf("\n");
		    if (extensionNumber == numberExtensions)
		      goto endPoint;
		    continue;
		 } else{
		    /* Set up next stratum */
		    MAKE_PAIR(endRule,SET_STRATUM(generatingDefaults)+1,pair);
		    Push(candidates,pair);
		    continue;
		 }
	      } else if (result == DONT_KNOW) /* Can prune */ {
		continue;
	     }
	}
     } else{
	SET_DEPTH(generatingDefaults) = -SET_DEPTH(generatingDefaults);
	REMOVE_ELEMENT(SET_DEPTH(generatingDefaults),generatingDefaults);
     }
     if (SET_DEPTH(generatingDefaults) < endRule) {
        currentCandidate = SET_DEPTH(generatingDefaults)+1;
        ADD_ELEMENT(currentCandidate,generatingDefaults);
	MAKE_PAIR(-currentCandidate, SET_STRATUM(generatingDefaults),pair);
        Push(candidates,pair);
	MAKE_PAIR(currentCandidate, SET_STRATUM(generatingDefaults),pair);
        Push(candidates,pair);
     } /* if */
  } /* while */
endPoint:
  return extensionNumber;
}

#endif /* _SEARCH_C */
