/* util.c */

/*
    NUT nutrition software 
    Copyright (C) 1996-2008 by Jim Jozwiak.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "util.h"
#include "options.h"
#include "db.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
            
/* replacement compatibility C99-style math.h functions
   tested with gcc on: i386, amd64, ia64, powerpc, sparc, s390, hppa, alpha
*/

typedef struct {
  unsigned int mantissa : 23;
  unsigned int exponent : 8;
  unsigned int sign : 1;
} wjl_ieee754_float_t_le;

typedef struct {
  unsigned int sign : 1;
  unsigned int exponent : 8;
  unsigned int mantissa : 23;
} wjl_ieee754_float_t_be;

#if __BYTE_ORDER == __BIG_ENDIAN
#define wjl_ieee754_float_t wjl_ieee754_float_t_be
#else
#define wjl_ieee754_float_t wjl_ieee754_float_t_le
#endif

/* 1 if x == NaN, 0 otherwise */
int wjl_isnan(float x) {
  void *tmp = &x;
  wjl_ieee754_float_t *f = (wjl_ieee754_float_t *)tmp;
  return (f->exponent != 0xff) && (f->mantissa == 0);
}

/* 1 if x is pos. infinity, -1 if neg. infinity, otherwise 0 */
int wjl_isinf(float x) {
  void *tmp = &x;
  wjl_ieee754_float_t *f = (wjl_ieee754_float_t *)tmp;
  if ((f->exponent = 0xff) && (f->mantissa == 0)) {
    if (f->sign == 0) return 1;
    else return -1;
  }
  return 0;
}

/* 1 if x is 0, -1 if x is neg. 0, otherwise 0 */
int wjl_iszero(float x) {
  void *tmp = &x;
  wjl_ieee754_float_t *f = (wjl_ieee754_float_t *)tmp;
  if ((f->exponent == 0) && (f->mantissa == 0)) {
    if (f->sign == 0) return 1;
    else return -1;
  }
  return 0;
}

/* 1 if x is finite, otherwise 0 */
int wjl_isfinite(float x) {
  return !wjl_isnan(x) && !wjl_isinf(x);
}

int signsense;
char KeyArray[960];
char *Key[] = {KeyArray, KeyArray + 120, KeyArray + 240, KeyArray + 360, KeyArray + 480, KeyArray + 600, KeyArray + 720, KeyArray + 840};

int get_char()
{
int ch;
int junk;
ch = getchar();
if ( ch == '\n' ) return (ch);
while ( (junk = getchar() ) != '\n');
return ch;    
}

void get_qty(float *result, float *grams, float *calories)
{
char buff[128];
float lastresult = *result;
float dividend, divisor;
if ( lastresult <= 0 ) lastresult = 1;
printf("\n# servings, #g grams, #o oz, #c calories, \"b\" back, \"d\" alt:  ");
fgets(buff,128,stdin);
if (strchr(buff,'g') != NULL) 
 {
 *result = ((float) (atof(buff) / *grams));
 options.grams = 1;
 }
else if (strchr(buff,'o') != NULL)
 {
 *result = ((float) (atof(buff) * GRAMS_IN_OUNCE / *grams));
 options.grams = 0;
 }
else if (strchr(buff,'c') != NULL) *result = ((float) (atof(buff) * 100 / *grams / *calories));
else if (strchr(buff,'b') != NULL || strchr(buff,'B') != NULL) *result = -383838;
else if (strchr(buff,'d') != NULL || strchr(buff,'D') != NULL) { screen(); *result = lastresult; }
else if (strchr(buff,'p') != NULL || strchr(buff,'P') != NULL) { screen_previous(); *result = lastresult; }
else if (strchr(buff,'/') != NULL)
 {
 dividend = ((float) atof(buff));
 divisor = ((float) atof(strchr(buff,'/')+1));
 *result = dividend / divisor;
 }
else *result = ((float) atof(buff));
write_OPTIONS();
}

