package javaIntro;
import java.math.BigInteger;
import java.util.Scanner;

/**
 * FactorialFunctions computes and shows the factorials of the
 * command line arguments.
 *
 * @author CS 140
 */
public class FactorialFunctions {
   /**
    Compute the factorial of the input value using int if the
    input is positive or zero. If the input is negative the
    function returns the <em>erroneous</em> value 1.
    The code uses a loop with the invariant: retVal = (i-1)!
    @param n positive or 0 value to compute factorial
    @return the factorial of n
    */
   public static int factorial1(int n) {
      int retVal = 1;
      for (int i = 2; i <= n; i++) {
         retVal *= i;
      }
      return retVal;
   }

   /**
    Compute the factorial of the input value using long if the
    input is positive or zero. If the input is negative the
    function returns the <em>erroneous</em> value 1.
    The code uses a loop with the invariant: retVal = (i-1)!
    @param n positive or 0 value to compute factorial
    @return the factorial of n
    */
   public static long factorial2(int n) {
      long retVal = 1;
      for (int i = 2; i <= n; i++) {
         retVal *= i;
      }
      return retVal;
   }

   /**
    Compute the factorial of the input value using BigInteger if the
    input is positive or zero. If the input is negative the
    function returns the <em>erroneous</em> value 1.
    The code uses a loop with the invariant: retVal = (i-1)!
    @param n positive or 0 value to compute factorial
    @return the factorial of n
    */
   public static BigInteger factorial3(int n) {
      BigInteger retVal = BigInteger.ONE;
      for (int i = 2; i <= n; i++) {
         retVal = retVal.multiply(BigInteger.valueOf(i));
      }
      return retVal;
   }

   /**
    * The main method computes and prints the
    * prints the factorial of the command line
    * argument on the screen.
    * @param args command-line argument should be
    * a single non-negative integer
    */
   public static void main(String[] args) {
      if (args.length == 0) {
         System.out.println("Usage error: you must " +
         "supply a non-negative integer argument");
      } else {
         for(int i = 0; i < args.length; i++) {
            Scanner input = new Scanner(args[i]);
            if (input.hasNextInt()) {
               int testValue = input.nextInt();
               if (testValue < 0) {
                  System.out.println("Usage error: you must " +
                  "not provide a negative integer argument");
                  System.out.println(args[i] + " is negative");
               } else {
                  System.out.println(factorial1(testValue));
                  System.out.println(factorial2(testValue));
                  System.out.println(factorial3(testValue));
               }
            } else {
               System.out.println("Usage error: you must " +
               "provide a non-negative integer argument");
               System.out.println(args[i] + " is not an integer");
            }
            input.close();
         }
      }
   }
}