/* anameal.c */ /* NUT nutrition software Copyright (C) 1996-2007 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 #include #include #include 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, ccals, fcals; 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; set_defanal(); 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 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 ) { if ( options.locknuts[ENERC_KCAL] || options.autocal ) printf("Type # of meals to analyze, \"s\" for food suggestions,\n"); if ( !options.locknuts[ENERC_KCAL] && !options.autocal ) 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 to quit: "); } if ( options.screen > 0 ) printf("\n\nType # of meals to analyze, \"d\" alternate displays, to quit: "); get_string(inbuf,127); if (strncmp(inbuf,"c",1) == 0) { if (!options.locknuts[ENERC_KCAL]) { newcal = food_work.nutrient[ENERC_KCAL]; options.abnuts[FAT] = 0; options.abnuts[FAMS] = 0; if (strstr(inbuf,"/") != NULL) { ccals = 0; fcals = 0; ccals = atof(inbuf+2); if (ccals > 0 && strstr(inbuf+2,"/") != NULL) { fcals = atof(strchr(inbuf+2,'/')+1); if (fcals > 0) newcal -= food_work.nutrient[CHO_KCAL] - ccals + food_work.nutrient[FAT_KCAL] - fcals; { if (!options.locknuts[CHOCDF]) { options.abnuts[CHOCDF] = 0; options.pccarb = 100 * ccals / newcal; } if (!options.locknuts[PROCNT]) { options.abnuts[PROCNT] = 0; options.pcprotein = 100 * food_work.nutrient[PROT_KCAL] / newcal; } if (!options.locknuts[FIBTG]) options.abnuts[FIBTG] = food_work.nutrient[FIBTG] * ccals / food_work.nutrient[CHO_KCAL]; } } if (ccals > 0 && strstr(inbuf+2,"/") == NULL) { newcal -= food_work.nutrient[CHO_KCAL] - ccals; if (!options.locknuts[CHOCDF]) { options.abnuts[CHOCDF] = 0; options.pccarb = 100 * ccals / newcal; } if (!options.locknuts[PROCNT]) { options.abnuts[PROCNT] = 0; options.pcprotein = 100 * food_work.nutrient[PROT_KCAL] / newcal; } if (!options.locknuts[FIBTG]) options.abnuts[FIBTG] = food_work.nutrient[FIBTG] * ccals / food_work.nutrient[CHO_KCAL]; } } if (options.fatprotratio > 0 && 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.locknuts[PROCNT] ) options.pcprotein = 0 ; if ( !options.locknuts[PROCNT] ) options.fatprotratio = 0 ; if ( !options.locknuts[CHOCDF] ) options.pccarb = 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]]; if ( !options.locknuts[ENERC_KCAL] ) newcal = food_work.nutrient[ENERC_KCAL]; if ( options.locknuts[ENERC_KCAL] ) newcal = DV[ENERC_KCAL] ; if ( !options.locknuts[FASAT] ) options.pcsatfat = 10 * food_work.nutrient[FASAT] / DVBase[FASAT] * DVBase[ENERC_KCAL] / newcal; if ( options.fatprotratio > 0 && ( options.pcprotein > 0 || options.abnuts[PROCNT] > 0) ) options.abnuts[CHOCDF] = 0; auto_cal(&newcal,1); } else if (strncmp(inbuf,"m",1) == 0 ) { if ( !options.locknuts[PROCNT] ) options.pcprotein = 0 ; if ( !options.locknuts[PROCNT] ) options.fatprotratio = 0 ; if ( !options.locknuts[CHOCDF] ) options.pccarb = 0 ; 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[FIBTG]) options.abnuts[FIBTG] = food_work.nutrient[FIBTG]; if ( !options.locknuts[FASAT]) options.abnuts[FASAT] = food_work.nutrient[FASAT]; if ( !options.locknuts[FAPU]) options.abnuts[FAPU] = food_work.nutrient[FAPU]; if ( !options.locknuts[OMEGA6]) options.abnuts[OMEGA6] = food_work.nutrient[OMEGA6]; if ( !options.locknuts[LA]) options.abnuts[LA] = food_work.nutrient[LA]; if ( !options.locknuts[AA]) options.abnuts[AA] = food_work.nutrient[AA]; if ( !options.locknuts[OMEGA3]) options.abnuts[OMEGA3] = food_work.nutrient[OMEGA3]; if ( !options.locknuts[ALA]) options.abnuts[ALA] = food_work.nutrient[ALA]; if ( !options.locknuts[EPA]) options.abnuts[EPA] = food_work.nutrient[EPA]; if ( !options.locknuts[DHA]) options.abnuts[DHA] = food_work.nutrient[DHA]; if ( !options.locknuts[ENERC_KCAL]) newcal = food_work.nutrient[ENERC_KCAL]; if ( options.locknuts[ENERC_KCAL]) newcal = DV[ENERC_KCAL]; if ( !options.locknuts[FASAT] ) options.pcsatfat = 10 * food_work.nutrient[FASAT] / DVBase[FASAT] * DVBase[ENERC_KCAL] / newcal; if ( options.fatprotratio > 0 && ( options.pcprotein > 0 || options.abnuts[PROCNT] > 0) ) options.abnuts[CHOCDF] = 0; options.abnuts[FAT] = food_work.nutrient[FAT]; options.abnuts[FAMS] = food_work.nutrient[FAMS]; auto_cal(&newcal,1); } else if (strncmp(inbuf,"n",1) == 0 ) { if ( !options.locknuts[PROCNT] ) options.abnuts[PROCNT] = 0 ; if ( !options.locknuts[PROCNT] ) options.fatprotratio = 0 ; if ( !options.locknuts[CHOCDF] ) options.abnuts[CHOCDF] = 0 ; if ( !options.locknuts[FIBTG]) options.abnuts[FIBTG] = food_work.nutrient[FIBTG]; 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[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.fatprotratio > 0 && ( options.pcprotein > 0 || options.abnuts[PROCNT] > 0) ) { options.pccarb = 0; options.abnuts[CHOCDF] = 0; } auto_cal(&newcal,1); } else if (strncmp(inbuf,"o",1) == 0 ) restore_defaults(0); 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] == VITD || DVMap[count+1] == PANTAC || DVMap[count+1] == FE || DVMap[count+1] == CU || 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 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("%-31s%-15s %3.0f%%\n"," ",Nutrient[DVMap[deficnut[count]+1]],deficpct[count]); else printf("%-31s%-15s %f%%\n"," ",Nutrient[DVMap[deficnut[count]+1]],deficpct[count]); if (deficnuts > count && count == 16) printf("%-31s%-23s\n"," ","plus additional nutrients..."); if (deficnuts > count && count == 16) break; } spacer(deficnuts + 3); printf("\nPress 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,"DRY") != NULL) high_grams = 114; if (strstr(food_ptr->name,"FROZEN DSSRT") != NULL) high_grams = 114; 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,"INST BRKFST PDR") != 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 / 28.35,food_ptr->name); spacecount++; if (spacecount == 19) break; totaldefic = 0; for (count = 0; count <= deficnuts; count++) { thispct = serving_ratio_abacus[abacuscount] * 100 * 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 to continue..."); count = get_int(); } } else { max = atoi(inbuf); if (max > 0) options.defanal = max; if (options.defanal == mealcount) options.defanal = 0; 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; }