/* test drive polynomial arithmetic
 */

#include <stdio.h>
#include <stdlib.h>
#include "Polynomial.h"

/* check polynomial's degree */
int correctDegree(char *func, poly_t poly, int knownDegree) {
  if (poly.degree != knownDegree) {
    printf("Bad %s degree, %d should be %d\n",
	   func, poly.degree, knownDegree);
    return 0; /* it doesn't have the correct degree */
  }
  return 1; /* it has the correct degree */
}

/* check polynomial's coefficients against previous calculated ones */
int correctCoefficients(char *func, poly_t poly) {
  int currentCoeff, i;
  for (i= 0; i <= poly.degree; i++) {
    scanf("%d", &currentCoeff);
    if (poly.coefficient[i] != currentCoeff) {
      printf("Bad %s at coefficient %d.  %d should be %d\n",
	     func, i, poly.coefficient[i], currentCoeff);
      return 0; /* not correct */
    }
  }
  return 1; /* correct */
}

/* read a polynomial's coefficients from standard in */
void scanCoefficients(poly_t *poly) {
  int i;
  for (i= 0; i <= poly->degree; i++) {
    scanf("%d", &(poly->coefficient[i]));
  }
}

/* initialize a polynomial's degree and coefficients */
void initPolynomials(poly_t *poly1, poly_t *poly2) {
  scanf("%d %d", &(poly1->degree), &(poly2->degree));
  if (poly1->degree < 0) {
    poly1->coefficient= NULL;
  } else {
    poly1->coefficient= (int *) malloc((poly1->degree + 1) * sizeof (int));
    scanCoefficients(poly1);
  }
  if (poly2->degree < 0) {
    poly2->coefficient= NULL;
  } else {
    poly2->coefficient= (int *) malloc((poly2->degree + 1) * sizeof (int));
    scanCoefficients(poly2);
  }
}

/* Check the product against previous calculations */
void checkProduct(const poly_t poly1, const poly_t poly2) {
  poly_t calcProduct= mult(poly1, poly2);
  int productDegree;

  if (poly1.degree < 0 || poly2.degree < 0) {
    productDegree= ZERO_DEGREE;
  } else {
    productDegree= poly1.degree + poly2.degree;
  }

  if (correctDegree("Product", calcProduct, productDegree)) {
    printf("Product has correct degree\n");
  }
  if (correctCoefficients("Product", calcProduct)) {
    printf("Product has correct coefficients\n");
  }
  if (calcProduct.coefficient) /* we allocated it */
    free (calcProduct.coefficient);
}

/* Check the sum against previous calculations */
void checkSum(const poly_t poly1, const poly_t poly2) {
  int maxDegree= poly1.degree;
  poly_t calcSum= plus(poly1, poly2);

  if (poly2.degree > poly1.degree) {
    maxDegree= poly2.degree;
  }

  if (correctDegree("Sum", calcSum, maxDegree) ) {
    printf("Sum has correct degree\n");
  }
  if (correctCoefficients("Sum", calcSum)) {
    printf("Sum has correct coefficients\n");
  }
  if (calcSum.coefficient) /* we allocated it */
    free (calcSum.coefficient);
}

/* check the quotient and remainder against previous calculations */
void checkDiv(const poly_t poly1, const poly_t poly2) {
  poly_t *calcDiv;
  if (poly1.degree < poly2.degree ||
      poly2.degree < 0 ||
      abs(poly2.coefficient[poly2.degree]) != 1) {
    printf("You can't do monic division on these polynomials\n");
    return;
  }

  calcDiv= monDiv(poly1, poly2);

  if (correctDegree("Quotient", calcDiv[0], 
		    poly1.degree - poly2.degree)) {
    printf("Quotient has correct degree\n");
  }
  if (correctCoefficients("Quotient", calcDiv[0])) {
    printf ("Quotient has correct coefficients\n");
  }
  /* no obvious way to check expected remainder's degree */
  if (correctCoefficients("Remainder", calcDiv[1])) {
    printf ("Remainder has correct coefficients\n");
  }

  /* tidy up */
  if (calcDiv[0].coefficient) /* non-NULL */
    free (calcDiv[0].coefficient);
  if (calcDiv[1].coefficient) /* non-NULL */
    free (calcDiv[1].coefficient);
  free (calcDiv);
}

/* Check evaluation of polynomial against previous calculation */
void checkEval(const poly_t poly) {
  int x, currentEval, calcEval;

  scanf("%d %d", &x, &currentEval);
  calcEval= eval(poly, x);
  if (calcEval != currentEval) {
    printf("Bad evaluation, %d should be %d\n",
	   calcEval, currentEval);
    return;
  }
  printf("Evaluation okay\n");
}
    
int main(void) {
  poly_t poly1, poly2;

  initPolynomials(&poly1, &poly2);
  checkProduct(poly1, poly2);
  checkSum(poly1, poly2);
  checkEval(poly1);
  checkEval(poly2);
  checkDiv(poly1, poly2);

  /* tidy up */
  if (poly1.coefficient) { /* it's been allocated */
    free(poly1.coefficient);
  }
  if (poly2.coefficient) { /* it's been allocated */
    free(poly2.coefficient);
  }

  return 0;
}

