using System.Collections;
using System.Collections.Generic;
using System;
using Godot;

namespace Rokojori
{
  [System.Serializable]
  public class LCGSeedState
  {
    public int modulus;
    public int multiplier;
    public int increment;
    public int state;    
  }

  public class LCG:SeedableRandomEngine
  {    
    private LCGSeedState _seedState = new LCGSeedState();
    private float _normalizer; 

    public LCG()
    {
      this.setParameters( (int)Mathf.Pow(2,32), 1664525, 1013904223 );
    }

    public static LCG WithSeed( int seed )
    {
      var lcg = new LCG();
      lcg.SetSeed( seed );

      return lcg;
    }


    public static LCG Randomized()
    {   
      var seed = (int) (Time.GetTicksUsec() % 1000000 );

      var lcg = new LCG();
      lcg.SetSeed( seed );

      lcg.SetSeed( lcg.IntegerExclusive( 0, 1000000 ) );

      return lcg;
    } 


    void setParameters( int modulus, int multiplier, int increment )
    {
      _seedState.modulus    = modulus;
      _seedState.multiplier = multiplier;
      _seedState.increment  = increment;
      _seedState.state      = 0;
      this._normalizer = 1f/(_seedState.modulus);   
    }

    public override object GetSeedState()
    {
      var seedState = new LCGSeedState();

      seedState.modulus = _seedState.modulus;
      seedState.multiplier = _seedState.multiplier;
      seedState.increment = _seedState.increment;
      seedState.state = _seedState.state;
    

      return seedState;
    }

    public int GetSeed()
    {
      return _seedState.state;
    }

    public override void SetSeedState( object seedStateObject )
    {
      var seedState = (LCGSeedState) seedStateObject;

      _seedState.modulus    = seedState.modulus;
      _seedState.multiplier = seedState.multiplier;
      _seedState.increment  = seedState.increment;
      _seedState.state      = seedState.state;
      this._normalizer = 1 / ( _seedState.modulus );   
    }

    public override float Next()
    {
      _seedState.state = ( _seedState.state * _seedState.multiplier + _seedState.increment) % _seedState.modulus;
      var value = _seedState.state * this._normalizer;
      return Mathf.Abs( value );
    }
    
    public override void SetSeed( int seed )
    {
      _seedState.state = seed % _seedState.modulus;      
    }
    
  }
}