//
// Written by John A deLaubenfels, https://www.adaptune.com/steg.htm .
// Permission granted to use freely in any non-fraudulent way.
//


#ifdef NEED_PCH
   #include "pch.h"
#else
   #include "stdafx.h"
#endif // !NEED_PCH


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

#include <time.h>
#include "globs.h"
#include "randd.h"

#ifdef _WIN32
#include <conio.h>
#endif // _WIN32

#define RANDDD randos
#define SRAND srandos
// #define SLASH '\\'
// #define OTHER_SLASH '/'

#ifndef ATOI
#define ATOI atoi
#endif

#define MAX_LINES (32768)

#define BILL_GATES

// #include <dos.h>
#include <malloc.h>
#include <fcntl.h>
// #include <io.h>


#ifndef _WIN32
#define _kbhit kbhit
#define _getch getch
#endif // !_WIN32


static char cbuf[MAX_CBRN];




void srandos(long seed)
{
   srand((unsigned int)seed);
}



long randos()
{
   return (long)rand();
}



// qxrandosWide()

long randosWide() {
   long l0 = randos();
   long l1 = randos();
   long lRet = l0 + (l1 << 15);

   return lRet;
} // end of randosWide()




//
// qxrandInit()

long randInit(void) {
   long lval;
   long theSeed;
   time_t loc_time;

   loc_time = time(NULL);

   if(jdebug & 0x0001) {
      SRAND((long)loc_time);
      lval = RANDDD();
      // fprintf(fp_std, "time %lld; first value out: %ld\n", (long long)loc_time, lval);
   }

   /* see man 3 random: */
   // SRAND((long)(2.0 * loc_time));
   // SRAND((long)(loc_time));
   theSeed = (long)(loc_time);
   SRAND(theSeed);
   SPIN;

   return theSeed;
} // end of randInit()...





//
// override 06-28-01, for serial number stuffola...
//
//
//
//
//
// qxrandInit()

long randInit(long theSeed) {
   long lval;
   time_t loc_time;

   // loc_time = time(NULL);
   loc_time = (time_t)theSeed;

   if(jdebug & 0x0001) {
      SRAND((long)loc_time);
      lval = RANDDD();
      // fprintf(fp_std, "time %lld; first value out: %ld\n", (long long)loc_time, lval);
   }

   /* see man 3 random: */
   // SRAND((long)(2.0 * loc_time));
   // SRAND((long)(loc_time));
   SRAND(theSeed);
   SPIN;

   return theSeed;
} // end of randInit()...




//
// new 03-16-02
//
// This modifies the rand state; used by randFromPwd().
//
//
//
// qxrandModi()
//

long randModi(long theModi) {
   int i;
   int nSpin = (theModi % 16) + 3;

   for(i=0; i<nSpin; i++) {
      RANDDD();
   } // for(i=0; i<nSpin; i++)
   long il = RANDDL;
   long il2 = il ^ theModi;
   long il3 = randInit(il2);

   return il3;
} // end of randModi()...





//
//
// spin some number of times:
//
//

void spin(void) {
   int i, ival;

   for(i=0; i<128; i++) {
      RANDDD();
   }
   ival = RAND_N(256);

   for(i=0; i<ival; i++) {
      RANDDD();
   }

   return;
} /* end of spin() */



#define TWO_TO_32    (4294967296.00)





//
// new 12-30-01
//
// uniform distribution from 0.0 to just shy of 1.0
//
//
//
// qxrandDoub()
//

double randDoub(void) {
   unsigned long ul;
   // ul = ((unsigned long)RANDDD() << 16) ^ (unsigned long)RANDDD();
   ul = ((unsigned long)RANDDD() << 20) ^ 
        ((unsigned long)RANDDD() << 10) ^ (unsigned long)RANDDD();
   double dRet = (double)ul / TWO_TO_32;

   return dRet;
} // end of randDoub()...





//
// new 12-30-01
//
// uniform distribution from just above 0.0 to 1.0
//
//
//
// qxrandDoubRev()
//

double randDoubRev(void) {
   unsigned long ul;
   // ul = ((unsigned long)RANDDD() << 16) ^ (unsigned long)RANDDD();
   ul = ((unsigned long)RANDDD() << 20) ^ 
        ((unsigned long)RANDDD() << 10) ^ (unsigned long)RANDDD();
   double dRet = ((double)ul + 1.0) / TWO_TO_32;

   return dRet;
} // end of randDoubRev()...




//
// new 03-16-02
//
//
//
//
// qxrandFromPwd()
//

long randFromPwd(void) {
   int teeRoo = 1;
   int nTyped = 0;
   long lRet;

   // start from a constant point:
   lRet = randInit(0x87654321);

   while(teeRoo) { // not really
      if(_kbhit()) {
         int ic = _getch();
         if(ic == 0x0D) break; // enter key

         // fprintf(fp_std, "Well, got %c (%02X).\n", ic, ic);
         lRet = randModi(ic);
         nTyped++;
      } // if(_kbhit()) 
      if(nTyped > 10) break;
   } // while(TRUE)  // not really

   return lRet;
} // end of randFromPwd()



//
// new 07-12-08 (jdl)
//
// This function attempts to improve the accuracy of the result; see $nv/it.
//
// Input:
//    iDesire: value leading to return of [0, iDesire-1].
//
// Output:
//    return value: [0 .. iDesire-1]
//
//
//
// qxrand_n()
//

long rand_n(long iDesire) {
   long lfact = N_RANDOS_WIDE / iDesire;
   long lmax  = lfact * iDesire;
   long lraw = randosWide();
   while(lraw >= lmax) lraw = randosWide();

   long lret = lraw % iDesire;           // [0, iDesire-1], with equal probability for each value.

   return lret;
} // end of rand_n()...


