/* @(#)interpret.c	1.6  2/10/93 */
/*******************************************************************************

This code was written and designed by 
Andrew Gene HALL of I.N. Services Pty. Ltd., Scarborough WA, Australia,
for the 
University of Western Australia, Crawley WA, Australia.

*******************************************************************************/

#include "diagmesg.h"
#include "sf_space.h"
#include "request_space.h"
#include "utilitys.h"
#include "sf_search.h"
#include "operators.h"
#include "expand.h"

/* Local Types */
typedef
enum {  unknown_, true_, false_ }
Conditional_Value;

typedef
struct {
   Block_Seq            *BS;
   Block_Seq            *complement;
   Conditional_Value    value;
}
Conditional_Result;


/* functions */

Conditional_Result	requests_froma_CR(
Conditional_Request	*condition,
Block_Seq		*search_domain)
{
Conditional_Result	rtn_cond;

   rtn_cond.BS = NULL;
   rtn_cond.complement = NULL;
   rtn_cond.value = unknown_;
   if( condition )
      switch( condition->tag ) {
      case RE_STRING:

           if( (rtn_cond.BS = names_in_Block_Seq( condition->cond.re_string, 
                                         search_domain, matches_re)) ) {
              rtn_cond.value = true_;
           } else {
              /* nothing found */
           }
           break;

      case UNARY_FN:
           switch( condition->cond.unary_fn.function ) {
           case COMPLEMENT: {
                Block_Seq	*universal = NULL;

                rtn_cond = requests_froma_CR( condition->cond.unary_fn.right, search_domain);
                universal = replicate_BS( search_domain );
                rtn_cond.complement = intersection_BS( universal, rtn_cond.BS, 
                                                       &(rtn_cond.BS) );
                if( rtn_cond.BS )
                   rtn_cond.value = true_;
                else
                   switch( rtn_cond.value ) {
                   case true_:
                        rtn_cond.value = false_;
                        break;

                   case false_:;
                   case unknown_:;
                   }
                } break;

           case ASSUME_TRUE:
                rtn_cond = requests_froma_CR( condition->cond.unary_fn.right, search_domain);
                if( rtn_cond.value == unknown_ )
                   rtn_cond.value = true_;
                break;

           default:
                ERROR_MSG("requests_froma_CR(): Unknown unary function.");
           }
           break;

      case COMPARISON_FN: {
           Boolean	(*fn)( Data_Item *, Data_Item *);
           Block_Seq            *tmp_BS;

           switch( condition->cond.comparison_fn.function ) {
           case EQUAL_STRINGS: 
                fn = equal_strings;
                break;

           case NOT_EQUAL_STRINGS: 
                fn = not_equal_strings;
                break;

           case SUB_STRING: 
                fn = sub_string;
                break;

           case NOT_SUB_STRING: 
                fn = not_sub_string;
                break;

           case ASCII_LESS: 
                fn = ascii_less;
                break;

           case ASCII_LESS_OR_EQUAL: 
                fn = ascii_less_or_equal;
                break;

           case ASCII_GREATER: 
                fn = ascii_greater;
                break;

           case ASCII_GREATER_OR_EQUAL: 
                fn = ascii_greater_or_equal;
                break;

           case REAL_EQUAL: 
                fn = real_equal;
                break;

           case REAL_NOT_EQUAL: 
                fn = real_not_equal;
                break;

           case REAL_LESS: 
                fn = real_less;
                break;

           case REAL_LESS_OR_EQUAL: 
                fn = real_less_or_equal;
                break;

           case REAL_GREATER: 
                fn = real_greater;
                break;

           case REAL_GREATER_OR_EQUAL: 
                fn = real_greater_or_equal;
                break;

           default:
                ERROR_MSG("requests_froma_CR(): Unknown comparison function.");
           }
           rtn_cond = requests_froma_CR( condition->cond.comparison_fn.left, search_domain);
           tmp_BS = rtn_cond.BS;
           rtn_cond.BS = apply_fn_over_BS( &tmp_BS, condition->cond.comparison_fn.right, fn);
           rtn_cond.complement = tmp_BS;
           if( rtn_cond.BS )
              rtn_cond.value = true_;
           else
              if( rtn_cond.value != unknown_ )
                 rtn_cond.value = false_;
           } break;

      case BINARY_FN: {
           Conditional_Result	left_cond, right_cond;
           Block_Seq	*complement;

           /* process the left and right branches */
           left_cond = requests_froma_CR( condition->cond.binary_fn.left,
                                          search_domain);
           right_cond = requests_froma_CR( condition->cond.binary_fn.right,
                                           search_domain);

           switch( condition->cond.binary_fn.function ) {
           case INTERSECTION:
                /* find the intersection */
                rtn_cond.BS = intersection_BS( left_cond.BS, right_cond.BS,
                                               &complement );
                rtn_cond.complement = complement;

                /* determine the value of operation */
                if( rtn_cond.BS )
                   rtn_cond.value = true_;
                else
                   switch( left_cond.value ) {
                   case true_:
                        switch( right_cond.value ) {
                        case true_:
                        case false_:
                             rtn_cond.value = false_;
                             break;
                        case unknown_:
                             rtn_cond.value = unknown_;
                             break;
                        default:
                             ERROR_MSG("requests_froma_CR(): Unknown condition value.");
                        }
                        break;

                   case false_:
                        switch( right_cond.value ) {
                        case true_:
                        case false_:
                        case unknown_:
                             rtn_cond.value = false_;
                             break;
                        default:
                             ERROR_MSG("requests_froma_CR(): Unknown condition value.");
                        }
                        break;
                   case unknown_:
                        switch( right_cond.value ) {
                        case true_:
                             rtn_cond.value = unknown_;
                             break;
                        case false_:
                             rtn_cond.value = false_;
                             break;
                        case unknown_:
                             rtn_cond.value = unknown_;
                             break;
                        default:
                             ERROR_MSG("requests_froma_CR(): Unknown condition value.");
                        }
                        break;
                   default:
                        ERROR_MSG("requests_froma_CR(): Unknown condition value.");
                   }
                break;

           case UNION:
                /* find the union */
                rtn_cond.BS = union_BS( left_cond.BS, right_cond.BS);
                rtn_cond.complement = NULL;

                /* determine the value of operation */
                if( rtn_cond.BS )
                   rtn_cond.value = true_;
                else
                   switch( left_cond.value ) {
                   case true_:
                        /* this shouldn't be possible */
                        ERROR_MSG("requests_froma_CR(): Error in logic of Union.");
                        rtn_cond.value = unknown_;
                        break;

                   case false_:
                        switch( right_cond.value ) {
                        case true_:
                             /* this shouldn't be possible */
                             ERROR_MSG("requests_froma_CR(): Error in logic of Union.");
                             rtn_cond.value = unknown_;
                             break;
                        case false_:
                        case unknown_:
                             rtn_cond.value = false_;
                             break;
                        default:
                             ERROR_MSG("requests_froma_CR(): Unknown condition value.");
                        }
                        break;
                   case unknown_:
                        switch( right_cond.value ) {
                        case true_:
                             /* this shouldn't be possible */
                             ERROR_MSG("requests_froma_CR(): Error in logic of Union.");
                             rtn_cond.value = unknown_;
                             break;
                        case false_:
                             rtn_cond.value = false_;
                             break;
                        case unknown_:
                             rtn_cond.value = unknown_;
                             break;
                        default:
                             ERROR_MSG("requests_froma_CR(): Unknown condition value.");
                        }
                        break;
                   default:
                        ERROR_MSG("requests_froma_CR(): Unknown condition value.");
                   }
                break;

           default:
                ERROR_MSG("requests_froma_CR(): Unknown binary function.");
           }
           } break;

      default:
           ERROR_MSG("requests_froma_CR(): Unknown domain for condition.");
      }
   else
      DEBUG_MSG("requests_froma_CR(): NULL condition.");
   return( rtn_cond );
} /* requests_froma_CR */

