// EdenAutoMorpher_ProfileSaver_Script, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// Eden.AutoMorpher.profile.ProfileUtil_IndexUtil
using UnityEngine;

public class ProfileUtil_IndexUtil
{
    public class BlockPermutations
    {
        private struct XorShift32
        {
            private uint _state;

            public XorShift32(uint seed)
            {
                this._state = ((seed != 0) ? seed : 1831565813u);
            }

            public uint NextUInt()
            {
                uint state = this._state;
                state ^= state << 13;
                state ^= state >> 17;
                return this._state = state ^ (state << 5);
            }

            public int NextInt(int maxExclusive)
            {
                return (int)(this.NextUInt() % (uint)maxExclusive);
            }
        }

        private readonly int _blockSize;

        private int[] _px;

        private int[] _py;

        private int[] _pz;

        private int[] _pall;

        private uint _checksum;

        private int _cachedLen = -1;

        private int[] _pxLen;

        private int[] _pyLen;

        private int[] _pzLen;

        private int[] _pallLen;

        public BlockPermutations(int blockSize)
        {
            this._blockSize = blockSize;
        }

        public void Build(int seed)
        {
            if (this._blockSize <= 1)
            {
                Debug.LogError("[ProfileUtil_IndexUtil] BlockPermutations.Build - invalid blockSize");
                return;
            }
            XorShift32 rng = new XorShift32((uint)(seed ^ -1556008596));
            XorShift32 rng2 = new XorShift32((uint)(seed ^ -939442524));
            XorShift32 rng3 = new XorShift32((uint)(seed ^ -1383041155));
            XorShift32 rng4 = new XorShift32((uint)(seed ^ 0x7E95761E));
            this._px = this.MakePermutation(this._blockSize, ref rng);
            this._py = this.MakePermutation(this._blockSize, ref rng2);
            this._pz = this.MakePermutation(this._blockSize, ref rng3);
            this._pall = this.MakePermutation(this._blockSize, ref rng4);
            this._checksum = this.ComputeChecksum(this._px, this._py, this._pz, this._pall);
            this._cachedLen = -1;
            this._pxLen = (this._pyLen = (this._pzLen = (this._pallLen = null)));
        }

        public bool ValidateRebuild(int seed)
        {
            uint checksum = this._checksum;
            BlockPermutations blockPermutations = new BlockPermutations(this._blockSize);
            blockPermutations.Build(seed);
            return blockPermutations._checksum == checksum;
        }

        public void GetPermutationsForLen(int len, out int[] pxUse, out int[] pyUse, out int[] pzUse, out int[] pallUse)
        {
            if (len == this._blockSize)
            {
                pxUse = this._px;
                pyUse = this._py;
                pzUse = this._pz;
                pallUse = this._pall;
                return;
            }
            if (this._cachedLen != len)
            {
                this._cachedLen = len;
                this._pxLen = this.MakeSubPermutation(this._px, len);
                this._pyLen = this.MakeSubPermutation(this._py, len);
                this._pzLen = this.MakeSubPermutation(this._pz, len);
                this._pallLen = this.MakeSubPermutation(this._pall, len);
            }
            pxUse = this._pxLen;
            pyUse = this._pyLen;
            pzUse = this._pzLen;
            pallUse = this._pallLen;
        }

        private int[] MakeSubPermutation(int[] fullPerm, int len)
        {
            int[] array = new int[len];
            int num = 0;
            for (int i = 0; i < fullPerm.Length; i++)
            {
                if (num >= len)
                {
                    break;
                }
                int num2 = fullPerm[i];
                if (num2 < len)
                {
                    array[num++] = num2;
                }
            }
            return array;
        }

