//
// CS 202 program 08_structures.cpp
// Written by D.C. Williams for 10/9/03 class
//
// Program to review the use of pointers and to introduce command line 
// arguments amd simple structures in the process of computing the 3 angles of 
// a triangle given the lengths of the sides.
//
// This algorithm uses law of cosines: c^2 = a^2 + b^2 - 2*a*b*cos(C), where
// C is the angle opposite side c. The trick is to calculate one angle,
// rotate the sides, and use the same expression to calculate the next angle.
// Three passes through the same loop calculates all three angles!
//


#include <iostream.h>
#include <math.h>
#include <iomanip.h>       // this allows us to format the data output


                                                 
float Angle_calc(float, float, float);           // to calculate the angles

int Ttest(float&, float&, float&, char);         // to test for valid data


const float RTD = float(45. / atan(1.));         // convert rad to degrees 


struct Side_angle      // declare a global structure of the type "Side_angle"
                       // global means we can create them in any function
{
   float side;         // this structure includes the length of a side
   float angle;        // and the measure of the angle opposite that side
                       // these are called "structure members" and can function
                       // just like any other variable.
                       // for those who remember classes, a structure is just 
                       // like a class with all public members and no functions!
};


int main(int argc, char *argv[])  // argc, argv handle command line arguments
                                  // argc = number of strings on command line
                                  // argv = pointer array for those strings
{

   char arg = '0';                // initialize in case there's no argument

   if (argc > 1)                  // and change it to equal the first character
      arg = *argv[1];             // of the argument if there is one
                                  // (note the de-referenced pointer)
   
   
   Side_angle a, b, c; // reserve storage for three structures: a, b, and c
                       // each holds the data for a side and the opposite angle
                       
   int flag = 1;       // flag = 1 means keep running


   cout << "\n\nProgram to calculate angles of a triangle given the sides.";
   
   while (flag != 0)    // flag = 0 will cause this loop to bail
   {
      cout << "\n\n\nInput three lengths separated by spaces (0 0 0 to quit): ";
           
      cin >> a.side >> b.side >> c.side;   // this is how we use our members

      if (a.side == 0. && b.side == 0. && c.side == 0)
      {
         flag = 0;     // time to bail!
         break;
      }

      if (a.side <= 0. || b.side <= 0. || c.side <= 0)
         cout << "\nInvalid input data! Try again!" << endl;
       
      if(Ttest(a.side, b.side, c.side, arg))                 // test validity 
         cout << "\nThat is NOT a valid triangle!" << endl;  
      else
      {              
         cout << "\nThese lengths represent a valid triangle." << endl;                                                       // bogus triangles

         a.angle = Angle_calc(b.side, c.side, a.side);             
         b.angle = Angle_calc(c.side, a.side, b.side);    
         c.angle = Angle_calc(a.side, b.side, c.side);          

         cout << setw(7) << setiosflags(ios::fixed) << setprecision(3) 
              << "\n\nSide length: " << a.side
              << "  , measure of angle opposite this side:  " 
              << a.angle * RTD << " degrees.";           
                       
         cout << setw(7) << setiosflags(ios::fixed) << setprecision(3) 
              << "\n\nSide length: " << b.side
              << "  , measure of angle opposite this side:  " 
              << b.angle * RTD << " degrees.";                  
                                
         cout << setw(7) << setiosflags(ios::fixed) << setprecision(3) 
              << "\n\nSide length: " << c.side 
              << "  , measure of angle opposite this side:  " 
              << c.angle * RTD << " degrees.";                                                                                                  
      }
   }  
   return 0;
}                


float Angle_calc(float a, float b, float c)
{
   return float(acos((pow(c,2.) - pow(a,2.) - pow(b,2.)) / (-2. * a * b)));;
}


int Ttest(float& a, float& b, float& c, char arg)
{

//
// the algorithm: find the largest side and make sure that the sum
// of the other two sides is greater than that.
//
// this also places the three sides in order by length
//
                                 // declare pointers to those variables
   float *pmax = 0, *pmid = 0;   // create a pointer to a float and set to 0
   float *pmin = NULL;           // create a pointer to a float and set to NULL
                                 // (0 and null are the same) 
                                 // it's important to initialize pointers when 
                                 // they're declared even if we set them to 
                                 // zero and later reassign them  
                                 
   
   if (a > b)                    // start with 2 sides and put them in order
   {
      pmax = &a;                 // remember that & means "the address of"
      pmin = &b;
   }
   
   else
   {
      pmax = &b;
      pmin = &a;
   }   
   
   if (c >= *pmax)               // take the third side and find out where it 
                                 // goes WRT the first 2
   {
      pmid = pmax;               // no * or & here - we're passing the address 
                                 // from pointer to pointer
      pmax = &c;
   }   
   
   else if (c >= *pmin)
      pmid = &c;   

   else
   {
      pmid = pmin;   
      pmin = &c;
   }  
   
   // a verbose output routine to illustrate how to de-reference pointers
   //
   // * = indirecton operator = dereference operator = print the value stored 
   // in the pointer's memory location . . . without it, the address is 
   // printed instead (that's what's stored as the value of a pointer variable)
   //
   
   if (arg == 'v')  // only execute this code if we asked for verbose output
   {
      cout << "\n\nLength of longest side  = " << *pmax 
           << " ,  memory address of this value = " << pmax << endl;
      cout << "Length of middle side   = " << *pmid 
           << " ,  memory address of this value = " << pmid << endl;
      cout << "Length of shortest side = " << *pmin 
           << " ,  memory address of this value = " << pmin << endl << endl;

   }        // end of verbose output routine
      
      
   if (*pmax < (*pmid + *pmin))   // the actual test
      return 0;                   // anything except 1 means we have a triangle
   else
      return 1;                   // but returning 1 means it's not 
}

// ! // ! // !