/*******************************************************************************
 * Copyright IBM Corp. and others 2000
 *
 * This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License 2.0 which accompanies this
 * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
 * or the Apache License, Version 2.0 which accompanies this distribution
 * and is available at https://www.apache.org/licenses/LICENSE-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License, v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception [1] and GNU General Public
 * License, version 2 with the OpenJDK Assembly Exception [2].
 *
 * [1] https://www.gnu.org/software/classpath/license.html
 * [2] https://openjdk.org/legal/assembly-exception.html
 *
 * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
 *******************************************************************************/

#include "infra/Random.hpp"

#include <limits.h>
#include <stdint.h>
#include "compile/Compilation.hpp"

TR_HasRandomGenerator::TR_HasRandomGenerator(TR::Compilation *comp)
  : _randomGenerator(comp->primaryRandom()) {}

uint32_t TR_RandomGenerator::getRandom()
   {
   // Linear congruential parameters used by GCC; see https://en.wikipedia.org/wiki/Linear_congruential_generator
   // ...except we keep the sign bit (bit 31) while apparently they do not.
   //
   _bits = 1103515245 * _bits + 12345;

   // _bits alternates between odd and even, which is terrible for randomBoolean.
   // Let's mix it up a bit.
   //
   return (uint32_t)(_bits ^ (_bits >> 16));
   }

int32_t TR_RandomGenerator::getRandom(int32_t min, int32_t max)
   {
   uint32_t bits = getRandom();
   uint32_t range = max-min+1;
   if (range == 0) // corner case when range is INT_MIN..INT_MAX
      return (int32_t)bits;
   uint32_t rand = bits % range; // unsigned remainder
   return min + rand;
   }

void TR_RandomGenerator::setSeed(uint32_t newSeed)
   {
   _bits = newSeed;

   // Similar seeds can produce sequences that start off similar, so eat a few.
   //
   for (int i = 0; i < 5; i++)
      getRandom();
   }

class RandomExercizer: public TR_HasRandomGenerator
   {
   TR::Compilation *_comp;

   public:

   RandomExercizer(TR::Compilation *comp): TR_HasRandomGenerator(comp), _comp(comp){}

   TR::Compilation *comp(){ return _comp; }
   };


void TR_RandomGenerator::exercise(int32_t period, TR::Compilation *comp)
   {
   // Don't use the actual random generator because we don't want to perturb it
   RandomExercizer ex(comp);
   traceMsg(comp, "  %12s %12s %12s %12s %12s %12s\n",
      "Int", "Int(-5,5)", "Int(1,1)", "Int(MIN,MAX)", "Boolean", "Boolean(5)");
   for (int32_t i = 0; i < period; i++)
      {
      traceMsg(comp, "  %12d %12d %12d %12d %12d %12d\n",
         ex.randomInt(), ex.randomInt(-5,5), ex.randomInt(1,1), ex.randomInt(INT_MIN, INT_MAX), ex.randomBoolean(), ex.randomBoolean(5));
      }
   }