/* anameal.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 "anameal.h"
#include "util.h"
#include "db.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

void analyze_meals(struct meal *meal_ptr_origin, int specialheader)
{
struct food *food_ptr, *food_ptr_abacus[MAX_FOOD];
struct food *food_recommended[18];
struct meal *meal_ptr;
int max, meals, count, mealcount, meal = 0, deficnuts;
int i, abacuscount, spacecount = 0, frcount, high_grams;
char meal_date[9], inbuf[128];
float newcal;
float deficpct[DV_COUNT], food_abacus[MAX_FOOD], serving_ratio_abacus[MAX_FOOD];
int deficnut[DV_COUNT];
float prodefic, thispct, totaldefic, serving_ratio;
options.temp_meal_root = meal_ptr_origin;
mealcount = meal_count(meal_ptr_origin);
max = mealcount;
if (specialheader) options.defanal = options.defanalrec;
else options.defanal = options.defanalanal;
if (options.defanal > 0 && options.defanal < mealcount) max = options.defanal;
if (mealcount == 0)
 {
 if (specialheader == 1) header("NUT:  Record Meals");
 else header("NUT:  Analyze Meals");
 spacer(0);
 printf("\nThere are no meals in database.  Press <enter> to continue..."); 
 count = get_int();
 return;
 }
while (max > 0)
 {
 meal_ptr = meal_ptr_origin;
 strcpy(meal_date,"");
 if (max > mealcount) max = mealcount;
 meals = 0;
 clear_work();
 while (meal_ptr->next != NULL && meals <= max)
  {
  meal_ptr = meal_ptr->next;
  if (strcmp(meal_date,meal_ptr->meal_date) != 0 || meal != meal_ptr->meal)
   {
   strcpy(meal_date,meal_ptr->meal_date);
   meal = meal_ptr->meal;
   meals++;
   }
  if (meals > max) break;
  for (count = 1; count <= *ScreenMap[options.screen] ; count++) if (! test_for_negative_zero(&FoodIndex[meal_ptr->food_no]->nutrient[ScreenMap[options.screen][count]])) food_work.nutrient[ScreenMap[options.screen][count]] = food_work.nutrient[ScreenMap[options.screen][count]] + ((options.mealsperday * meal_ptr->grams / 100 * FoodIndex[meal_ptr->food_no]->nutrient[ScreenMap[options.screen][count]]) / (float) max); 
  food_work.nutrient[FAT_KCAL] += ((options.mealsperday * meal_ptr->grams / 100 * FoodIndex[meal_ptr->food_no]->nutrient[FAT_KCAL]) / (float) max);
  food_work.nutrient[PROT_KCAL] += ((options.mealsperday * meal_ptr->grams / 100 * FoodIndex[meal_ptr->food_no]->nutrient[PROT_KCAL]) / (float) max);
  food_work.nutrient[CHO_KCAL] += ((options.mealsperday * meal_ptr->grams / 100 * FoodIndex[meal_ptr->food_no]->nutrient[CHO_KCAL]) / (float) max);
  food_work.nutrient[SHORT3] += ((options.mealsperday * meal_ptr->grams / 100 * FoodIndex[meal_ptr->food_no]->nutrient[SHORT3]) / (float) max);
  food_work.nutrient[LONG3] += ((options.mealsperday * meal_ptr->grams / 100 * FoodIndex[meal_ptr->food_no]->nutrient[LONG3]) / (float) max);
  food_work.nutrient[SHORT6] += ((options.mealsperday * meal_ptr->grams / 100 * FoodIndex[meal_ptr->food_no]->nutrient[SHORT6]) / (float) max);
  food_work.nutrient[LONG6] += ((options.mealsperday * meal_ptr->grams / 100 * FoodIndex[meal_ptr->food_no]->nutrient[LONG6]) / (float) max);
  }
 if (specialheader == 1) header("NUT:  Record Meals");
 else header("NUT:  Analyze Meals");
 if (max != 1 && options.screen == 0 && !options.custom) printf("Here are \"Daily Value\" average percentages for your previous %d meals:\n",max);
 if (max == 1 && options.screen == 0 && !options.custom) printf("Here are \"Daily Value\" average percentages for your previous 1 meal:\n");
 if (max != 1 && options.screen == 0 && options.custom) printf("Here are customized DV average percentages for your previous %d meals:\n",max);
 if (max == 1 && options.screen == 0 && options.custom) printf("Here are customized DV average percentages for your previous 1 meal:\n");
 if (max != 1 && options.screen > 0) printf("Here are average daily nutrient levels for your previous %d meals:\n",max);
 if (max == 1 && options.screen > 0) printf("Here are average daily nutrient levels for your previous 1 meal:\n");
 if (max != 1 && max == mealcount) printf(" -> Meals %s/%d through %s/%d\n\n",meal_ptr->meal_date,meal_ptr->meal,meal_ptr_origin->next->meal_date,meal_ptr_origin->next->meal);
 if (max != 1 && max != mealcount) printf(" -> Meals %s/%d through %s/%d\n\n",prev_meal(meal_ptr)->meal_date,prev_meal(meal_ptr)->meal,meal_ptr_origin->next->meal_date,meal_ptr_origin->next->meal);
 if (max == 1) printf(" -> Meal %s/%d\n\n",meal_ptr_origin->next->meal_date,meal_ptr_origin->next->meal);
 food_display(stdout);
 spacer(19);
 if ( options.screen == 0 )
  {
  printf("Type # of meals to analyze,  \"s\" for food suggestions, \"c\" to reset calories,\n");
  printf("\"m\" to reset macronutrients, \"e\" to reset everything,  \"o\" to restore defaults,\n");
  printf("\"d\" for alternate displays,  or just press <enter> to quit:  ");
  }
 if ( options.screen > 0 ) printf("\n\nType # of meals to analyze, \"d\" alternate displays, <enter> to quit: ");
 get_string(inbuf,127);
 if (strncmp(inbuf,"c",1) == 0)
  {
  if (options.screen != 0) continue;
  if (!options.locknuts[ENERC_KCAL])
   {
   newcal = food_work.nutrient[ENERC_KCAL];
   options.abnuts[FAT] = 0;
   options.abnuts[FAMS] = 0;
   if (options.abnuts[PROCNT]) options.pccarb = 0;
   auto_cal(&newcal,1);
   }
  } 
 else if (strncmp(inbuf,"d",1) == 0) screen();
 else if (strncmp(inbuf,"p",1) == 0) screen_previous();
 else if (strncmp(inbuf,"e",1) == 0)
  {
  if (options.screen != 0) continue;
  restore_defaults(0);
  for ( i = 1; i < DVMap[0]; i++) if ( !options.locknuts[DVMap[i+1]]) options.abnuts[DVMap[i+1]] = food_work.nutrient[DVMap[i+1]];
  options.abnuts[FAMS] = 0;
  if ( !options.locknuts[ENERC_KCAL] && !options.autocal) newcal = food_work.nutrient[ENERC_KCAL];
  if (  options.locknuts[ENERC_KCAL] || options.autocal) newcal = DV[ENERC_KCAL];
  if ( !options.locknuts[FASAT] ) options.pcsatfat = 10 * food_work.nutrient[FASAT] / DVBase[FASAT] * DVBase[ENERC_KCAL] / newcal;
  auto_cal(&newcal,1);
  }
 else if (strncmp(inbuf,"m",1) == 0)
  {
  if (options.screen != 0) continue;
  restore_defaults(0);
  if ( !options.locknuts[FIBTG]) options.abnuts[FIBTG] = food_work.nutrient[FIBTG];
  if ( !options.locknuts[FASAT]) options.abnuts[FASAT] = food_work.nutrient[FASAT];
  if ( !options.locknuts[PROCNT]) options.abnuts[PROCNT] = food_work.nutrient[PROCNT];
  if ( !options.locknuts[CHOCDF]) options.abnuts[CHOCDF] = food_work.nutrient[CHOCDF];
  if ( !options.locknuts[ENERC_KCAL] && !options.autocal) newcal = food_work.nutrient[ENERC_KCAL];
  if (  options.locknuts[ENERC_KCAL] || options.autocal) newcal = DV[ENERC_KCAL];
  if ( !options.locknuts[FASAT] ) options.pcsatfat = 10 * food_work.nutrient[FASAT] / DVBase[FASAT] * DVBase[ENERC_KCAL] / newcal;
  auto_cal(&newcal,1);
  }
 else if (strncmp(inbuf,"o",1) == 0)
  {
  if (options.screen != 0) continue;
  restore_defaults(0);
  }
 else if (strncmp(inbuf,"n",1) == 0)
  {
  if (options.screen != 0) continue;
  restore_defaults(0);
  if ( !options.locknuts[FIBTG]) options.abnuts[FIBTG] = food_work.nutrient[FIBTG];
  if ( !options.locknuts[FASAT]) options.abnuts[FASAT] = food_work.nutrient[FASAT];
  if ( !options.locknuts[ENERC_KCAL] && !options.autocal)
   {
   newcal = food_work.nutrient[ENERC_KCAL];
   if ( !options.locknuts[PROCNT]) options.pcprotein = food_work.nutrient[PROT_KCAL] / food_work.nutrient[ENERC_KCAL] * 100;
   if ( !options.locknuts[CHOCDF]) options.pccarb = food_work.nutrient[CHO_KCAL] / food_work.nutrient[ENERC_KCAL] * 100;
   if ( !options.locknuts[FASAT] ) options.pcsatfat = 10 * food_work.nutrient[FASAT] / DVBase[FASAT] * DVBase[ENERC_KCAL] / newcal;
   }
  if (  options.locknuts[ENERC_KCAL] || options.autocal)
   {
   newcal = DV[ENERC_KCAL];
   if ( !options.locknuts[PROCNT]) options.pcprotein = food_work.nutrient[PROT_KCAL] / DV[ENERC_KCAL] * 100;
   if ( !options.locknuts[CHOCDF]) options.pccarb = food_work.nutrient[CHO_KCAL] / DV[ENERC_KCAL] * 100;
   if ( !options.locknuts[FASAT] ) options.pcsatfat = 10 * food_work.nutrient[FASAT] / DVBase[FASAT] * DVBase[ENERC_KCAL] / newcal;
   }
  auto_cal(&newcal,1);
  }
 else if (strncmp(inbuf,"s",1) == 0)
  {
  if (options.screen != 0) continue;
  header("NUT:  Food Suggestions");
  deficnuts = -1;
  totaldefic = 0;
  for (count = 0; count < DVMap[0]; count++) 
   {
   if (DVMap[count+1] == ENERC_KCAL || DVMap[count+1] == FAT || 
      DVMap[count+1] == NA || DVMap[count+1] == FASAT || 
      DVMap[count+1] == FAMS || DVMap[count+1] == FAPU || 
      DVMap[count+1] == CHOLE || DVMap[count+1] == OMEGA6 ||
      DVMap[count+1] == CHO_NONFIB || DVMap[count+1] == OMEGA3 ||
      DVMap[count+1] == CHOCDF ||
      (DVMap[count+1] == AA  && DV[AA] - 0.01 < .00001 && DV[EPA] - 0.01 < .00001 && DV[DHA] - 0.01 < .00001 ) ||
      (DVMap[count+1] == EPA && DV[AA] - 0.01 < .00001 && DV[EPA] - 0.01 < .00001 && DV[DHA] - 0.01 < .00001 ) ||
      (DVMap[count+1] == DHA && DV[AA] - 0.01 < .00001 && DV[EPA] - 0.01 < .00001 && DV[DHA] - 0.01 < .00001 ) ||
      food_work.nutrient[DVMap[count+1]] / DV[DVMap[count+1]] >= .9999) deficpct[count] = 0;
   else 
    {
    deficnuts++;
    deficnut[deficnuts] = count;
    deficpct[deficnuts] = (((float) max) / (float) options.mealsperday) * 100 * (1 - food_work.nutrient[DVMap[count+1]]/DV[DVMap[count+1]]);
    totaldefic += deficpct[deficnuts];
    }
   }
  if (deficnuts > 0) deficsort(deficpct, deficnut, deficnuts);
  if (deficnuts == -1 || deficpct[0] == 0)
   {
   printf("You have achieved the \"Daily Value\" for all nutrients.");
   spacer(0);
   printf("\nPress <enter> to continue..."); 
   count = get_int();
   }
  else
   {
   printf("Here are nutrients with additional daily percentages in the \"Daily Values\":\n\n");
   spacecount = 0;
   for (count = 0; count <= deficnuts; count++) 
    {
    if (totaldefic >= 1) printf("%-29s%-15s %6.0f%%\n"," ",Nutrient[DVMap[deficnut[count]+1]],deficpct[count]);
    else printf("%-29s%-15s %f%%\n"," ",Nutrient[DVMap[deficnut[count]+1]],deficpct[count]);
    if (deficnuts > count && count == 16) printf("%-29s%-23s\n"," ","plus additional nutrients...");
    if (deficnuts > count && count == 16) break;
    }
   spacer(deficnuts + 3);
   printf("\nPress <enter> to continue..."); 
   count = get_int();
   header("NUT:  Food Suggestions");
   printf("Here are randomly selected foods that provide the additional nutrients noted:\n\n");
   frcount = -1;
   while (totaldefic > 0)
    {
    food_ptr = &food_root;
    abacuscount = -1;
    while (food_ptr->next != NULL)
     {
     food_ptr = food_ptr->next;
     food_ptr_abacus[++abacuscount] = food_ptr;
     prodefic = 0;
     serving_ratio_abacus[abacuscount] = 10;
     high_grams = 114;
     for (count = 0; count <= deficnuts; count++)
      {
      thispct = 100 * food_ptr->nutrient[DVMap[deficnut[count]+1]] / DV[DVMap[deficnut[count]+1]]; 
      serving_ratio = deficpct[count] / thispct;
      if (serving_ratio < serving_ratio_abacus[abacuscount] && serving_ratio * food_ptr->grams > 14) serving_ratio_abacus[abacuscount] = serving_ratio;
      }
/*
     if (strstr(food_ptr->name,"DEHYD") != NULL) high_grams = 114;
     if (strstr(food_ptr->name,"DEHYDRATED") != NULL) high_grams = 114;
     if (strstr(food_ptr->name,"DRY") != NULL) high_grams = 114;
     if (strstr(food_ptr->name,"FROZEN DSSRT") != NULL) high_grams = 114;
*/
     if (strstr(food_ptr->name,"DRY") != NULL) serving_ratio_abacus[abacuscount] = 0;
     if (strstr(food_ptr->name,"FREEZE-DRIED") != NULL) serving_ratio_abacus[abacuscount] = 0;
     if (strstr(food_ptr->name,"DEHYD") != NULL) serving_ratio_abacus[abacuscount] = 0;
     if (strstr(food_ptr->name,"ALASKA NATIVE") != NULL) serving_ratio_abacus[abacuscount] = 0;
     if (strstr(food_ptr->name,"AK NATIVE") != NULL) serving_ratio_abacus[abacuscount] = 0;
     if (strstr(food_ptr->name,"NAVAJO") != NULL) serving_ratio_abacus[abacuscount] = 0;
     if (strstr(food_ptr->name,"INST BRKFST PDR") != NULL) serving_ratio_abacus[abacuscount] = 0;
     if (strstr(food_ptr->name,"INSTANT BREAKFAST") != NULL) serving_ratio_abacus[abacuscount] = 0;
     if (strstr(food_ptr->name,"ENSURE") != NULL) serving_ratio_abacus[abacuscount] = 0;
     if (strstr(food_ptr->name,"MEATLESS") != NULL) serving_ratio_abacus[abacuscount] = 0;
     if (strstr(food_ptr->name,"MARGARINE") != NULL) high_grams = 14;
     if (food_ptr->fdgrp == 2 || food_ptr->fdgrp == 3 || food_ptr->fdgrp == 8 || food_ptr->fdgrp == 14 || food_ptr->fdgrp == 19 || food_ptr->fdgrp == 25) serving_ratio_abacus[abacuscount] = 0;
     if (serving_ratio_abacus[abacuscount] > 1 && high_grams == 114) serving_ratio_abacus[abacuscount] = 1;
     if ((serving_ratio_abacus[abacuscount] * food_ptr->grams) > high_grams) serving_ratio_abacus[abacuscount] = high_grams / food_ptr->grams;
     for (count = 0; count <= deficnuts; count++)
      {
      thispct = serving_ratio_abacus[abacuscount] * food_ptr->grams * food_ptr->nutrient[DVMap[deficnut[count]+1]] / DV[DVMap[deficnut[count]+1]]; 
      if (thispct > deficpct[count]) thispct = deficpct[count];
      prodefic += thispct;
      }
     if (serving_ratio_abacus[abacuscount] == 0) prodefic = 0;
     food_abacus[abacuscount] = prodefic;
     for (count = 0 ; count <= frcount; count++) if (food_ptr_abacus[abacuscount] == food_recommended[count]) food_abacus[abacuscount] = -1;
     }
    abacuscount = random_max_var_array(food_abacus, abacuscount);
    food_ptr = food_ptr_abacus[abacuscount];            
    food_recommended[++frcount] = food_ptr;
    printf("%4.0f gm or %4.1f oz %-60s\n",serving_ratio_abacus[abacuscount] * food_ptr->grams,serving_ratio_abacus[abacuscount] * food_ptr->grams / GRAMS_IN_OUNCE,food_ptr->name);
    spacecount++;
    if (spacecount == 19) break;
    totaldefic = 0;
    for (count = 0; count <= deficnuts; count++) 
     {
     thispct = serving_ratio_abacus[abacuscount] * food_ptr->grams * food_ptr->nutrient[DVMap[deficnut[count]+1]] / DV[DVMap[deficnut[count]+1]]; 
     if (thispct > deficpct[count]) thispct = deficpct[count];
     deficpct[count] -= thispct;
     totaldefic += deficpct[count];
     }
    }
   spacer(++spacecount);
   printf("Press <enter> to continue...");
   count = get_int();
   }
  }
 else 
  {
  max = atoi(inbuf);
  if (max > 0) options.defanal = max;
  if (options.defanal == mealcount) options.defanal = 0;
  if (specialheader) options.defanalrec = options.defanal;
  if (!specialheader) options.defanalanal = options.defanal;
  write_OPTIONS();
  }
 }
}

void deficsort(float *deficpct, int *deficnut, int deficnuts)
{
int count, subcount, tempint;
float tempfloat;
for (count = 0 ; count < deficnuts ; count++)
 {
 for (subcount = count + 1 ; subcount <= deficnuts ; subcount++)
  {
  if (deficpct[subcount] > deficpct[count])
   {
   tempfloat = deficpct[count];
   deficpct[count] = deficpct[subcount];
   deficpct[subcount] = tempfloat;
   tempint = deficnut[count];
   deficnut[count] = deficnut[subcount];
   deficnut[subcount] = tempint;
   }
  }
 }
}

int random_max_var_array(float abacus[], int last)
{
int count, i = 0, max_count = 1, rand_count;
unsigned seed;
time_t t;
for ( count = 1 ; count < last ; count++ )
 {
 if (abacus[count] > abacus[i])
  {
  i = count;
  max_count = 1;
  }
 else if (abacus[count] == abacus[i]) max_count++;
 }
time(&t);
seed = (unsigned) t;
srand(seed);
rand_count = rand() % max_count;
for (count = 0 ; count < last ; count++)
 {
 if (abacus[count] == abacus[i]) rand_count--;
 if (rand_count < 0) return count;
 }
return i;
}