        private int[] MakePermutation(int n, ref XorShift32 rng)
        {
            int[] array = new int[n];
            for (int i = 0; i < n; i++)
            {
                array[i] = i;
            }
            for (int num = n - 1; num > 0; num--)
            {
                int num2 = rng.NextInt(num + 1);
                ref int reference = ref array[num];
                ref int reference2 = ref array[num2];
                int num3 = array[num2];
                int num4 = array[num];
                reference = num3;
                reference2 = num4;
            }
            return array;
        }

        private uint ComputeChecksum(int[] a, int[] b, int[] c, int[] d)
        {
            uint h = 2166136261u;
            this.MixArray(ref h, a);
            this.MixArray(ref h, b);
            this.MixArray(ref h, c);
            this.MixArray(ref h, d);
            return h;
        }

        private void MixArray(ref uint h, int[] arr)
        {
            for (int i = 0; i < arr.Length; i++)
            {
                uint num = (uint)arr[i];
                h ^= num;
                h *= 16777619u;
            }
        }
    }

    public readonly int blockSize = 9783;

    private readonly BlockPermutations _perm;

    private float[] _xTmp;

    private float[] _yTmp;

    private float[] _zTmp;

    public ProfileUtil_IndexUtil(int blockSize = 9783)
    {
        this.blockSize = blockSize;
        this._perm = new BlockPermutations(blockSize);
        this._xTmp = new float[blockSize];
        this._yTmp = new float[blockSize];
        this._zTmp = new float[blockSize];
    }

    public void Build(int seed)
    {
        this._perm.Build(seed);
    }

    public void EncodeInto(Vector3[] input, Vector3[] output)
    {
        if (input == null || output == null)
        {
            Debug.LogError("[ProfileUtil_IndexUtil] EncodeInto - null args");
            return;
        }
        if (output.Length < input.Length)
        {
            Debug.LogError("[ProfileUtil_IndexUtil] EncodeInto - output too small");
            return;
        }
        int num = input.Length;
        int num2 = this.blockSize;
        int num3 = (num + num2 - 1) / num2;
        for (int i = 0; i < num3; i++)
        {
            int num4 = i * num2;
            int num5 = Mathf.Min(num2, num - num4);
            this._perm.GetPermutationsForLen(num5, out var pxUse, out var pyUse, out var pzUse, out var pallUse);
            for (int j = 0; j < num5; j++)
            {
                Vector3 vector = input[num4 + j];
                this._xTmp[pxUse[j]] = vector.x;
                this._yTmp[pyUse[j]] = vector.y;
                this._zTmp[pzUse[j]] = vector.z;
            }
            for (int k = 0; k < num5; k++)
            {
                int num6 = pallUse[k];
                output[num4 + num6] = new Vector3(this._xTmp[k], this._yTmp[k], this._zTmp[k]);
            }
        }
    }

    public void DecodeInto(Vector3[] encoded, Vector3[] output)
    {
        if (encoded == null || output == null)
        {
            Debug.LogError("[ProfileUtil_IndexUtil] DecodeInto - null args");
            return;
        }
        if (output.Length < encoded.Length)
        {
            Debug.LogError("[ProfileUtil_IndexUtil] DecodeInto - output too small");
            return;
        }
        int num = encoded.Length;
        int num2 = this.blockSize;
        int num3 = (num + num2 - 1) / num2;
        for (int i = 0; i < num3; i++)
        {
            int num4 = i * num2;
            int num5 = Mathf.Min(num2, num - num4);
            this._perm.GetPermutationsForLen(num5, out var pxUse, out var pyUse, out var pzUse, out var pallUse);
            for (int j = 0; j < num5; j++)
            {
                int num6 = pallUse[j];
                Vector3 vector = encoded[num4 + num6];
                this._xTmp[j] = vector.x;
                this._yTmp[j] = vector.y;
                this._zTmp[j] = vector.z;
            }
            for (int k = 0; k < num5; k++)
            {
                output[num4 + k] = new Vector3(this._xTmp[pxUse[k]], this._yTmp[pyUse[k]], this._zTmp[pzUse[k]]);
            }
        }
    }
}
