/*
 * Copyright ©2026 Soham Pardeshi. All rights reserved.
 * Permission is hereby granted to students registered for University of
 * Washington CSE 333 for use solely during Summer Quarter 2026 for
 * purposes of the course. No other use, copying, distribution, or
 * modification is permitted without prior written consent. Copyrights
 * for third-party components of this work must be honored. Instructors
 * interested in reusing these course materials should contact the author.
 */

#include <stdio.h>     // for printf
#include <stdlib.h>    // for strtol, EXIT_SUCCESS / EXIT_FAILURE
#include <string.h>    // for strlen

// Print out the given string to stderr with an error prefix
void LogError(const char* error_text);

// Print out the usage of the program to stderr
void LogUsage(void);

// Return the nth fractional term in the Nilakantha series.
double GetNthTerm(int n);

int main(int argc, char* argv[]) {
  // [Precheck]
  // Verify that the user only passed one input via the command line
  if (argc != 2) {
    LogUsage();
    return EXIT_FAILURE;
  }

  // [Precheck]
  // Verify that the user gave us an integer value.
  // Although strtol returns a long, we can assume it is an int from the spec

  char* end_ptr;
  int num_terms = strtol(argv[1], &end_ptr, 10);

  // [Edge Case]
  // What happens if the user types in "10abc" or "10.5"? In that case, strtol
  // will parse the "10" and stop at the first non-integer character. We can
  // check for this by comparing these two pointers:
  //
  //     - `end_ptr` points to the last character that strtol was able to parse
  //     - `end_arg_ptr` points to the last character in argv[1]
  //
  // If they are pointing to different characters, then strtol was not able to
  // parse the entire string as a single integer value.

  char* end_arg_ptr = argv[1] + strlen(argv[1]);
  if (end_ptr != end_arg_ptr) {
    LogError("User provided a non-integer value.");
    LogUsage();
    return EXIT_FAILURE;
  }

  // [Precheck] 
  // Verify that the integer isn't negative.
  if (num_terms < 0) {
    LogError("User provided a negative integer value.");
    LogUsage();
    return EXIT_FAILURE;
  }

  // Calculate and print the estimate.
  double estimate = 3.0;
  for (int i = 1; i <= num_terms; ++i) {
    estimate += GetNthTerm(i);
  }
  printf("Our estimate of Pi is %.20f\n", estimate);

  return EXIT_SUCCESS;
}

void LogError(const char* error_text) {
  fprintf(stderr, "ERROR: %s\n", error_text);
}

void LogUsage(void) {
  fprintf(stderr,
          "Usage:\n"
          "    ./ex1 n\n"
          "where n is a non-negative integer.\n"
          "Prints an estimate for Pi using n terms "
          "of the Nilakantha series.\n");
}

double GetNthTerm(int n) {
  double numerator = 4.0;
  double denominator = (2.0 * n) * (2.0 * n + 1.0) * (2.0 * n + 2.0);

  double term = numerator / denominator;
  if (n % 2 == 0) {
    term *= -1.0;
  }

  return term;
}