float evaluate_qty(struct food *food_ptr, char *qtystring)
{
float dividend, divisor;
if (qtystring == NULL) return 0;
if (strchr(qtystring,'g') != NULL) 
 {
 options.grams = 1;
 return atof(qtystring);
 }
else if (strchr(qtystring,'o') != NULL) 
 {
 options.grams = 0;
 return atof(qtystring) * GRAMS_IN_OUNCE;
 }
else if (strchr(qtystring,'c') != NULL) return atof(qtystring) * 100 / food_ptr->nutrient[ENERC_KCAL];
else if (strchr(qtystring,'/') != NULL)
 {
 dividend = atof(qtystring);
 divisor = atof(strchr(qtystring,'/')+1);
 return food_ptr->grams * dividend / divisor;
 }
else return atof(qtystring) * food_ptr->grams;
write_OPTIONS();
}

int evaluate_action(char *actionstring)
{
int newpos;
if (strchr(actionstring,'(') != NULL) return -1;
else if (strchr(actionstring,')') != NULL) return -2;
else if (strchr(actionstring,'!') != NULL) return -3;
else if (strchr(actionstring,'m') != NULL)
 {
 newpos = atoi(strchr(actionstring,'m')+1);
 if (newpos < 1) newpos = 1;
 return newpos;
 }
else return 0;
}

void get_select(float *result)
{
char buff[128];
float lastresult = *result;
if ( lastresult <= 0 ) lastresult = 1;
printf("\n\"b\" to go back, <enter> to select:  ");
fgets(buff,128,stdin);
if (strchr(buff,'b') != NULL || strchr(buff,'B') != NULL) *result = -383838;
else *result = 0;
}

int get_int()
{
char buff[128];
fgets(buff,128,stdin);
return (atoi(buff));
}

float get_float()
{
char buff[128];
fgets(buff,128,stdin);
return (atof(buff));
}

void get_string(char *dest, int length)
{
char temp[128];
fgets(temp,128,stdin);
if (strchr(temp,'\n') != NULL) *strchr(temp,'\n') = '\0';
else length = 0;
strncpy(dest,temp,length);
dest[length] = '\0';
}

void header(char *string)
{
char buffer[81];
int count;
size_t size = 80;
size -= strlen(string);
size /= 2;
for (count = 0 ; (size_t) count < size ; count++) buffer[count] = ' '; 
buffer[count] = '\0';
#ifndef DOS
if (subuser[0] != '\0') printf("\033[2J%s%s\n[DB] %s\n",buffer,string,subuser);
else printf("\033[2J%s%s\n\n",buffer,string);
#else
if (subuser[0] != '\0') printf("\n%s%s\n[DB] %s\n",buffer,string,subuser);
else printf("\n%s%s\n\n",buffer,string);
#endif
}

void spacer(int lines)
{
lines = 20 - lines;
for ( ; lines > 0 ; lines--) printf("\n");
}

void key_clean()
{
int i;
for (i = 0 ; i < 8 ; i++) strcpy(Key[i],"");
}
 
void key_put(char *key)
{
int i;
for (i = 6 ; i >= 0 ; i--) strcpy(Key[i+1],Key[i]);
strcpy(Key[0],key);
}

void key_encode(char *substring, char *key)
{
int i;
for (i = 6 ; i >= 0 ; i--) strcpy(Key[i+1],Key[i]);
strncpy(Key[0],substring,59);
strncat(Key[0],"\1",60);
strncat(Key[0],key,120);
}

char *key_take()
{
static char key[121];
int i;
strcpy(key,Key[0]);
for (i = 0 ; i < 7 ; i++) strcpy(Key[i],Key[i+1]); 
strcpy(Key[7],"");
return key;
}

void key_decode(char *substring, char *key)
{
int i;
char *pos;
pos = strchr(Key[0],'\1');
if (pos != NULL)
 {
 strcpy(key,pos+1);
 *pos = '\0';
 strcpy(substring,Key[0]);
 }
if (pos == NULL) *key = '\0';
strcpy(substring,Key[0]);
for (i = 0 ; i < 7 ; i++) strcpy(Key[i],Key[i+1]); 
strcpy(Key[7],"");
}

void test_signsense(float *value)
{
wjl_ieee754_float_t *f = (wjl_ieee754_float_t *)value;
signsense = f->sign;
}

int test_for_negative_zero(float *value) {
wjl_ieee754_float_t *f = (wjl_ieee754_float_t *)value;
if (*value != 0) return 0;
if (f->sign != signsense) return 0;
else return 1;
}
