///
/// Copyright (c) 2018 xdx. All rights reserved.
///
/// \file: rand.go
///
/// \brief: The default random number generators of grand
///
/// \author: xdx
///

package grand

import (
	"bytes"
	"crypto/rand"
	"io"
	"math/big"

	"xdx.jelly/xgcl/gerrors"
)

// Reader re-export crypto/rand.Reader. It the default Random number generator of GCL.
var Reader = rand.Reader

// ReaderZero is a Reader which output 000...
// Note: only for testing
var ReaderZero = ConstantReader(0)

// ReaderOne is a Reader which output 111...
// Note: only for testing
var ReaderOne = ConstantReader(1)

var ReaderTwo = ConstantReader(2)

// ConstantReader is a reader which outputs constant byte squence.
type ConstantReader byte

// Read implements the io.Reader interface.
func (r ConstantReader) Read(b []byte) (int, error) {
	for i := range b {
		b[i] = byte(r)
	}
	return len(b), nil
}

// Read is a helper function for grand.Reader.
func Read(b []byte) (n int, err error) {
	return Reader.Read(b)
}

// GenerateRandom is the same as Read.
var GenerateRandom = Read

// GetRandom tries to get a random bytes slice of length.
// The return []byte may have a smaller length.
func GetRandom(length int) []byte {
	buf := make([]byte, length)
	n, _ := Read(buf)
	return buf[:n]
}

// GenerateRandomExact generates a random slice of length exactly n, or returns error
func GenerateRandomExact(n int, r io.Reader) ([]byte, error) {
	res := make([]byte, n)
	m, err := r.Read(res)
	if m < n {
		return nil, gerrors.WithAnnotating(ErrGenerateRandomFailed, err.Error())
	}
	return res, nil
}

// Int generate a random big.Int of bits bits
func Int(bits int) *big.Int {
	if bits <= 0 {
		return new(big.Int)
	}

	// n = 2^bits
	n := big.NewInt(1)
	n.Lsh(n, uint(bits))

	m, _ := rand.Int(Reader, n)
	m.SetBit(m, bits-1, 1)
	return m
}

////////////////////////////////////////////////////////////////
//             Deprecated functions                           //
////////////////////////////////////////////////////////////////

// NewReaderFromBytes wraps data to a reader, the return reader could
// read at most len(data) bytes.
// Note: when return an error, the reader may have read n bytes.
//
// Deprecated: use bytes.NewReader instead.
func NewReaderFromBytes(data []byte) io.Reader {
	return bytes.NewReader(data)
}
