#include "prodsys.h"
     
int production_system(char *context) 
{
 int  hit_number           = 0,
      hits[L],
      i                    = 0,
      interpreting_context = 1,
      lowest               = L,
      no_hits              = 1,
      reading_rules        = 1,
      result               = 1,
      rule_number          = 1;
    
char rule[L];
    
while(interpreting_context){
    
   for(i=0; i<L; i++)
      hits[i] = LIMIT;
   hit_number = 0;
    
   no_hits       = 1;
   rule_number   = 1;
   reading_rules = 1;
   while(reading_rules){
     reading_rules =
         read_a_rule(rule_number, rule);
     rule_number++;
    
     if(is_a_hit(context, rule)){
       no_hits            = 0;
       hits[hit_number++] = rule_number-1;
     }
   }  /* ends while reading_rules */
    
if(!no_hits){
   /* deactivate any hit whose action adds
      a duplicate to the context */
    
   for(i=0; i<L; i++){
     if(hits[i] != LIMIT){
       read_a_rule(hits[i], rule);
       if(is_a_duplicate(context, rule))
            hits[i] = LIMIT;
     }  /* ends if hits */
   }  /* ends loop through hits */
    
   lowest = lowest_number(hits);
    
   if(lowest == LIMIT){
     no_hits = 1;
   }  /* ends if lowest == LIMIT */
   else{
     fire_rule(context, lowest);
   }  /* ends else lowest != LIMIT */
}  /* ends if not no_hits */
    
    
if(no_hits)
   interpreting_context = 0;
    
}  /* ends while */
    
return(result);
    
}  /* ends production_system */
    
/*********************************/
/*********************************/
    
int read_a_rule(int rule_number,
                char *answer)
{
char *there,
     rule[L];
FILE *rule_file;
int  i      = 1,
     result = 1;
    
rule_file = fopen(RULES_FILE, "rt");
if(rule_file == NULL)   
   printf("\nERROR Could not open file %s",
          RULES_FILE);
    
while(i <= rule_number){
   if(fgets(rule, L, rule_file) == NULL){
     i = rule_number * 100;
     result = 0;
   }
    
      /* did we read a rule or a comment or
         a blank line? No COMMENT and IF
         means we hit a rule */
   there = strstr(rule, "COMMENT");
   if(there != NULL){
   }
   else{  /*  no COMMENT */
      there = strstr(rule, "IF");
      if(there != NULL){
         i++;
      }  /* ends if there */
   }  /* ends else no COMMENT */
    
}  /* ends while */
    
fclose(rule_file);
    
strcpy(answer, rule);
return(result);
    
}  /* ends read_a_rule */
    
/*********************************/
/*********************************/
    
