/* trendy.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 "trendy.h"
#include "food.h"
#include "options.h"
#include "util.h"
#include "ranking.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

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 <enter> 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 <enter> 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 <enter> 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 <enter> 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 <enter> 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);
}
