'use strict';


var TYPED_OK = (typeof Uint8Array !== 'undefined') &&
  (typeof Uint16Array !== 'undefined') &&
  (typeof Int32Array !== 'undefined');

function _has(obj, key) {
  return Object.prototype.hasOwnProperty.call(obj, key);
}

function assign(obj, objO) {
  // var sources = Array.prototype.slice.call(arguments, 1);
  // while (sources.length) {
  //   var source = sources.shift();
  //   if (!source) { continue; }

  //   if (typeof source !== 'object') {
  //     throw new TypeError(source + 'must be non-object');
  //   }

  //   for (var p in source) {
  //     if (_has(source, p)) {
  //       obj[p] = source[p];
  //     }
  //   }
  // }
  for (var p in objO) {
    if (_has(objO, p)) {
      obj[p] = objO[p];
    }
  }

  return obj;
};


// reduce buffer size, avoiding mem copy
function shrinkBuf(buf, size) {
  if (buf.length === size) { return buf; }
  if (buf.subarray) { return buf.subarray(0, size); }
  buf.length = size;
  return buf;
};


var fnTyped = {
  arraySet: function (dest, src, src_offs, len, dest_offs) {
    if (src.subarray && dest.subarray) {
      dest.set(src.subarray(src_offs, src_offs + len), dest_offs);
      return;
    }
    // Fallback to ordinary array
    for (var i = 0; i < len; i++) {
      dest[dest_offs + i] = src[src_offs + i];
    }
  },
  // Join array of chunks to single array.
  flattenChunks: function (chunks) {
    var i, l, len, pos, chunk, result;

    // calculate data length
    len = 0;
    for (i = 0, l = chunks.length; i < l; i++) {
      len += chunks[i].length;
    }

    // join chunks
    result = new Uint8Array(len);
    pos = 0;
    for (i = 0, l = chunks.length; i < l; i++) {
      chunk = chunks[i];
      result.set(chunk, pos);
      pos += chunk.length;
    }

    return result;
  }
};

var fnUntyped = {
  arraySet: function (dest, src, src_offs, len, dest_offs) {
    for (var i = 0; i < len; i++) {
      dest[dest_offs + i] = src[src_offs + i];
    }
  },
  // Join array of chunks to single array.
  flattenChunks: function (chunks) {
    return [].concat.apply([], chunks);
  }
};


// Enable/Disable typed arrays use, for testing
let Buf8, Buf16, Buf32, arraySet, flattenChunks

if (TYPED_OK) {
  Buf8 = Uint8Array;
  Buf16 = Uint16Array;
  Buf32 = Int32Array;
  arraySet = fnTyped.arraySet;
  flattenChunks = fnTyped.flattenChunks
} else {
  Buf8 = Array;
  Buf16 = Array;
  Buf32 = Array;
  arraySet = fnUntyped.arraySet;
  flattenChunks = fnUntyped.flattenChunks
}



export const utils = {
  assign,
  shrinkBuf,
  Buf8,
  Buf16,
  Buf32,
  arraySet,
  flattenChunks
};
