                          /* needs.c, 20 May 11 */

#include <stdio.h>
#include <stdlib.h>
 
#include "global.h"
#include "errors.h"
#include "isprop.h"
#include "utils.h"
#include "fltval.h"
#include "hashtab.h"
#include "printnum.h"
#include "matchnum.h"
#include "singlefile.h"
#include "needs.h"


int percent_need_match = 100,
    sus_min_need_match = 5,
    max_fails_need_match = 10;
struct seen_need_rec *all_seen_need_list; // List of matched need sequences

static int fails_since_need_match;

static fp_t dummy_fp_val;

// List of partially matched need sequences
static struct seen_need_rec *working_need_list;


void print_need_no_match(struct num_db_rec *num_ptr)
{
if (do_print_no_match)
   {
   print_progress();
   print_number(num_ptr->mantissa, num_ptr->len_mantissa, num_ptr->exponent);
   printf("  partial need match\n");
   }
}


void not_need_value(struct num_db_rec *need_num_ptr)
{
struct num_seen_rec *val_ptr;

return;

// TODO
// The following will only work if the literal seen is exactly the same
// as the literal in the ndb, an unlikely possibility.

val_ptr = get_saved_info(need_num_ptr,
			 need_num_ptr->mantissa, need_num_ptr->len_mantissa,
			 need_num_ptr->exponent,
			 NULL);

if ((val_ptr != NULL) && ((val_ptr->match_kind == 0) ||
			  enum_eq(val_ptr->match_kind, NO_MATCH)))
   {
   (void)save_match(NO_MATCH, NULL, need_num_ptr->num_valu,
			 need_num_ptr->mantissa, need_num_ptr->len_mantissa,
			 need_num_ptr->exponent);
   print_need_no_match(need_num_ptr);
   }
}


static void save_need_match(struct need_num_rec *need_ptr)
{
/*
 * Increment the count of the number of times this need sequence
 * has matched.
 */
struct seen_need_rec *temp_need_list = working_need_list,
		     *prev_need_list = NULL;

need_ptr->num_mantissa_matches=0;
free(need_ptr->seen_need_num);
need_ptr->seen_need_num=NULL;

// Remove matched need sequence from working_need_list
while (temp_need_list != NULL)
   {
   if (need_ptr == temp_need_list->need_ptr)
      {
      if (temp_need_list == working_need_list)
	 working_need_list=working_need_list->next;
      else
	 prev_need_list->next=temp_need_list->next;
      free(temp_need_list);
      break;
      }
   prev_need_list=temp_need_list;
   temp_need_list=temp_need_list->next;
   }

// Add need sequence to count of matched sequences
temp_need_list=all_seen_need_list;
while (temp_need_list != NULL)
   {
   if (need_ptr == temp_need_list->need_ptr)
      {
      temp_need_list->total_seen++;
      return;
      }
   temp_need_list=temp_need_list->next;
   }

temp_need_list=get_heap(sizeof(struct seen_need_rec));
if (temp_need_list != NULL)
   {
   temp_need_list->total_seen=1;
   temp_need_list->need_ptr=need_ptr;
   temp_need_list->next=all_seen_need_list;
   all_seen_need_list=temp_need_list;
   }
}


static void start_init_match(struct need_num_rec *need_ptr)
{
/*
 * Initialization for handling a new matching need sequence.
 */
int snum;
struct seen_need_rec *temp_need_list = working_need_list;

need_ptr->seen_need_num=get_heap(sizeof(short)*need_ptr->list_len);
need_ptr->num_mantissa_matches=0;
for (snum=0; snum < need_ptr->list_len; snum++)
   need_ptr->seen_need_num[snum]=0;

while (temp_need_list != NULL)
   {
   if (need_ptr == temp_need_list->need_ptr)
      return;
   temp_need_list=temp_need_list->next;
   }

temp_need_list=get_heap(sizeof(struct seen_need_rec));
if (temp_need_list != NULL)
   {
   temp_need_list->need_ptr=need_ptr;
   temp_need_list->next=working_need_list;
   working_need_list=temp_need_list;
   }
}


void handle_need_match(enum match_enum match_kind,
		       struct num_db_rec *spec_num_ptr,
                       DIGIT_CHAR *mantissa,
                       int len_mantissa,
                       DIGIT_CHAR *exponent)
{
int snum,
    need_total;

// Is this the first time we have seen a value in this need sequence?
if (spec_num_ptr->need_info->seen_need_num == NULL)
   start_init_match(spec_num_ptr->need_info);

spec_num_ptr->need_info->seen_need_num[spec_num_ptr->need_num]++;
spec_num_ptr->need_info->num_mantissa_matches += (match_kind == LEV_SIGNIF) |
						 (match_kind == EXACT_SIGNIF);
// Have we seen each value at least once?
need_total=0;
for (snum=0; snum < spec_num_ptr->need_info->list_len; snum++)
   if (spec_num_ptr->need_info->seen_need_num[snum] != 0)
      need_total++;
if (need_total == spec_num_ptr->need_info->list_len)
   {
   // Report a !need match and reduce seen count for each number
   print_match(NEED_MATCH, spec_num_ptr, dummy_fp_val, mantissa, len_mantissa, exponent);
   save_need_match(spec_num_ptr->need_info);
   }
fails_since_need_match=0;
}


static void unmatched_need_num(struct num_db_rec *need_num_ptr)
{
}


static void clear_working_needs(void)
{
// End of line, existing need matches treated as non-matches.
// Report need values as unmatched.
struct seen_need_rec *walk_need_list = working_need_list,
		     *temp_need_list;
while (walk_need_list)
   {
   struct need_num_rec *need_num_ptr = walk_need_list->need_ptr;
   short need_num,
	 total_matched_needs=0;
   for (need_num=0; need_num < need_num_ptr->list_len; need_num++)
      total_matched_needs += (need_num_ptr->seen_need_num[need_num] > 0);
// printf("total matched %d, list len %d percent needed %d\n",
// 	total_matched_needs, need_num_ptr->list_len, percent_need_match);
   if (100*total_matched_needs/need_num_ptr->list_len >= percent_need_match)
      print_partial_need_match(need_num_ptr,
				  total_matched_needs, need_num_ptr->list_len);
   else if ((total_matched_needs >= sus_min_need_match) &&
	    (100*total_matched_needs/need_num_ptr->list_len >= 40))
      print_suspect_need_match(need_num_ptr,
				  total_matched_needs, need_num_ptr->list_len);
   need_num_ptr->num_mantissa_matches=0;
   for (need_num=0; need_num < need_num_ptr->list_len; need_num++)
      if (need_num_ptr->seen_need_num[need_num] > 0)
	 unmatched_need_num(need_num_ptr->num_list[need_num]);
   free(need_num_ptr->seen_need_num);
   need_num_ptr->seen_need_num=NULL;
   temp_need_list=walk_need_list;
   walk_need_list=walk_need_list->next;
   free(temp_need_list);
   } 
working_need_list=NULL;
}

void need_match_fail(DIGIT_CHAR * mantissa,
                     int len_mantissa,
                     DIGIT_CHAR * exponent)
{
if (working_need_list == NULL)
   return;
fails_since_need_match++;
if (fails_since_need_match >= max_fails_need_match)
   clear_working_needs();
}


void finish_needs(void)
{
clear_working_needs();
}


void init_needs(void)
{
fp_init(&dummy_fp_val);
}

