                         /* matchnum.c, 28 May 11 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "global.h"
#include "utils.h"
#include "errors.h"
#include "isprop.h"
#include "fltval.h"
#include "levkeydist.h"
#include "printnum.h"
#include "hashtab.h"
#include "usage.h"
#include "arccomp.h"
#include "needs.h"
#include "singlefile.h"
#include "matchnum.h"


BOOL found_match;
BOOL do_print_match = TRUE;
BOOL do_print_value = TRUE;
BOOL do_print_word = FALSE;
BOOL match_mantissa = FALSE;
BOOL match_value = TRUE;
int min_levkey_dist = 0;   // Minimum keyboard levenstein distance
int num_simp_digits;
DIGIT_CHAR simp_digit_seq[MAX_NUM_DIGITS];


void save_simp_digit(DIGIT_CHAR ch)
{
// Don't save any leading zeroes or a decimal point
if ((num_simp_digits == 0) && is_zero(ch)) // don't save leading zeroes
   return;

// printf("%c[%d]<%d>", ch, ch, is_dec_point(ch));

if (is_dec_point(ch))
   return;
if (num_simp_digits < MAX_NUM_DIGITS)
   {
   simp_digit_seq[num_simp_digits]=ch;
   num_simp_digits++;
   }
}


void simplify_match_num(DIGIT_CHAR *some_num,
                        int len_some_num)
{
// 'simplify' a number by removing leading/trailing zeroes
int dig_num;

num_simp_digits=0;

for (dig_num=0; dig_num < len_some_num; dig_num++)
   save_simp_digit(some_num[dig_num]);

// Remove any trailing zeroes.
for (dig_num=num_simp_digits; dig_num > 0; dig_num--)
   if (is_zero(simp_digit_seq[dig_num-1]))
      num_simp_digits--;
   else
      break;
}


BOOL save_match(enum match_enum match_kind,
		struct num_db_rec *spec_num_ptr,
                fp_t seen_val,
		DIGIT_CHAR *mantissa,
                int len_mantissa,
                DIGIT_CHAR *exponent)
{
// If a summary was requested save information about a match
if (!(((match_kind == NO_MATCH) && do_summary_no_match) ||
      ((match_kind != NO_MATCH) && do_summary_match) ||
      ((match_kind == NDB_MATCH) && do_mk_ndb)))
   return FALSE;

if (cnt_seen_num(match_kind, spec_num_ptr, seen_val,
				mantissa, len_mantissa, exponent))
   return TRUE;

return FALSE;
}


void handle_match(enum match_enum match_kind,
		  struct num_db_rec *spec_num_ptr,
                  fp_t seen_val,
		  DIGIT_CHAR *mantissa,
                  int len_mantissa,
                  DIGIT_CHAR *exponent)
{
// Found a match, now figure out what actions to take.

// print_match(match_kind, spec_num_ptr, mantissa, len_mantissa, exponent);
if ((spec_num_ptr == NULL) || (spec_num_ptr->need_info == NULL))
   {
   print_match(match_kind, spec_num_ptr, seen_val, mantissa, len_mantissa, exponent);
   (void)save_match(match_kind, spec_num_ptr,
				seen_val, mantissa, len_mantissa, "");
   }
else
   handle_need_match(match_kind, spec_num_ptr, mantissa, len_mantissa, exponent);
}


void match_dp_mantissa(struct num_db_rec *spec_num_ptr,
		       DIGIT_CHAR * exponent)
{
// See if a floating-point literal's mantissa matches
// i.e., ignore any exponent.
int least_signif; // number of digits in the two mantissa

if (num_simp_digits < spec_num_ptr->simp_mant_len)
   least_signif=num_simp_digits;
else
   least_signif=spec_num_ptr->simp_mant_len;

if (least_signif < match_signif_digits)
   return;

// printf("%d %d %d\n", num_simp_digits, spec_num_ptr->simp_mant_len, min_signif);
// printf("%s : %s\n", spec_num_ptr->simp_mant, simp_digit_seq);
if (memcmp(spec_num_ptr->simp_mant, simp_digit_seq, least_signif) == 0)
   {
   found_match=TRUE;
   handle_match(EXACT_SIGNIF, spec_num_ptr,
				cur_fp_val, simp_digit_seq, num_simp_digits, exponent);
   }
else if ((min_levkey_dist > 0) &&
         (levkey_dist(spec_num_ptr->simp_mant, simp_digit_seq, least_signif) <=
								min_levkey_dist))
   {
// printf("levkey dist %d\n",  levkey_dist(spec_num_ptr->simp_mant, simp_digit_seq, least_signif));
   found_match=TRUE;
   handle_match(LEV_SIGNIF, spec_num_ptr,
			cur_fp_val, simp_digit_seq, num_simp_digits, exponent);
   }
}


void match_fp_val(struct num_db_rec *spec_num_ptr,
		  DIGIT_CHAR * mantissa,
		  int len_mantissa,
		  DIGIT_CHAR * exponent)
{
// fp_print(cur_fp_val); printf(" ");
// fp_print(spec_num_ptr->num_valu); printf("\n");

if (fp_almost_eq(cur_fp_val, spec_num_ptr->num_valu, spec_num_ptr->match_fuzz))
   {
   found_match=TRUE;
   handle_match(VALUE_MATCH, spec_num_ptr,
			     cur_fp_val, mantissa, len_mantissa, exponent);
   }
}


void match_dp_number(DIGIT_CHAR * mantissa,
		     int len_mantissa,
		     DIGIT_CHAR * exponent)
{
struct num_db_rec *spec_num_ptr=special_numbers.num_info[simp_digit_seq[0] - '0'];
BOOL always_try_match = (num_simp_digits >= match_signif_digits);

found_match=FALSE;

if (spec_num_ptr == NULL)
   return;

// Loop over all ndb values having the same first digit.
while (spec_num_ptr)
   {
// Attempt a match if the literal contains more significant digits than
//    o digits in ndb value
//    o match_signif_digits
// but don't attempt a match if literal contains
//    o 'many' more digits than ndb value (assumption is
//      that ndb value will almost be the 'best' known value).
//    o more than MAX_NUM_DIGITS digits
   if (((num_simp_digits >= spec_num_ptr->simp_mant_len) ||
        always_try_match) &&
       ((num_simp_digits <= 3+spec_num_ptr->simp_mant_len) ||
        (num_simp_digits > MAX_NUM_DIGITS)))
      {
      if (match_value)
         match_fp_val(spec_num_ptr, mantissa, len_mantissa, exponent);

      if ((!found_match) && match_mantissa)
         match_dp_mantissa(spec_num_ptr, exponent);
      }
   spec_num_ptr=spec_num_ptr->next;
   }
}


void match_number(DIGIT_CHAR * mantissa,
                  int len_mantissa,
		  DIGIT_CHAR * exponent)
{
simplify_match_num(mantissa, len_mantissa);
if (has_dp && (num_simp_digits > 0))
   {
   if (do_usage_value)
      cnt_val_usage(mantissa, len_mantissa, exponent);
   match_dp_number(mantissa, len_mantissa, exponent);
   if (!found_match)
      need_match_fail(mantissa, len_mantissa, exponent);
   if (!found_match)
      {
//print_number(mantissa, len_mantissa, exponent);
//printf(" unmatched\n");
      (void)save_match(NO_MATCH, NULL,
			cur_fp_val, mantissa, len_mantissa, exponent);
      }
   }
}


void init_match(void)
{
}

