/*
 * Program 1 - Find the coding style violations in this program.
 * Joe Student
 * CPE 101-xx
 * Adds, subtracts, multiplies and divides common fractions, displaying 
 * results in reduced form.
 */

#include <stdio.h>
#include <stdlib.h>   /* provides function abs */

/* Function prototypes */
void scan_fraction(int *nump, int *denomp);
char get_operator(void); 
void add_fractions(int numer1, int denom1, int numer2, int denom2,
                   int *n_ansp, int *d_ansp);
void multiply_fractions(int numer1, int denom1, int numer2, int denom2,
                        int *n_ansp, int *d_ansp);
int find_gcd (int numer1, int numer2);
void reduce_fraction(int *nump, int *denomp);
void print_fraction(int num, int denom);

/* Main Function */
int
main(void)
{
      int  numer1;       /* numerator of first fraction	*/
      int  denom1;       /* denominator of first fraction */
      int  numer2;       /* numerator of second fraction */
      int  denom2;       /* denominator of second fraction */
      char operator;     /* arithmetic operator + - * or / */
      char again;        /* y or n depending on user's desire to continue	*/
      int  n_ans;        /* numerator of answer	*/
      int  d_ans;        /* denominator of answer */

      /* While the user wants to continue, gets and solves arithmetic 
         problems with common fractions	*/
      do 
      {
          /* Gets the numerator and denominator of two fractions to manipulate */
          scan_fraction(&numer1, &denom1);
          /* Get the desired arithmetic operator */
          operator = get_operator();
          scan_fraction(&numer2, &denom2);

          /* Perform the needed operation for this operator  */
          switch (operator) 
          {
          case '+':  
                add_fractions(numer1, denom1, numer2, denom2, &n_ans, &d_ans);
                break;

          case '-':
                add_fractions(numer1, denom1, -numer2, denom2, &n_ans, &d_ans);
                break;

          case '*':
                multiply_fractions(numer1, denom1, numer2, denom2, &n_ans, &d_ans);
                break;

          case '/':
                multiply_fractions(numer1, denom1, denom2, numer2, &n_ans, &d_ans);
                break;
          }

          /*  Reduce the answer to simplest terms */
          reduce_fraction(&n_ans, &d_ans);

          /* Displays problem and result	*/
          printf("\n");
          print_fraction(numer1, denom1);
          printf(" %c ", operator);
          print_fraction(numer2, denom2);
          printf(" = ");
          print_fraction(n_ans, d_ans);

          /* Asks user about doing another problem	*/
          printf("\nDo another problem? (y/n)> ");
          scanf(" %c", &again);
      } while (again == 'y'  ||  again == 'Y');
      return (0);
}

/*
 * (INCOMPLETE) Gets and returns a valid fraction as its result
 * A valid fraction is of this form: integer/positive integer
 * Pre : none
 */
void
scan_fraction(int *nump, int *denomp)
{
      char slash;    /* character between numerator and denominator 	*/
      int  status;   /* status code returned by scanf indicating number of valid values obtained	*/
      int  error;    /* flag indicating presence of an error 	*/
      char discard;  /* unprocessed character from input line 	*/

      do {
          /* No errors detected yet 	*/
          error = 0;

          /* Get a fraction from the user 	*/
          printf("Enter a common fraction as two integers separated ");
          printf("by a slash> ");

	       status = scanf("%d %c%d",_______, _______, _______);

          /* Validate the fraction 	*/
          if (status < 3) {
                error = 1;
                printf("Invalid-please read directions carefully\n"); 
          } else if (slash != '/') {
                error = 1;
                printf("Invalid-separate numerator and denominator");
                printf(" by a slash (/)\n");
          } else if (*denomp <= 0) {
                error = 1;
                printf("Invalid-denominator must be positive\n");
          }

          /* Discard extra input characters 	*/
          do {
              scanf("%c", &discard);
          } while (discard != '\n');
      } while (error);
}