Block_Seq	*requests_froma_RS(
Request_Seq	*reqs,
Block_Seq	*search_domain,	   /* the domain from which searches are done */
Block_Seq	*condition_domain, /* result of the parental condition, 
                                      used for scope changing */
Block_Seq	*original_domain)  /* the original file */
{
Block_Seq       *rtn_BS = NULL;
Block_Seq       *tmp_BS = NULL;
Conditional_Result	cond;

   while( reqs ) {
      if( reqs->req ) {
         switch( reqs->req->tag ) {
         case CONDITIONAL :
              if( reqs->req->request.conditional ) {
                 cond = requests_froma_CR( reqs->req->request.conditional, search_domain );
                 tmp_BS = cond.BS;
              }
              else {
                 DEBUG_MSG("requests_froma_RS(): NULL conditional.");
                 tmp_BS = NULL;
              }
              break;

         case BRANCHING :
              if( reqs->req->request.branching ) {
                 cond = requests_froma_CR( 
                                        reqs->req->request.branching->condition,
                                        search_domain );
                 switch( cond.value ) {
                 case true_ :
                      tmp_BS = requests_froma_RS( 
                                      reqs->req->request.branching->true_branch,
                                      search_domain, cond.BS, original_domain);
                      break;

                 case false_ :
                      tmp_BS = requests_froma_RS( 
                                     reqs->req->request.branching->false_branch,
                                     search_domain, original_domain, 
                                                    original_domain);
                      break;

                 case unknown_ :
                      if(  reqs->req->request.branching->unknown_branch )
                         tmp_BS = requests_froma_RS( 
                                   reqs->req->request.branching->unknown_branch,
                                   search_domain, original_domain, 
                                                  original_domain);
                      else
                         tmp_BS = requests_froma_RS( 
                                     reqs->req->request.branching->false_branch,
                                     search_domain, cond.BS, original_domain);
                      break;

                 default:
                      ERROR_MSG("requests_froma_RS(): Unknown state after a condition.");
                      tmp_BS = NULL;
                 }
              }
              else {
                 DEBUG_MSG("requests_froma_RS(): NULL branching.");
                 tmp_BS = NULL;
              }
              break;

         case SCOPE :
              if( reqs->req->request.scope ) {
                 register Block_Seq	*tmp_search = NULL;

                 switch( reqs->req->request.scope->scope ) {
                 case SCOPE_DATA_ITEM:
                      tmp_BS = requests_froma_RS(reqs->req->request.scope->reqs,
                                                 condition_domain,
                                                 condition_domain,
                                                 original_domain);
                      break;

                 case SCOPE_LOOP_PACKET:
                      tmp_search = expand_loop_packets( condition_domain,
                                                    original_domain);
                      tmp_BS = requests_froma_RS(reqs->req->request.scope->reqs,
                                                 tmp_search,
                                                 condition_domain,
                                                 original_domain);
                      free_Block_Seq( tmp_search );
                      break;

                 case SCOPE_LOOP_STRUCTURE:
                      tmp_search = expand_loop_structures( condition_domain,
                                                       original_domain);
                      tmp_BS = requests_froma_RS(reqs->req->request.scope->reqs,
                                                 tmp_search,
                                                 condition_domain,
                                                 original_domain);
                      free_Block_Seq( tmp_search );
                      break;

                 case SCOPE_SAVE_FRAME:
                      tmp_search = expand_save_frames( condition_domain,
                                                   original_domain);
                      tmp_BS = requests_froma_RS(reqs->req->request.scope->reqs,
                                                 tmp_search,
                                                 condition_domain,
                                                 original_domain);
                      free_Block_Seq( tmp_search );
                      break;

                 case SCOPE_DATA_BLOCK:
                      tmp_search = expand_data_blocks( condition_domain,
                                                   original_domain);
                      tmp_BS = requests_froma_RS(reqs->req->request.scope->reqs,
                                                 tmp_search,
                                                 condition_domain,
                                                 original_domain);
                      free_Block_Seq( tmp_search );
                      break;

                 case SCOPE_FILE:
                      tmp_BS = requests_froma_RS(reqs->req->request.scope->reqs,
                                                 original_domain,
                                                 condition_domain,
                                                 original_domain);
                      break;

                 default:
                     ERROR_MSG("requests_froma_RS(): Unknown scope.");
                     tmp_BS = NULL;
                 }
              } else {
                 DEBUG_MSG("requests_froma_RS(): NULL scope.");
                 tmp_BS = NULL;
              }
              break;

         default:
              ERROR_MSG("requests_froma_RS(): Unknown Domain in Sequence.");
              tmp_BS = NULL;
         }
         if( rtn_BS )
            /* merge the existing requested data with the data just requested */
            rtn_BS = union_BS( rtn_BS, tmp_BS);
         else
            rtn_BS = tmp_BS;
      }
      else
         DEBUG_MSG("requests_froma_RS(): NULL request.");
      reqs = reqs->next;
   }
   return( rtn_BS );
} /* requests_froma_RS */
