'use strict';

var createHmac = require('create-hmac');
var checkParameters = require('../lib/precondition');
var defaultEncoding = require('../lib/default-encoding');
var Buffer = require('safe-buffer').Buffer;

module.exports = function pbkdf2(password, salt, iterations, keylen, digest) {
	if (!Buffer.isBuffer(password)) {
		password = Buffer.from(password, defaultEncoding);
	}
	if (!Buffer.isBuffer(salt)) {
		salt = Buffer.from(salt, defaultEncoding);
	}

	checkParameters(iterations, keylen);

	digest = digest || 'sha1';

	var hLen;
	var l = 1;
	var DK = Buffer.allocUnsafe(keylen);
	var block1 = Buffer.allocUnsafe(salt.length + 4);
	salt.copy(block1, 0, 0, salt.length);

	var r;
	var T;

	for (var i = 1; i <= l; i++) {
		block1.writeUInt32BE(i, salt.length);
		var U = createHmac(digest, password).update(block1).digest();

		if (!hLen) {
			hLen = U.length;
			T = Buffer.allocUnsafe(hLen);
			l = Math.ceil(keylen / hLen);
			r = keylen - ((l - 1) * hLen);
		}

		U.copy(T, 0, 0, hLen);

		for (var j = 1; j < iterations; j++) {
			U = createHmac(digest, password).update(U).digest();
			for (var k = 0; k < hLen; k++) {
				T[k] ^= U[k];
			}
		}

		var destPos = (i - 1) * hLen;
		var len = i === l ? r : hLen;
		T.copy(DK, destPos, 0, len);
	}

	return DK;
};