/*
 * Gets and returns a valid arithmetic operator.  Skips over newline
 * characters and permits re-entry of operator in case of error.
 */
char
get_operator(void) 
{
      char operator;

      printf("Enter an arithmetic operator (+,-,*, or /)\n> ");
      for  (scanf("%c", &operator);
            operator != '+'  &&  operator != '-'  &&
            operator != '*'  &&  operator != '/';
            scanf("%c", &operator)) {
          if (operator != '\n')
              printf("%c invalid, reenter operator (+,-, *,/)\n> ", operator);
      }
      return (operator);
}

/*
 * Adds fractions represented by pairs of integers.
 * Pre:  numer1, denom1, numer2, denom2 are defined; 
 *       n_ansp and d_ansp are addresses of type int variables.
 * Post: sum of numer1/denom1 and numer2/denom2 is stored in variables pointed 
 *       to by n_ansp and d_ansp.  Result is not reduced.
 */
void
add_fractions(int      numer1, int      denom1, /* input - first fraction   */
              int      numer2, int      denom2, /* input - second fraction  */
              int *n_ansp, int *d_ansp) /* output - sum of 2 fractions*/
{
      int denom,     /* common denominator used for sum (may not be least)	*/
          numer,       /* numerator of sum                	*/
          sign_factor; /* -1 for a negative, 1 otherwise	*/

      /* Finds a common denominator	*/
      denom = denom1 * denom2;

      /* Computes numerator	*/
      numer = numer1 * denom2 + numer2 * denom1;

      /* Adjusts sign (at most, numerator should be negative)	*/
      if (numer * denom >= 0)
            sign_factor = 1;
      else
            sign_factor = -1;

      numer = sign_factor * abs(numer);
      denom = abs(denom);

      /* Returns result	*/	
      *n_ansp = numer;
      *d_ansp = denom;
}

/*
 ***** STUB *****
 * Multiplies fractions represented by pairs of integers.
 * Pre:  numer1, denom1, numer2, denom2 are defined; 
 *       n_ansp and d_ansp are addresses of type int variables.
 * Post: product of numer1/denom1 and numer2/denom2 is stored in variables pointed 
 *       to by n_ansp and d_ansp.  Result is not reduced.
 */
void
multiply_fractions(int      numer1, int   denom1, /*  input - first fraction	*/
                   int      numer2, int   denom2, /*  input - second fraction	*/
                   int *n_ansp,           /*  output -	*/
		   int *d_ansp)           /*     product of 2 fractions	*/
{
      /* Displays trace message	*/
      printf("\nEntering multiply_fractions with\n");
      printf("numer1 = %d, denom1 = %d, numer2 = %d, denom2 = %d\n", numer1, denom1, numer2, denom2);

      /* Defines output arguments	*/
      *n_ansp = 1;
      *d_ansp = 1;
}

/* 
 ***** STUB *****
 * Finds greatest common divisor of two integers
 */
int
find_gcd (int numer1, int numer2) /* input - two integers	*/
{
      int gcd;

      /* Displays trace message	*/
      printf("\nEntering find_gcd with numer1 = %d, numer2 = %d\n", numer1, numer2);    

      /* Asks user for gcd	*/
      printf("gcd of %d and %d?> ", numer1, numer2);
      scanf("%d", &gcd);	

      /* Displays exit trace message	*/
      printf("find_gcd returning %d\n", gcd);
      return (gcd);
}


/* 
 * Reduces a fraction by dividing its numerator and denominator by their
 * greatest common divisor.
 */
void
reduce_fraction(int *nump,   /* input/output -	*/	
                int *denomp) /* numerator and denominator of fraction	*/
{
      int gcd;   /* greatest common divisor of numerator & denominator	*/

      gcd = find_gcd(*nump, *denomp);
      *nump = *nump / gcd;
      *denomp = *denomp / gcd;
}


/* 
 * Displays pair of integers as a fraction.
 */
void
print_fraction(int num, int denom)  /* input - numerator & denominator	*/
{
      printf("%d/%d", num, denom);
}