// @author: Constantine Apostolou
// @description:
//    Testing how recursive implementation of a function
//    that computes the factorial behaves in Rust.
// @license: GNU GPL v3

// We add the following line to be able to "use" everything
// in a library, since the "lib::*" feature is experimental.
#![feature(globs)]

// We include the external libc crate.
extern crate libc;

// And we use the needed libraries.
use std::*;
use libc::*;

// Compute the factorial of a number in a
// recursive manner. The parameter n is the
// number of which we want to find the factorial.
fn fact(n: u64) -> u64 {
    if n < 2 {
        1
    } else {
        n * fact(n - 1)
    }
}

// Computes the factorial of a manner in a
// tail-recursive manner. From the parameters:
// 'n' is the number of which we want to find the factorial.
// 'a' is initialy 1 and will carry the result of the
//     computation of the factorial.
fn 
(n: u64, a: u64) -> u64 {
    if n == 1 {
        return a;
    }
    else if n == 0 {
        return 1;
    }
    else {
        if n < 0 {
            return 0;
        }

        return facttail(n - 1, n * a);
    }
}

// Main entry to the program:
fn main() {
    // Store the parameters that were passed through the terminal
    // to the program.
    let args: Vec<String> = os::args();

    // Check if we have enough arguments; if we don't, then we need
    // to exit the program, as the nex step will result in an error.
    if args.len() < 2 {
        println!("Usage: fact [number]");
        println!("\tThis program computes the factorial of a given number.");
        println!("\t[number] must be a positive number.");

        unsafe {
            exit(1 as c_int);
        }
    }

    // This step does not check if we have a character/string instead
    // of a number.

    // Save the number that is in the second command line argument.
    let num: u64 = from_str::<u64>(args.get(1).as_slice()).unwrap();

    // Run the two functions that compute the factorial.
    let res = fact(num);        // Compute in a recursive manner.
    let ret = facttail(num, 1);    // Compute in a tail-recursive manner.

    // Finally print the results.
    println!("Result of fact({})        -> {}", num, res);
    println!("Result of facttail({}, 1) -> {}", num, ret);
}

facttail