/* trendy.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 "trendy.h" #include "food.h" #include "options.h" #include "util.h" #include "ranking.h" #include #include #include #include char trendy(char mode) { int nutnum, count; int caldv = 0, nutdv = 0, linecount, graphwidth = 35, daycount; float calunit, nutunit; char last_meal = '0'; char last_meal_date[9] = "00000000"; char nutname[36], roundbuf[20]; char calstring[36], nutstring[36], caldvstring[38], nutdvstring[38]; struct meal *meal_ptr, *another_crazy_meal_ptr; struct ep { char period[9]; float nutrient[NUTRIENT_COUNT]; int mealcount; struct ep *next; }; struct ep eachmonth, eachday, *ep_ptr, *saveep_ptr, *whichep_ptr; ep_ptr = &eachmonth; strcpy(ep_ptr->period,"00000000"); ep_ptr->next = NULL; for ( count = 1; count <= *ScreenMap[options.screen]; count++) ep_ptr->nutrient[ScreenMap[options.screen][count]] = 0; ep_ptr->nutrient[ENERC_KCAL] = 0; ep_ptr->nutrient[PROT_KCAL] = 0; ep_ptr->nutrient[FAT_KCAL] = 0; ep_ptr->nutrient[CHO_KCAL] = 0; ep_ptr = &eachday; strcpy(ep_ptr->period,"00000000"); ep_ptr->next = NULL; for ( count = 1; count <= *ScreenMap[options.screen]; count++) ep_ptr->nutrient[ScreenMap[options.screen][count]] = 0; ep_ptr->nutrient[ENERC_KCAL] = 0; ep_ptr->nutrient[PROT_KCAL] = 0; ep_ptr->nutrient[FAT_KCAL] = 0; ep_ptr->nutrient[CHO_KCAL] = 0; if (meal_count(&meal_root) == 0) { header("NUT: Plot Daily and Monthly Trends"); spacer(0); printf("\nThere are no meals in database. Press to continue..."); count = get_int(); return 'X'; } header("NUT: Plot Daily and Monthly Trends"); nut_list(); printf("\nType number of nutrient to graph and \"d\" or \"m\" (or to quit): "); nutnum = get_trendy(&mode); if (nutnum < 1 || nutnum > *ScreenMap[options.screen]) return mode; nutnum = ScreenMap[options.screen][nutnum]; ep_ptr = &eachmonth; saveep_ptr = &eachmonth; meal_ptr = &meal_root; daycount = 0; for ( ; ; ) { while (meal_ptr->next != NULL) { meal_ptr = meal_ptr->next; if ((saveep_ptr == &eachmonth && strncmp(ep_ptr->period,meal_ptr->meal_date,6) != 0) || (saveep_ptr == &eachday && strncmp(ep_ptr->period,meal_ptr->meal_date,8) != 0)) { if (daycount == 36) break; if ((ep_ptr->next = malloc(sizeof(struct ep))) == NULL) { printf("We are out of memory. Bummer.\n"); abort(); } ep_ptr = ep_ptr->next; ep_ptr->next = NULL; if (saveep_ptr == &eachmonth) { strncpy(ep_ptr->period,meal_ptr->meal_date,6); ep_ptr->period[6] = '\0'; } if (saveep_ptr == &eachday) { strncpy(ep_ptr->period,meal_ptr->meal_date,8); ep_ptr->period[8] = '\0'; daycount++; } for ( count = 1; count <= *ScreenMap[options.screen]; count++) ep_ptr->nutrient[ScreenMap[options.screen][count]] = 0; ep_ptr->nutrient[ENERC_KCAL] = 0; ep_ptr->nutrient[PROT_KCAL] = 0; ep_ptr->nutrient[FAT_KCAL] = 0; ep_ptr->nutrient[CHO_KCAL] = 0; ep_ptr->mealcount = 0; } if (strcmp(last_meal_date,meal_ptr->meal_date) != 0 || last_meal != meal_ptr->meal) { ep_ptr->mealcount++; strcpy(last_meal_date,meal_ptr->meal_date); last_meal = meal_ptr->meal; } for ( count = 1; count <= *ScreenMap[options.screen]; count++) ep_ptr->nutrient[ScreenMap[options.screen][count]] += (FoodIndex[meal_ptr->food_no]->nutrient[ScreenMap[options.screen][count]] * meal_ptr->grams / 100); if (options.screen > 1) ep_ptr->nutrient[ENERC_KCAL] += (FoodIndex[meal_ptr->food_no]->nutrient[ENERC_KCAL] * meal_ptr->grams / 100); ep_ptr->nutrient[PROT_KCAL] += (FoodIndex[meal_ptr->food_no]->nutrient[PROT_KCAL] * meal_ptr->grams / 100); ep_ptr->nutrient[FAT_KCAL] += (FoodIndex[meal_ptr->food_no]->nutrient[FAT_KCAL] * meal_ptr->grams / 100); ep_ptr->nutrient[CHO_KCAL] += (FoodIndex[meal_ptr->food_no]->nutrient[CHO_KCAL] * meal_ptr->grams / 100); } ep_ptr = saveep_ptr; while (ep_ptr->next != NULL) { ep_ptr = ep_ptr->next; for ( count = 1; count <= *ScreenMap[options.screen]; count++) { ep_ptr->nutrient[ScreenMap[options.screen][count]] = ep_ptr->nutrient[ScreenMap[options.screen][count]] * (float) options.mealsperday / (float) ep_ptr->mealcount; if (ep_ptr->nutrient[ScreenMap[options.screen][count]] > saveep_ptr->nutrient[ScreenMap[options.screen][count]]) saveep_ptr->nutrient[ScreenMap[options.screen][count]] = ep_ptr->nutrient[ScreenMap[options.screen][count]]; } if (options.screen > 1) { ep_ptr->nutrient[ENERC_KCAL] = ep_ptr->nutrient[ENERC_KCAL] * (float) options.mealsperday / (float) ep_ptr->mealcount; if (ep_ptr->nutrient[ENERC_KCAL] > saveep_ptr->nutrient[ENERC_KCAL]) saveep_ptr->nutrient[ENERC_KCAL] = ep_ptr->nutrient[ENERC_KCAL]; } ep_ptr->nutrient[PROT_KCAL] = ep_ptr->nutrient[PROT_KCAL] * (float) options.mealsperday / (float) ep_ptr->mealcount; if (ep_ptr->nutrient[PROT_KCAL] > saveep_ptr->nutrient[PROT_KCAL]) saveep_ptr->nutrient[PROT_KCAL] = ep_ptr->nutrient[PROT_KCAL]; ep_ptr->nutrient[FAT_KCAL] = ep_ptr->nutrient[FAT_KCAL] * (float) options.mealsperday / (float) ep_ptr->mealcount; if (ep_ptr->nutrient[FAT_KCAL] > saveep_ptr->nutrient[FAT_KCAL]) saveep_ptr->nutrient[FAT_KCAL] = ep_ptr->nutrient[FAT_KCAL]; ep_ptr->nutrient[CHO_KCAL] = ep_ptr->nutrient[CHO_KCAL] * (float) options.mealsperday / (float) ep_ptr->mealcount; if (ep_ptr->nutrient[CHO_KCAL] > saveep_ptr->nutrient[CHO_KCAL]) saveep_ptr->nutrient[CHO_KCAL] = ep_ptr->nutrient[CHO_KCAL]; } if (saveep_ptr == &eachday) break; ep_ptr = &eachday; saveep_ptr = &eachday; last_meal = '0'; strcpy(last_meal_date,"00000000"); meal_ptr = options.temp_meal_root; another_crazy_meal_ptr = options.temp_meal_root->next; while (strcmp(another_crazy_meal_ptr->meal_date,meal_ptr->meal_date) == 0) meal_ptr = prev_meal(meal_ptr); } whichep_ptr = &eachday; for ( ; ; ) { if (mode == 'd') { whichep_ptr = &eachday; graphwidth=34; } if (mode == 'm') { whichep_ptr = &eachmonth; graphwidth=35; } saveep_ptr = whichep_ptr; linecount = 0; calunit = whichep_ptr->nutrient[ENERC_KCAL] / graphwidth; nutunit = whichep_ptr->nutrient[nutnum] / graphwidth; if (whichep_ptr->nutrient[ENERC_KCAL] < DV[ENERC_KCAL]) calunit = DV[ENERC_KCAL] / graphwidth; if (options.screen == 0 && whichep_ptr->nutrient[nutnum] < DV[nutnum]) nutunit = DV[nutnum] / graphwidth; if (calunit > 0) caldv = floor(DV[ENERC_KCAL]/calunit +.5); if (nutunit > 0) { if (options.screen == 0) nutdv = floor(graphwidth - DV[nutnum]/nutunit +.5); else { sprintf(roundbuf,"%1.0e",whichep_ptr->nutrient[nutnum]/2); nutdv = floor(graphwidth - (atof(roundbuf)/nutunit +.5)); } } for (count = 0; count < graphwidth; count++) { caldvstring[count] = ' '; nutdvstring[count] = ' '; nutname[count] = ' '; } if (calunit > 0) { caldvstring[caldv-2] = 'D'; caldvstring[caldv-1] = 'V'; } if (nutunit > 0) { if (options.screen == 0) { nutdvstring[nutdv] = 'D'; nutdvstring[nutdv+1] = 'V'; } else sprintf(nutdvstring+nutdv,"%g%-3s",atof(roundbuf),Unit[nutnum]); } caldvstring[graphwidth] = '\0'; if (nutdv != graphwidth - 1) nutdvstring[graphwidth] = '\0'; else nutdvstring[graphwidth+1] = '\0'; strcpy(nutname + (21 + graphwidth - strlen(Nutrient[nutnum])) / 2,Nutrient[nutnum]); nutname[graphwidth] = '\0'; if (mode == 'm') { header("NUT: Plot Monthly Trends"); printf("%6s %-s %-s\n"," ","Protein/Carb/Fat Calories",nutname); printf("%6s %-s %-s\n"," ",caldvstring,nutdvstring); } if (mode == 'd') { header("NUT: Plot Daily Trends"); printf("%8s %-s %-s\n"," ","Protein/Carb/Fat Calories",nutname); printf("%8s %-s %-s\n"," ",caldvstring,nutdvstring); } ep_ptr = saveep_ptr; while (ep_ptr->next != NULL) { ep_ptr = ep_ptr->next; for (count = 0; count < graphwidth; count++) { calstring[count] = ' '; nutstring[count] = ' '; } if (calunit > 0) { for (count = 0; count < floor(ep_ptr->nutrient[ENERC_KCAL]/calunit +.5); count++) calstring[count] = 'F'; for (count = 0; count < floor(ep_ptr->nutrient[PROT_KCAL]/calunit + ep_ptr->nutrient[CHO_KCAL]/calunit +.5); count++) calstring[count] = 'c'; for (count = 0; count < floor(ep_ptr->nutrient[PROT_KCAL]/calunit + .5); count++) calstring[count] = 'P'; } switch (nutnum) { case FAT : for (count = 0; count < floor(ep_ptr->nutrient[FAT]/nutunit + .5); count++) nutstring[graphwidth-1-count] = '.'; for (count = 0; count < floor(ep_ptr->nutrient[FASAT]/nutunit + ep_ptr->nutrient[FAMS]/nutunit + ep_ptr->nutrient[OMEGA6]/nutunit + ep_ptr->nutrient[OMEGA3]/nutunit +.5); count++) nutstring[graphwidth-1-count] = 's'; for (count = 0; count < floor(ep_ptr->nutrient[FAMS]/nutunit + ep_ptr->nutrient[OMEGA6]/nutunit + ep_ptr->nutrient[OMEGA3]/nutunit +.5); count++) nutstring[graphwidth-1-count] = 'm'; for (count = 0; count < floor(ep_ptr->nutrient[OMEGA6]/nutunit + ep_ptr->nutrient[OMEGA3]/nutunit +.5); count++) nutstring[graphwidth-1-count] = '6'; for (count = 0; count < floor(ep_ptr->nutrient[OMEGA3]/nutunit +.5); count++) nutstring[graphwidth-1-count] = '3'; break; case FASAT : for (count = 0; count < floor(ep_ptr->nutrient[FASAT]/nutunit + .5); count++) nutstring[graphwidth-1-count] = 's'; break; case FAMS : for (count = 0; count < floor(ep_ptr->nutrient[FAMS]/nutunit + .5); count++) nutstring[graphwidth-1-count] = 'm'; break; case FAPU : for (count = 0; count < floor(ep_ptr->nutrient[FAPU]/nutunit + .5); count++) nutstring[graphwidth-1-count] = '6'; for (count = 0; count < floor(ep_ptr->nutrient[LA]/nutunit + ep_ptr->nutrient[AA]/nutunit + ep_ptr->nutrient[OMEGA3]/nutunit +.5); count++) nutstring[graphwidth-1-count] = 'L'; for (count = 0; count < floor(ep_ptr->nutrient[AA]/nutunit + ep_ptr->nutrient[OMEGA3]/nutunit +.5); count++) nutstring[graphwidth-1-count] = 'A'; for (count = 0; count < floor(ep_ptr->nutrient[OMEGA3]/nutunit +.5); count++) nutstring[graphwidth-1-count] = '3'; for (count = 0; count < floor(ep_ptr->nutrient[ALA]/nutunit + ep_ptr->nutrient[EPA]/nutunit + ep_ptr->nutrient[DHA]/nutunit +.5); count++) nutstring[graphwidth-1-count] = 'n'; for (count = 0; count < floor(ep_ptr->nutrient[EPA]/nutunit + ep_ptr->nutrient[DHA]/nutunit +.5); count++) nutstring[graphwidth-1-count] = 'e'; for (count = 0; count < floor(ep_ptr->nutrient[DHA]/nutunit +.5); count++) nutstring[graphwidth-1-count] = 'd'; break; case OMEGA6 : for (count = 0; count < floor(ep_ptr->nutrient[OMEGA6]/nutunit + .5); count++) nutstring[graphwidth-1-count] = '6'; for (count = 0; count < floor(ep_ptr->nutrient[LA]/nutunit + ep_ptr->nutrient[AA]/nutunit +.5); count++) nutstring[graphwidth-1-count] = 'L'; for (count = 0; count < floor(ep_ptr->nutrient[AA]/nutunit +.5); count++) nutstring[graphwidth-1-count] = 'A'; break; case LA : for (count = 0; count < floor(ep_ptr->nutrient[LA]/nutunit + .5); count++) nutstring[graphwidth-1-count] = 'L'; break; case AA : for (count = 0; count < floor(ep_ptr->nutrient[AA]/nutunit + .5); count++) nutstring[graphwidth-1-count] = 'A'; break; case OMEGA3 : for (count = 0; count < floor(ep_ptr->nutrient[OMEGA3]/nutunit +.5); count++) nutstring[graphwidth-1-count] = '3'; for (count = 0; count < floor(ep_ptr->nutrient[ALA]/nutunit + ep_ptr->nutrient[EPA]/nutunit + ep_ptr->nutrient[DHA]/nutunit +.5); count++) nutstring[graphwidth-1-count] = 'n'; for (count = 0; count < floor(ep_ptr->nutrient[EPA]/nutunit + ep_ptr->nutrient[DHA]/nutunit +.5); count++) nutstring[graphwidth-1-count] = 'e'; for (count = 0; count < floor(ep_ptr->nutrient[DHA]/nutunit +.5); count++) nutstring[graphwidth-1-count] = 'd'; break; case ALA : for (count = 0; count < floor(ep_ptr->nutrient[ALA]/nutunit + .5); count++) nutstring[graphwidth-1-count] = 'n'; break; case EPA : for (count = 0; count < floor(ep_ptr->nutrient[EPA]/nutunit + .5); count++) nutstring[graphwidth-1-count] = 'e'; break; case DHA : for (count = 0; count < floor(ep_ptr->nutrient[DHA]/nutunit + .5); count++) nutstring[graphwidth-1-count] = 'd'; break; case CHOCDF : for (count = 0; count < floor(ep_ptr->nutrient[CHOCDF]/nutunit + .5); count++) nutstring[graphwidth-1-count] = '.'; for (count = 0; count < floor(ep_ptr->nutrient[FIBTG]/nutunit +.5); count++) nutstring[graphwidth-1-count] = ':'; break; case FIBTG : for (count = 0; count < floor(ep_ptr->nutrient[FIBTG]/nutunit + .5); count++) nutstring[graphwidth-1-count] = ':'; break; default : for (count = 0; count < floor(ep_ptr->nutrient[nutnum]/nutunit +.5); count++) nutstring[graphwidth-1-count] = '.'; break; } if (calunit > 0 && (calstring[caldv-2] == calstring[caldv] || (calstring[caldv] == ' ' && calstring[caldv-1] == ' ') || (caldv == graphwidth && calstring[caldv-1] == ' '))) calstring[caldv-1] = '|'; if (nutunit > 0 && (nutstring[nutdv+1] == nutstring[nutdv-1] || (nutstring[nutdv-1] == ' ' && nutstring[nutdv] == ' ') || (nutdv == 0 && nutstring[nutdv] == ' '))) nutstring[nutdv] = '|'; calstring[graphwidth] = '\0'; nutstring[graphwidth] = '\0'; printf("%-s %-s %-s\n",ep_ptr->period,calstring,nutstring); linecount++; if (mode == 'm' && linecount == 12) saveep_ptr = ep_ptr; if (linecount == 18 && ep_ptr->next != NULL) { spacer(linecount+2); printf("\nPress to scroll..."); count = get_int(); linecount = 0; if (mode == 'm') { header("NUT: Plot Monthly Trends"); printf("%6s %-s %-s\n"," ","Protein/Carb/Fat Calories",nutname); printf("%6s %-s %-s\n"," ",caldvstring,nutdvstring); } if (mode == 'd') { saveep_ptr = ep_ptr; header("NUT: Plot Daily Trends"); printf("%8s %-s %-s\n"," ","Protein/Carb/Fat Calories",nutname); printf("%8s %-s %-s\n"," ",caldvstring,nutdvstring); } ep_ptr = saveep_ptr; } } spacer(linecount+2); printf("\nPress to quit..."); count = get_int(); if (mode == 'm') header("NUT: Plot Monthly Trends"); if (mode == 'd') header("NUT: Plot Daily Trends"); nut_list(); printf("\nType number of nutrient to graph and \"d\" or \"m\" (or to quit): "); nutnum = get_trendy(&mode); if (nutnum < 1 || nutnum > *ScreenMap[options.screen]) { saveep_ptr = eachmonth.next; while (saveep_ptr != NULL) { ep_ptr = saveep_ptr; saveep_ptr = ep_ptr->next; free(ep_ptr); } saveep_ptr = eachday.next; while (saveep_ptr != NULL) { ep_ptr = saveep_ptr; saveep_ptr = ep_ptr->next; free(ep_ptr); } return mode; } nutnum = ScreenMap[options.screen][nutnum]; } } int get_trendy(char *mode) { char buff[128]; fgets(buff,128,stdin); if (strchr(buff,'M') != NULL) *mode = 'm'; if (strchr(buff,'m') != NULL) *mode = 'm'; if (strchr(buff,'D') != NULL) *mode = 'd'; if (strchr(buff,'d') != NULL) *mode = 'd'; return atoi(buff); }