/*!
 * algorithms/concat.js - Concat Key Derivation
 *
 * Copyright (c) 2015 Cisco Systems, Inc.  See LICENSE file.
 */
"use strict";

var CONSTANTS = require("./constants.js"),
    sha = require("./sha.js");

function concatDeriveFn(name) {
  name = name.replace("CONCAT-", "");

  // NOTE: no nodejs/webcrypto/fallback model, since ConcatKDF is
  //       implemented using the SHA algorithms

  var fn = function(key, props) {
    props = props || {};

    var keyLen = props.length,
        hashLen = CONSTANTS.HASHLENGTH[name];
    if (!keyLen) {
      return Promise.reject(new Error("invalid key length"));
    }

    // setup otherInfo
    if (!props.otherInfo) {
      return Promise.reject(new Error("invalid otherInfo"));
    }
    var otherInfo = props.otherInfo;

    var op = sha[name].digest;
    var N = Math.ceil(keyLen / hashLen),
        idx = 0,
        okm = [];
    function step() {
      if (N === idx++) {
        return Buffer.concat(okm).slice(0, keyLen);
      }

      var T = Buffer.alloc(4 + key.length + otherInfo.length);
      T.writeUInt32BE(idx, 0);
      key.copy(T, 4);
      otherInfo.copy(T, 4 + key.length);
      return op(T).then(function(result) {
        okm.push(result);
        return step();
      });
    }

    return step();
  };

  return fn;
}

// Public API
// * [name].derive
var concat = {};
[
  "CONCAT-SHA-1",
  "CONCAT-SHA-256",
  "CONCAT-SHA-384",
  "CONCAT-SHA-512"
].forEach(function(name) {
  concat[name] = {
    derive: concatDeriveFn(name)
  };
});

module.exports = concat;
