#include <stdio.h>
#include "gmp.h"
#include <string.h>
#include <stdlib.h>

void fact
(
   mpz_t lFn,
   mpz_t lF
);


int main
(
   int   iArgs    ,
   char *apsArgs[]
)
{
    int   i = 0;
    char *pcArgN = NULL;
    char *pcArgR = NULL;
    long  lN     = 0L;
    long  lR     = 0L;


    mpz_t lFa;
    mpz_t lNa;
    mpz_t lNb;
    mpz_t lN_m_R;
    mpz_t lRa;
    mpz_t lRb;

    printf ("-n=number in the set. ie colours\n");
    printf ("-r=range of sequence. ie width * height\n");

    for (i = 0; i < iArgs; i++)
    {
       if (0 == strncmp ("-n=", apsArgs[i], 3))         // -n
       {
          pcArgN = apsArgs[i] + 3;
          lN     = atol (pcArgN);
       }
       else if (0 == strncmp ("-r=", apsArgs[i], 3))        // -r
       {
          pcArgR = apsArgs[i] + 3;
          lR     = atol (pcArgR);
       }
    }

   //

   printf ("pcArgN=[%s] lN=%ld\n", pcArgN, lN);
   printf ("pcArgR=[%s] lR=%ld\n", pcArgR, lR);

   // permutation  (order important, repetition allowed)          = n^r
   // permutation  (order NOT important, repetition allowed)      = (n+r-1)!/r!(n-1)!
   // permutation  (order NOT important, repetition NOT allowed)  = n!/(n-r)!(r!)      (NOTE: n > r)
   // permutation  (order important, repetition NOT allowed)      = n!/(n-r)!          (NOTE: n > r)



   // n = the number in the set. ie colors
   // r = the number to choose. ie width*height

   mpz_init (lFa);
   mpz_init (lNa);
   mpz_init (lNb);
   mpz_init (lN_m_R);
   mpz_init (lRa);
   mpz_init (lRb);

   // Set N and R from the args

   mpz_set_ui (lFa, 0);
   mpz_set_ui (lNa, lN);
   mpz_set_ui (lRa, lR);
  // gmp_printf ("lNa=%Zd\n", lNa);
  // gmp_printf ("lNb=%Zd\n", lNb);
  // gmp_printf ("lRa=%Zd\n", lRa);


   // Factorial of N

   fact (lNb, lNa);
   gmp_printf (" N=%Zd\n", lNa);
   gmp_printf ("N!=%Zd\n", lNb);

   // N-R

   mpz_sub (lN_m_R, lNa, lRa);

   gmp_printf ("R  =%Zd\n", lRa);
   gmp_printf ("N-R=%Zd\n", lN_m_R);

   // Factorial of N-R

   fact (lRb, lN_m_R);
   gmp_printf ("(N-R)!=%Zd\n", lRb);


   // !n / (n-r)!

   mpz_cdiv_q (lFa, lNb, lRb);
   gmp_printf ("N!/(N-R)!=%Zd\n", lFa);


   mpz_clear (lNa);
   mpz_clear (lNb);

   return (0);
}

void fact
(
   mpz_t lFn,
   mpz_t lF
)
{

   mpz_t N;
   mpz_t F;

   // FxF-1

   mpz_init (N);
   mpz_init (F);


   mpz_set (N, lF);
   mpz_set_ui (F, 1);


   while (mpz_cmp_ui (N, 2) >= 0)
   {
      //gmp_printf ("N=%Zd\n", N);
      mpz_mul (F, F, N);   // F = F * N;

      mpz_sub_ui (N, N, 1);   // N = N - 1;
   }

   mpz_set (lFn, F);

   return;
}
