/// <summary>
        /// UnShuffle the data that has been shuffled
        /// </summary>
        /// <param name="data">The shuffled data</param>
        /// <returns>The UnShuffled data</returns>
        public T[] UnShuffle <T>(T[] data, int ChunkSize = 255, ShuffleStatusCallback callback = null)
        {
            if (data.Length <= 1)
            {
                return(data);
            }

            lock (UnshuffleRnd)
            {
                T[] UnShuffledData            = new T[data.Length];
                List <DataShuffleInfo> NewPos = new List <DataShuffleInfo>();
                GetNewPos(ref NewPos, data, ref UnshuffleRnd, ChunkSize, callback);

                for (int i = 0; i < NewPos.Count; i++)
                {
                    if (NewPos[i].Length == 1)
                    {
                        UnShuffledData[NewPos[i].OldIndex] = data[NewPos[i].NewIndex];
                    }
                    else
                    {
                        Buffer.BlockCopy(data, NewPos[i].NewIndex, UnShuffledData, NewPos[i].OldIndex, NewPos[i].Length);
                    }
                }
                NewPos.Clear();
                return(UnShuffledData);
            }
        }
        private void GetNewPos <T>(ref List <DataShuffleInfo> NewPos, T[] data, ref Random rnd, int ChunkSize, ShuffleStatusCallback callback)
        {
            lock (rnd)
            {
                bool           isOneByte      = ChunkSize >= data.Length;
                int            size           = isOneByte ? 1 : ChunkSize;
                int            MaxSize        = (int)Math.Floor((float)data.Length / (float)size);
                int            BytesLeft      = data.Length - (size * MaxSize);
                int            BytesLeftIndex = -1;
                int[]          Indexes        = new int[MaxSize];
                ProgressHelper progressHelper = new ProgressHelper((ulong)MaxSize);

                //lets pre-generate the indexes

                for (int i = 0; i < Indexes.Length; i++)
                {
                    Indexes[i] = i;
                }

                int prevProgress = 0;
                for (int i = Indexes.Length, j = 0; i > 1; i--, j++)
                {
                    int pos = rnd.Next(i); // 0 <= j <= i-1
                    int tmp = Indexes[pos];
                    Indexes[pos]   = Indexes[i - 1];
                    Indexes[i - 1] = tmp;

                    progressHelper.Update(1);

                    if (callback != null)
                    {
                        double progress = progressHelper.Progress;
                        if (prevProgress != progress)
                        {
                            callback(progress, progressHelper.TimeLeft, (int)progressHelper.Speed);
                            prevProgress = progressHelper.Progress;
                        }
                    }
                }

                /*for (int i = 0; i < MaxSize; i++)
                 * {
                 *  decimal tmp = rnd.NextDecimal();
                 *  while (Indexes.ContainsKey(tmp))
                 *      tmp = rnd.NextDecimal();
                 *  Indexes.Add(tmp, i);
                 * }*/

                //lets generate where the data needs to be
                for (int i = 0, j = 0; i < data.Length; i += size, j++)
                {
                    if (i + size > data.Length)
                    {
                        BytesLeftIndex = i;
                        break;
                    }

                    DataShuffleInfo inf = new DataShuffleInfo()
                    {
                        OldIndex = i,
                        NewIndex = Indexes[j] * size,
                        Length   = size
                    };

                    if (inf.OldIndex + size > data.Length)
                    {
                        inf.Length = (inf.OldIndex + size) - data.Length;
                    }
                    if (inf.NewIndex + size > data.Length)
                    {
                        inf.Length = (inf.NewIndex + size) - data.Length;
                    }

                    NewPos.Add(inf);
                }

                if (BytesLeft > 0 && BytesLeftIndex >= 0)
                {
                    //need some improvement
                    NewPos.Add(new DataShuffleInfo()
                    {
                        OldIndex = BytesLeftIndex, NewIndex = BytesLeftIndex, Length = BytesLeft
                    });
                }
                Indexes = null;
            }
        }