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

#define TRUE 1

#include "compthreads.cpp"
#include "qcborwein.cpp"

/* Change the endianess of a short int */
unsigned short
swapendian16 (unsigned short oldnum)
{
  char *oldn, *newn;
  unsigned short newnum;
  oldn = (char *) &oldnum;
  newn = (char *) &newnum;
  newn[0] = oldn[1];
  newn[1] = oldn[0];

  return newnum;
}

/* Check the endianess of the machine. 0 LE, 1 BE */
unsigned char
machine_endianess (void)
{
  unsigned char *endian;
  short int testnum = 256;
  endian = (unsigned char *) &testnum;
  return endian[0];
}

/*
   16 bit version
*/
unsigned short
checksum16 (unsigned char *data, int len)
{
  unsigned int sum = 0, tmp;

  if (machine_endianess () != TRUE)	/* Little Endian */
    {
      if ((len & 1) == 0)
	len = len >> 1;
      else
	len = (len >> 1) + 1;
      while (len > 0)
	{
	  sum += *((unsigned short *) data);
	  data += sizeof (unsigned short);
	  len--;
	}

      sum = (sum >> 16) + (sum & 0xffff);
      sum += (sum >> 16);
      return (~sum);
    }
    
  /* Big Endian */  
  if ((len & 1) == 0)
    len = len / 2;
  else
    len = (len / 2) + 1;

  while (len > 0)
    {
      tmp = swapendian16 (*(unsigned short *) data);
      sum += tmp;
      data += sizeof (unsigned short);
      len--;
    }

  sum = (sum << 16) + (sum & 0xffff0000);
  sum += (sum << 16);
  return (~sum >> 16);
}

int
main (int argc, char *argv[])
{
  char *pistr;
  mp_exp_t expvar;
  unsigned long long bits, i = 0, xdigits;
  int iter, thread = 0, prec = 4;

  if (argc == 1)
    {
      printf ("Invalid number of iterations \n");
      return 0;
    }

/* The number of iterations */
  iter = atoi (argv[1]);

  if (iter < 4)
    iter = 4;

  /*
   * Calculate the precision xdigits 
   */

  for (i = 0; i < iter - 1; i++)
    prec += prec;

  xdigits = prec;
  bits = (unsigned long long) (prec * 3.33);
  printf (" Calculating %10ld digits of pi...", (unsigned long) xdigits);
  fflush (stdout);

  /*
   * Initialize the mpf's 
   */
  mpf_set_default_prec (bits);

  borwein_initialize ((void *) &thread);	/* Initialize the borwein's algorithm */

  /* The Borwein's iterations */
  i = 0;
  prec = 4;


  while (i < (iter - 1))
    {
      borwein_calculate ((void *) &thread);	/* Calculate using the borwein's algorithm */
      prec += prec;
      i++;
    }

  borwein_finalize ((void *) &thread);


  pistr = (char *) malloc (prec + 100);
  mpf_get_str (pistr, &expvar, 10, prec, bd[0].p2);
  printf (" Checksum: %5u\n", checksum16 ((unsigned char *) pistr, prec));

  free (pistr);


  return 0;

}
