                       /* printnum.c, 28 May 11 */

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

#include "global.h"
#include "fltval.h"
#include "hashtab.h"
#include "../hash/hashtable_itr.h"
#include "matchnum.h"
#include "arccomp.h"
#include "needs.h"
#include "singlefile.h"
#include "words.h"
#include "printnum.h"

BOOL do_print_all,
     do_print_no_match,
     do_summary_match = TRUE,
     do_summary_no_match;


void print_progress(void)
{
if (do_trace_progress && !have_printed_filename)
   {
   if (started_arccomp_file)
      {
      printf("%s\n", cur_arccomp_name);
      started_arccomp_file=FALSE;
      }
   printf("%s\n", cur_filename);
   have_printed_filename=TRUE;
   }
}


void print_digit_seq(DIGIT_CHAR digit_seq[MAX_NUM_DIGITS],
                     int num_digits)
{
int c;

for (c=0; c < num_digits; c++)
   printf("%c", digit_seq[c]);
}


void print_number(DIGIT_CHAR mantissa[MAX_NUM_DIGITS],
                  int len_mantissa,
		  DIGIT_CHAR exponent[MAX_NUM_DIGITS])
{
print_digit_seq(mantissa, len_mantissa);
if (strlen(exponent) != 0)
   printf("e%s", exponent);
}


static void print_diff_plus_num(fp_t seen_num, fp_t ndb_num, BOOL align_numbers)
{
const int MAX_SEEN_LEN = 20;
size_t seen_len,
       ndb_len,
       min_len,
       nindex,
       dbindex,
       eindex;;
DIGIT_CHAR seen_str[MAX_NUM_DIGITS];
DIGIT_CHAR ndb_str[MAX_NUM_DIGITS];

fp_to_string(seen_str, seen_num, MAX_NUM_DIGITS-1);
fp_to_string(ndb_str, ndb_num, MAX_NUM_DIGITS-1);
seen_len=strlen(seen_str);
ndb_len=strlen(ndb_str);
if (seen_len < ndb_len)
   min_len=seen_len;
else
   min_len=ndb_len;

for (nindex=0; nindex < min_len; nindex++)
   if (seen_str[nindex] == ndb_str[nindex])
      printf(".");
   else
      break;

// seen_str mantissa is shorter than ndb_str,
// handle the case where the exponents are the same.
if ((nindex < min_len) && (seen_str[nindex] == 'e'))
   {
   eindex=nindex;
   for (dbindex=nindex; dbindex < ndb_len; dbindex++)
      if (ndb_str[dbindex] == 'e')
         break;
   if (dbindex < ndb_len)
      {
      for (; (nindex < seen_len) && (dbindex < ndb_len); nindex++, dbindex++)
	 if (seen_str[nindex] != ndb_str[dbindex])
	    break;
      if ((nindex < seen_len) || (dbindex < ndb_len))
	 nindex=eindex; // reset original value so following outer loop iterates
      else
	 {
	 printf("|"); // indicate that there were more digits in ndb value
	 for (; eindex < seen_len-1; eindex++) // Exponent matches
            printf(".");
	 }
      }
   }
for (; nindex < seen_len; nindex++)
   printf("%c", seen_str[nindex]);

if (align_numbers)
   for (nindex=seen_len; nindex < MAX_SEEN_LEN; nindex++)
      printf(" ");

printf("  ");

for (nindex=0; nindex < ndb_len; nindex++)
   printf("%c", ndb_str[nindex]);
}


void print_match(enum match_enum match_kind,
                 struct num_db_rec *num_ptr,
                 fp_t seen_val,
                 DIGIT_CHAR *match_num,
                 int signif_dig,
                 DIGIT_CHAR *exponent)
{
// Print information about a match that was found
DIGIT_CHAR output_num[MAX_NUM_DIGITS];

if (!do_print_match)
   return;

memcpy(output_num, match_num, signif_dig);
if (signif_dig == MAX_NUM_DIGITS)
   signif_dig--;
output_num[signif_dig]=NULL_CHAR;

print_progress();
if (do_print_location)
   printf("%5d ", line_count);
if (do_print_value)
   {
   if ((match_kind == NEED_MATCH) || (match_kind == EXACT_SIGNIF) ||
       (match_kind == LEV_SIGNIF))
      print_number(match_num, signif_dig, exponent);
   else
      print_diff_plus_num(seen_val, num_ptr->num_valu, FALSE);
   printf("   ");
   }

switch (match_kind)
   {
   case NEED_MATCH: if (num_ptr->need_info->num_mantissa_matches > 0)
		       printf("Includes mantissa only matches: ");
		    printf(num_ptr->need_info->msg, output_num, signif_dig);
		    break;

   case EXACT_SIGNIF: printf("Mantissa match: ");
		      fp_print(seen_val);
//		    print_number(match_num, signif_dig, exponent);
		      printf("  ");
		      print_number(num_ptr->mantissa, num_ptr->len_mantissa,
							     num_ptr->exponent);
		      printf("  ");
		      printf(num_ptr->msg, output_num, signif_dig);
		      break;

   case LEV_SIGNIF: printf("Close mantissa match: ");
		    fp_print(seen_val);
//		    print_number(match_num, signif_dig, exponent);
		    printf("  ");
		    print_number(num_ptr->mantissa, num_ptr->len_mantissa,
							 num_ptr->exponent);
		    printf("  ");
		    printf(num_ptr->msg, output_num, signif_dig);
		    break;

   default: printf(num_ptr->msg, output_num, signif_dig);
	    break;
   }
if (do_print_word)
   print_word_buf();
}


