// Name:  Micheal H. McCabe
// Date:  April 1, 2009 (April Fools Day!)
//
// Remarks:  This is a quick-and-dirty approach to the Biorhythm Generator
// Problem assisgned on Wednesday, April 1, 2009.
//
using namespace std;

// Libraries to be included

#include <iostream>
#include <string>
#include <iomanip>
#include <cmath>

// Misc. Definitions

#define LEFT_MARGIN 10             // Margin reserved for x-axis information
#define PLOT_WIDTH 60              // Overall range for plotting values is thus
                                   // (-44) to (+15) with one space reserved
                                   // for zero (offset plot.)
                                   
#define NEGATIVE_SCALE 44          // I could calculate these at run-time to
#define POSITIVE_SCALE 15          // make the program more general, but this
                                   // is the quick and dirty version.

// Function Prototypes Go Here

int plot (float time, float y);
void display_scale();
void plot_header();
void plot_string(int y, char K);

// Global Variables

char SPACE=' ';
char PLOT_DATA_POINT='*';
char PLOT_AREA_CHAR='-';
char PLOT_ZERO_CHAR='.';
char TICK_MARK_CHAR='|';
string TICK_MARK_STRING="-----|";

float bio_sine [] = { 0.00000,  0.13954,  0.27635,  0.40776,  0.53117,
                      0.64422,  0.74464,  0.83049,  0.90010,  0.95209,
                      0.98544,  0.99953,  0.94043,  0.96911,  0.92521,
                      0.86321,  0.78432,  0.69007,  0.58233,  0.46319,
                      0.33499,  0.20023,  0.06155, -0.07833, -0.21667,
                     -0.35078, -0.47802, -0.59592, -0.70215, -0.79436,
                     -0.87157, -0.93146, -0.97312, -0.99573, -0.99887,
                     -0.98245, -0.94681, -0.89265, -0.82101, -0.73331,
                     -0.63127, -0.51686, -0.39235, -0.26015, -0.12287};

// Main Routine

int main()
{
    float t;
    float y;
    int d=0;
    int begin_time=-9999;
    int end_time=-9999;
    float delta_time=0;
    int plot_area_units;
    
    cout << "Biorhythm Application -- 04/01/2009\n";
    cout << "Enter begin time (0-45): ";
    while (begin_time<0 || !cin)
          {
          cin >> begin_time;
          if (!cin || begin_time<0)
             cout << "Try again, Dufus!" << endl;
          }
    cout << "Enter end time (0-45):   ";
    while (end_time<=begin_time || !cin)
          {
           cin >> end_time;
           if (!cin || end_time<begin_time)
           cout << "Try again, Dufus!" << endl;
          }
    cout << "Enter delta-time (usually between.1 and 1): ";
    while (delta_time<0.1 || delta_time>1 || !cin)
          {
          cin >> delta_time;
          if (delta_time<0.1 || !cin)
             cout << "Try again, Dufus!" << endl;
          }       
    display_scale();
    plot_string(LEFT_MARGIN+2,SPACE);
    plot_header();
   for (t=begin_time; t<=end_time; t=t+delta_time)
       {
       // Here's where some confusion comes into play.  I would have thought
       // that we would scale the time value in a  linear fashion for values
       // less than 45 deg to get a full-function plot.  Instead it appears
       // that the time value simple advances 1 degree per iteration.
       // For the example given in the assignment, we iterate in steps of 0.5
       // time units, but advance 40 degrees during that time-frame (20 time
       // units = 40 degrees.)
       y=bio_sine[d%45]; // Take the mod to handle values > 45
       plot(t,y);
       d++;
       }
   plot_string(LEFT_MARGIN+2,SPACE);
   plot_header();
   display_scale();
return 0;
}

// Subroutines Begin Here

int plot(float time, float y)
{
    int skippy;
    int plot_area_units;
    cout << setprecision(1) << fixed << setw(LEFT_MARGIN) << time << SPACE
         << PLOT_AREA_CHAR << TICK_MARK_CHAR;
    if (y<0)
       {
       skippy= (int) (NEGATIVE_SCALE+(y*NEGATIVE_SCALE));
       plot_string(skippy,SPACE);
       cout << PLOT_DATA_POINT;
       plot_area_units=(NEGATIVE_SCALE-skippy)-1;
       plot_string(plot_area_units,PLOT_AREA_CHAR);
       cout << PLOT_ZERO_CHAR << endl;
       }
       else    if (y>0)
                  {
                  plot_string(NEGATIVE_SCALE,SPACE);
                  cout << PLOT_ZERO_CHAR;
                  plot_area_units=(int)(y*POSITIVE_SCALE+NEGATIVE_SCALE)-(NEGATIVE_SCALE+1);
                  plot_string(plot_area_units, PLOT_AREA_CHAR);
                  cout << PLOT_DATA_POINT << endl;
                  }
                else
                {
                plot_string(NEGATIVE_SCALE,SPACE);
                cout << PLOT_DATA_POINT << endl;
                }
               
    return 0;
}

void plot_header()
{
     int i;
     cout << TICK_MARK_CHAR;
     for (i=1; i<=10; i++)
         cout  << TICK_MARK_STRING;
     cout << endl;
     return;
}

void plot_string(int y, char k)
{
     int i;
     for (i=1; i<=y; i++)
         cout << k;
     return;
}

void display_scale()
{    
     //
     // I Don't like this, it appears that the scale is completely arbitrary
     // when compared with the scaled values generated by the main loop.
     // Either I need a second round of scaling or I'm missing something.
     //
     // Just some notes -- Since we are using an offset scale, we have a
     // data range of -17 to +6 with a plot range of -44 to +15.  This means
     // our negative scale is 17/44 (appx. 0.3863) per unit and our positive
     // scale is 6/15 (appx. 0.4) per unit.
     //
     // Sounds like it's time to revisit the main loop!
     //
     
     float scale=-17;
     int i;
     plot_string(LEFT_MARGIN-1, SPACE);
     for (i=0; i<=10; i++)
         {
         cout << setw(5) << setprecision(1) << fixed << scale << SPACE;
         scale=scale+2.3;
         }
     cout << endl;
     return;
}

         