/* You need this in order to use printf() */
#include <stdio.h>

/* These are function prototypes. 
 * They tell any code the follows that such functions exist,
 * what parameters (if any) they take, and what type (if any)
 * they return.
 */

/* Prints a line of dashes to the console */
void dashedLine();

/* Computes the factorial of num and returns the result */
unsigned int factorial(unsigned int num);

/* Prints the word representation of the digits in the number */
void printNumbers(int number);

/* Reverses the digits in a number */
unsigned int reverseDigits(unsigned int num);

/* A function that is declared before it is used does not need a prototype,
 * since the declaration contains the same information.
 */
void printFactorial(unsigned int num)
{
        printf("%d factorial is %d\n", num, factorial(num));
}

/* A global array with initial values.
 *
 * These numbers are used to test the factorial function.
 * Notice that these are ints but factorial takes an unsigned int.
 * The first negative number indicates the end of the list.
 */
int testNumbers[] =
{
        5,
        7,
        50,             /* This will overflow! */
        1,              /* Checking unusual cases */
        0,

        /* End of list */
        -1              /* What happens if this isn't here? */
};

/* Execution begins at main(), and ends when main() returns */
int main()
{
        int i;

        /* factorial */
        dashedLine();
        printf("Factorial Calculator:\n");
        for (i = 0; testNumbers[i] >= 0; i++)
        {
                /* int is automatically converted to unsigned int */
                printFactorial(testNumbers[i]);
        }
        dashedLine();

        /* number printer */
        dashedLine();
        printf("Number Printer:\n");
        printf("%6d -> ", 345);
        printNumbers(345);
        printf("%6d -> ", 5234);
        printNumbers(5234); 
        printf("%6d -> ", -952);
        printNumbers(-952);
        dashedLine();

        /* main() must return some value, but for our purposes it means nothing */
        return 0;
}

unsigned int factorial(unsigned int num)
{
        unsigned int i, accum=1;
        
        for (i = num; i > 1; i--)
        {
                accum = accum * i;
        }
        
        return accum;
}

void printNumbers(int num)
{
        /* This is used later, but must be declared before any executable code */
        unsigned int rev;

        if (num < 0)
        {
                printf("negative ");
                
                /* Make the number positive.
                 * This allows the rest of the code to only worry about positive numbers.
                 */
                num = -num;
        }
        else if (num == 0)
        {
                /* Handle the simple case of 0 */
                printf("zero");
                
                /* Notice there is no return value, the function has a 'void' return type.
                 * This just says I want to leave this function and return to where I was called from
                 */
                return;
        }

        /* Reverse the digits, reason for this will become clear */
        rev = reverseDigits(num);

        /* We will loop while rev > 0, so we must make sure that rev does
         * actually become 0 at some point
         */
        while (rev > 0)
        {
                /* By using the modulus operator and 10 we grab the digit in the ones place */
                unsigned char tempNum = rev % 10;

                /* We then divide rev by 10 and this shifts decimal one place left.
                 * Remember that integers truncate so once we shift out the last number
                 * rev becomes 0.
                 */
                rev /= 10;

                /* Based on tempNum (the ones digit) we print the word.
                 * To print the digits in the right order we had to first reverse them.
                 */
                switch (tempNum)
                {
                        case 0:
                                printf("zero ");
                                break;
                        case 1:
                                printf("one ");
                                break;
                        case 2:
                                printf("two ");
                                break;
                        case 3:
                                printf("three ");
                                break;
                        case 4:
                                printf("four ");
                                break;
                        case 5:
                                printf("five ");
                                break;
                        case 6:
                                printf("six ");
                                break;
                        case 7:
                                printf("seven ");
                                break;
                        case 8:
                                printf("eight ");
                                break;
                        case 9:
                                printf("nine ");
                                break;
                }
        }
        
        printf("\n");
}

unsigned int reverseDigits(unsigned int num)
{
        unsigned int rev = 0;
        
        /* Loop while number remains greater than 0 */
        while (num > 0)
        {
                /* Multiply the reversed number by 10 (shifts the decimal right) */
                rev *= 10;      /* same as: rev = rev * 10; */
                
                /* After the shift, the ones place of rev is 0.
                 * Now add the ones digit of num to rev.
                 */
                rev += num % 10; /* same as: rev = rev + num %10; */
                
                /* We then shift num one decimal place left */
                num /= 10;      /* same as: num = num/10; */
        }
        
        /* Return the reversed number */
        return rev;
}

void dashedLine()
{
        int i;

        /* For loop to print a dash some number of times */
        for (i = 0; i < 40; i++)
        {
                printf("-");
        }

        /* Add on a newline character only once */
        printf("\n");

        /* Notice there is no return.  This function is void.
         * It will automatically go back to where it was called when it finishes.
         */
}