int is_a_hit(char *context, 
            char *rule)
{
int a            = 0,
    b            = 0,
    hit          = 0,
    logical_case = 6;
    
char *and_there,
     *and_not_there,
     *not_there,
     *or_there,
     *or_not_there,
     *there,
     *there1,
     *there2,
     *there3,
     word[L],
     word1[L],
     word2[L],
     word3[L];
    
    
and_there     = strstr(rule, " AND "); 
and_not_there = strstr(rule, "AND_NOT"); 
not_there     = strstr(rule, " NOT "); 
or_there      = strstr(rule, " OR "); 
or_not_there  = strstr(rule, "OR_NOT");
    
    
if( (and_there     != NULL)  &&
    (and_not_there == NULL))
     logical_case = 1;
    
if( (and_there     == NULL)  &&
    (and_not_there != NULL))
     logical_case = 2;
    
if( (and_there     != NULL)  &&
    (and_not_there != NULL))
     logical_case = 7;
    
    
if(not_there != NULL)
   logical_case = 3;
    
    
if( (or_there     != NULL)  &&
    (or_not_there == NULL))
     logical_case = 4;
    
if( (or_there     == NULL)  &&
    (or_not_there != NULL))
     logical_case = 5;
    
if( (or_there     != NULL)  &&
    (or_not_there != NULL))
     logical_case = 8;
    
switch(logical_case){
    
 case 1:  /* AND  */
          /* 1a IF a AND b THEN z */
          /* 1b IF a AND b AND c THEN z */
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word1, &a);
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word2, &a);
    b = get_next_word(rule, word, &a);
    
       /* case 1a */
    if(strcmp(word, "AND") != 0){ 
      there1 = strstr(context, word1);
      there2 = strstr(context, word2);
      if((there1 != NULL)  &&
         (there2 != NULL))
            hit = 1;
    }  /* ends if case 1a */
    
       /* case 1b */
    else{
     b      = get_next_word(rule, 
                              word3, 
                              &a);
     there1 = strstr(context, word1);
     there2 = strstr(context, word2);
     there3 = strstr(context, word3);
     if((there1 != NULL)  &&
        (there2 != NULL)  &&
        (there3 != NULL))
            hit = 1;
    }  /* ends else case 1b */
 break;
    
 case 2:  
    /* AND_NOT IF a AND_NOT b THEN z */
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word1, &a);
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word2, &a);
    there1 = strstr(context, word1);
    there2 = strstr(context, word2);
    if((there1 != NULL)  &&
       (there2 == NULL))
         hit = 1;
 break;
    
 case 3:  /* NOT  IF NOT a THEN b */
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word, &a);
    there = strstr(context, word);
    if(there == NULL) hit = 1;
 break;
    
 case 4:
   /* OR  IF a OR b THEN z */
   /* 4a IF a OR b THEN z */
   /* 4b IF a OR b OR c THEN z */
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word1, &a);
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word2, &a);
    b = get_next_word(rule, word, &a);
    
       /* case 4a */
    if(strcmp(word, "AND") != 0){ 
       there1 = strstr(context, word1);
       there2 = strstr(context, word2);
       if((there1 != NULL)  ||
          (there2 != NULL))
            hit = 1;
    }  /* ends if case 4a */
    
       /* case 4b */
    else{
       b = get_next_word(rule, word3, &a);
       there1 = strstr(context, word1);
       there2 = strstr(context, word2);
       there3 = strstr(context, word3);
       if((there1 != NULL)  ||
          (there2 != NULL)  ||
          (there3 != NULL))
            hit = 1;
    }  /* ends else case 4b */
 break;
    
 case 5:  
   /* OR_NOT  IF a OR_NOT b THEN z */
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word1, &a);
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word2, &a);
    there1 = strstr(context, word1);
    there2 = strstr(context, word2);
    if((there1 != NULL)  ||
       (there2 == NULL))
         hit = 1;
 break;
    
 case 6: /* simplest, IF x THEN y */
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word, &a);
    there = strstr(context, word);
    if(there != NULL) hit = 1;
 break;
    
 case 7:  
    /* complex AND_NOT  */
    /* IF a AND b AND_NOT c THEN z */
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word1, &a);
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word2, &a);
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word3, &a);
    there1 = strstr(context, word1);
    there2 = strstr(context, word2);
    there3 = strstr(context, word3);
    if((there1 != NULL)  &&
       (there2 != NULL)  &&
       (there3 == NULL))
         hit = 1;
 break;
    
 case 8:  
    /* complex OR_NOT  */
    /* IF a OR b OR_NOT c THEN z */
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word1, &a);
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word2, &a);
    b = get_next_word(rule, word, &a);
    b = get_next_word(rule, word3, &a);
    there1 = strstr(context, word1);
    there2 = strstr(context, word2);
    there3 = strstr(context, word3);
    if((there1 != NULL)  ||
       (there2 != NULL)  ||
       (there3 == NULL))
         hit = 1;
 break;
    
 default:
  printf("\ndefault fall through");
 break;
    
}  /* ends switch logical_case */
    
    
return(hit);
    
}  /* ends is_a_hit */
    
/*********************************/
/*********************************/
/*
  this returns 1 if hits end of line 0 if not
*/
    
    
int get_next_word(char *line,
                  char *next_word, int *place)
{
int i        = 0,
    j        = 0,
    not_done = 1,
    result   = 0;
    
next_word[0] = '\0';
    
i = *place;
    
while(not_done){
   if(line[i] == ' '){
      if(j == 0) i++;
      else
         not_done = 0;
   }
    
   if(line[i] == '\n'){
      not_done = 0;
      result   = 1;
   }
    
   if(not_done)
      next_word[j++] = line[i++];
    
}   /* ends while not_done */
    
next_word[j] = '\0';
*place       = i;
    
return(result);
}  /* ends get_next_word */
    
/*********************************/
/*********************************/
    
int is_a_duplicate(char *context, char *rule)
    
/*
  if the result of the action in the rule
  is already in the context, return a 1
  else return a 0 
*/
    
{
char *there,
     word[L];
int a        = 0,
    b        = 0,
    not_done = 1,
    result   = 0;
    
while(not_done){
 b = get_next_word(rule, word, &a);
 if(strcmp(word, "THEN") == 0){
   b = get_next_word(rule, word, &a);
    not_done = 0;
 }  /* ends if */
}  /* ends while not_done */
    
there = strstr(context, word);
if(there != NULL)
   result = 1;
    
return(result);
    
}  /* ends is_a_duplicate */
    
/*********************************/
/*********************************/
    
int fire_rule(char *context, 
             int number)
{
char rule[L],
     temp[L],
     word[L];
int  a        = 0,
     b        = 0,
     not_done = 1;
    
a = read_a_rule(number, rule);
    
while(not_done){
 b = get_next_word(rule, word, &a);
 if(strcmp(word, "THEN") == 0){
  b = get_next_word(rule, word, &a);
  not_done = 0;
 }  /* ends if */
}  /* ends while not_done */
    
    
strcpy(temp, " ");
strcpy(temp, word);
strcat(temp, " ");
strcat(temp, context);
strcpy(context, temp);
    
return(a);
    
}  /* ends fire_rule */
    
/*********************************/
/*********************************/
    
int lowest_number(int *list)
{
int i      = 0,
    lowest = LIMIT;
    
for(i=0; i<L; i++){
   if(list[i] < lowest)
      lowest = list[i];
}
    
return(lowest);
}  /* ends lowest_number */
    
/* End of File */