void print_partial_need_match(struct need_num_rec *need_num_ptr,
			      int total_match_needs,
			      int total_needs)
{
if (!do_print_match)
   return;

print_progress();
if (do_print_location)
   printf("%5d ", line_count);
printf("Partial need match (%d out of %d): %s",
			total_match_needs, total_needs, need_num_ptr->msg);
}


void print_suspect_need_match(struct need_num_rec *need_num_ptr,
			      int total_match_needs,
			      int total_needs)
{
if (!do_print_match)
   return;

print_progress();
if (do_print_location)
   printf("%5d ", line_count);
printf("Suspicious partial need match (%d out of %d): %s",
			total_match_needs, total_needs, need_num_ptr->msg);
}


static void print_need_summary(void)
{
struct seen_need_rec *temp_need_list = all_seen_need_list;

while (temp_need_list != NULL)
   {
   printf("%6d ", temp_need_list->total_seen);
   printf("value sequence ");
   printf("  %s", temp_need_list->need_ptr->msg);
   temp_need_list=temp_need_list->next;
   }
}


void print_summary(void)
{
if (do_summary_match)
   {
   struct num_seen_rec *matched_num_ptr = matched_num_list;
   printf("Matched summary\n");
   print_need_summary();

   while (matched_num_ptr)
      {
      //  Set to zero after printing information
      if (matched_num_ptr->total_occurrences != 0)
	 {
	 struct num_seen_rec *temp_matched_ptr = matched_num_ptr;
	 struct num_db_rec *cur_num_db = matched_num_ptr->matched_num;
	 // Look for all matches against this ndb value
	 while (temp_matched_ptr)
	    {
	    if (temp_matched_ptr->matched_num != cur_num_db)
	       {
	       temp_matched_ptr=temp_matched_ptr->next;
	       continue;
	       }
	    printf("%4d ", temp_matched_ptr->total_occurrences);
            if (enum_eq(temp_matched_ptr->match_kind, VALUE_MATCH))
	       {
	       print_diff_plus_num(temp_matched_ptr->seen_valu,
		                   temp_matched_ptr->matched_num->num_valu, TRUE);
	       }
            else
	    if (enum_eq(temp_matched_ptr->match_kind, LEV_SIGNIF) ||
                enum_eq(temp_matched_ptr->match_kind, EXACT_SIGNIF))
	       {
               print_digit_seq(temp_matched_ptr->mantissa,
					   temp_matched_ptr->len_mantissa);
	       printf("  ");
	       fp_print(temp_matched_ptr->matched_num->num_valu);
	       }
	    printf("  %s", temp_matched_ptr->matched_num->msg);
	    temp_matched_ptr->total_occurrences=0;
	    temp_matched_ptr=temp_matched_ptr->next;
	    }
	 }
      matched_num_ptr=matched_num_ptr->next;
      }
   }

if (do_summary_no_match)
   {
   struct num_seen_keys *key;
   struct hashtable_itr *itr;
   struct num_seen_rec *seen_num_ptr;

   printf("Unmatched number summary\n");

   // Iterator only returns a valid iterator if the hashtable is not empty
   itr = hashtable_iterator(saved_htable);
   if (hashtable_count(saved_htable) > 0)
      {
      do
	 {
         key = hashtable_iterator_key(itr);
         seen_num_ptr = hashtable_iterator_value(itr);
         if ((seen_num_ptr->file_occurrences != 0) &&
	     enum_eq(seen_num_ptr->match_kind, NO_MATCH))
	    {
	    printf("%4d ", seen_num_ptr->file_occurrences);
            print_digit_seq(seen_num_ptr->mantissa,
					      seen_num_ptr->len_mantissa);
	    if (strlen(seen_num_ptr->exponent) == 0)
	       printf("\n");
	    else
	       printf("e%s\n", seen_num_ptr->exponent);
	    }
         }
      while (hashtable_iterator_advance(itr));
      }
   }
}

