var bindings = require("bindings")("argon2_lib"),
  crypto = require("crypto");

exports.encrypt = function (plain, salt, options, callback) {
  "use strict";

  if (typeof(callback) == 'undefined') {
    callback = options;
    options = {};
  }

  options.timeCost = options.timeCost || 3;
  options.memoryCost = options.memoryCost || 12;
  options.parallelism = options.parallelism || 1;
  options.argon2d = !!options.argon2d;

  if (salt.length > 16) {
    process.nextTick(function () {
      callback(new Error("Salt too long, maximum 16 characters."), null);
    });
    return;
  }

  if (options.memoryCost >= 32) {
    process.nextTick(function () {
      callback(new Error("Memory cost too high, maximum of 32."), null);
    });
    return;
  }

  return bindings.encrypt(plain, salt, options.timeCost, options.memoryCost,
    options.parallelism, options.argon2d, callback);
};

exports.encryptSync = function (plain, salt, options) {
  "use strict";

  options = options || {};

  options.timeCost = options.timeCost || 3;
  options.memoryCost = options.memoryCost || 12;
  options.parallelism = options.parallelism || 1;
  options.argon2d = !!options.argon2d;

  if (salt.length > 16) {
    throw new Error("Salt too long, maximum 16 characters.");
  }

  if (options.memoryCost >= 32) {
    throw new Error("Memory cost too high, maximum of 32");
  }

  return bindings.encryptSync(plain, salt, options.timeCost, options.memoryCost,
    options.parallelism, options.argon2d);
};

exports.generateSalt = function (callback) {
  "use strict";

  crypto.randomBytes(16, function (err, buffer) {
    callback(err, buffer.toString());
  });
};

exports.generateSaltSync = function () {
  "use strict";

  return crypto.randomBytes(16).toString();
};

exports.verify = function (encrypted, plain, callback) {
  "use strict";

  return bindings.verify(encrypted, plain, /argon2d/.test(encrypted), callback);
};

exports.verifySync = function (encrypted, plain) {
  "use strict";

  return bindings.verifySync(encrypted, plain, /argon2d/.test(encrypted));
};


@@ -74,16 +74,243 @@
 pto%22);%0A%0A
+var fail = function (message, callback) %7B%0A  var error = new Error(message);%0A%0A  if (typeof(callback) === %22undefined%22) %7B%0A    throw error;%0A  %7D else %7B%0A    process.nextTick(function () %7B%0A      callback(error, null);%0A    %7D);%0A  %7D%0A%7D;%0A%0A
 exports.
@@ -685,63 +685,12 @@
     
-process.nextTick(function () %7B%0A      callback(new Error
+fail
 (%22Sa
@@ -725,31 +725,26 @@
 acters.%22
-)
 , 
-null);%0A    %7D
+callback
 );%0A    r
@@ -797,63 +797,12 @@
     
-process.nextTick(function () %7B%0A      callback(new Error
+fail
 (%22Me
@@ -840,23 +840,18 @@
 32.%22
-)
 , 
-null);%0A    %7D
+callback
 );%0A 
@@ -1314,31 +1314,20 @@
 ) %7B%0A    
-throw new Error
+fail
 (%22Salt t
@@ -1357,24 +1357,36 @@
 racters.%22);%0A
+    return;%0A
   %7D%0A%0A  if (o
@@ -1420,23 +1420,12 @@
     
-throw new Error
+fail
 (%22Me
@@ -1461,16 +1461,28 @@
 f 32%22);%0A
+    return;%0A
   %7D%0A%0A  r

Remove code duplication at failures