
'use strict';

/**
 * Module dependencies
 */

var Emitter = require('emitter')
  , Batch = require('batch')
  , AudioContext = require('./context')
  , agent = require('superagent')

function getContext () {
  return (AudioContext.context = AudioContext.context || new AudioContext());
}

/**
 * `AudexBuffer' constructor
 *
 * @api public
 * @param {AudioBuffer} buffer
 * @param {AudioContext} ctx
 * @param {String} type
 */

module.exports = AudexBuffer;
function AudexBuffer (buffer, ctx, type) {
  if (!(this instanceof AudexBuffer)) {
    return new AudexBuffer(buffer, ctx, type);
  }

  if (2 == arguments.length) {
    if ('string' == typeof ctx) {
      type = ctx;
      ctx = getContext();
    }
  } else if (1 == arguments.length) {
    ctx = getContext();
  } else if (0 == arguments.length) {
    throw new Error("Expecting atleast 2 arguments.");
  }

  if (!(buffer instanceof AudioBuffer)) {
    throw new TypeError("Expecting an instance of `AudioBuffer'.");
  } else if (!(ctx instanceof AudioContext)) {
    throw new TypeError("Expecting an instance of `AudioContext'.");
  }

  this.type = 'string' == typeof type ? type : AudexBuffer.DEFAULT_MIMETYPE;
  this.buffer = buffer;
  this.source = ctx.createBufferSource();
  this.context = ctx;

  Object.defineProperty(this, 'length', {
    get: function () {
      return buffer.length;
    }
  });
}

// Inherit from `Emitter'
Emitter(AudexBuffer.prototype);

/**
 * `AudexBuffer' singleton context
 *
 * @api public
 */

AudexBuffer.context = null;

/**
 * Default `AudexBuffer' instance mimetype
 *
 * @api public
 */

AudexBuffer.DEFAULT_MIMETYPE = 'audio/mpeg';

/**
 * Concats multple `AudexBuffer' instance
 * buffers into a single buffer
 *
 * @api public
 * @static
 * @param {Object} opts - optional
 * @param {Array} buffers
 */

AudexBuffer.concat = function (opts, buffers) {
  if (1 == arguments.length) {
    buffers = opts;
    opts = {};
  }

  if (false == Array.isArray(buffers)) {
    throw new TypeError("Expecting an array of buffers.");
  }

  var channels = opts.channels || 2;
  var channel = null;
  var offset = 0;
  var audio = null;
  var rate = 0;
  var size = 0;
  var curr = null;
  var ctx = null;
  var buf = null;
  var len = buffers.length;
  var i = 0;
  var j = 0;

  size = buffers.reduce(function (a, b) {
    return a + b.length;
  }, 0);


  ctx = getContext();
  rate = ctx.sampleRate;
  audio = ctx.createBuffer(channels, size, rate);
  buf = new AudexBuffer(audio, ctx);

  for (;i < channels; ++i) {
    // `TypedArray' offset
    offset = 0;

    for (j = 0; j < len; ++j) {
      // current channel in final audio buffer
      channel = audio.getChannelData(i);

      // current buffer
      curr = buffers[j];

      // append current audio chanel to the
      // final audio buffer
      channel.set(curr.buffer.getChannelData(i), offset);

      // advance offset with current buffer length
      offset += curr.buffer.length;
    }
  }

  return buf;
};

/**
 * Loads a buffer from a source URL
 * and calls `fn' with an instance of
 * a `AudexBuffer' object
 *
 * @api public
 * @static
 * @param {String} url
 * @param {String} type
 * @param {Function} fn
 */

AudexBuffer.load = function (url, type, fn) {
  var buf = null;
  var ctx = getContext();
  var req = new XMLHttpRequest();
  var res = null;

  // init
  req.responseType = 'arraybuffer';
  req.open('GET', url, true);

  // events
  req.onload = onload;
  req.onerror = onerror;

  // request
  try { req.send(); }
  catch (e) { return fn(e); }

  function onload (e) {
    var status = e.target.status;

    res = e.target.response;

    if (null == res) {
      return fn(new Error("Failed to parse response"));
    } else if (status >= 400 && status < 500) {
      return fn(new Error(status + ': '+ e.target.statusText));
    }

    ctx.decodeAudioData(res, ondecoded);
    function ondecoded (buffer) {
      if (null == buffer) {
        return fn(new Error("Failed to decode audio data."));
      }

      // create buffer
      buf = new AudexBuffer(buffer, ctx, type);

      // callback
      fn(null, buf);
    }
  }

  function onerror (err) {
    fn(err);
  }
};

AudexBuffer.prototype.slice = function () {

};

AudexBuffer.prototype.copy = function () {

};


@@ -1757,57 +1757,57 @@
 am %7B
-Object%7D opts - optional%0A * @param %7BArray%7D buffers
+Array%7D buffers%0A * @param %7BObject%7D opts - optional
 %0A */
@@ -1843,20 +1843,20 @@
 on (
-opts, 
 buffer
+s, opt
 s) %7B
@@ -1891,28 +1891,8 @@
 ) %7B%0A
-    buffers = opts;%0A
     
@@ -2100,16 +2100,22 @@
 ar audio
+Buffer
  = null;
@@ -2121,17 +2121,23 @@
 ;%0A  var 
-r
+sampleR
 ate = 0;
@@ -2143,17 +2143,28 @@
 ;%0A  var 
-s
+totalBufferS
 ize = 0;
@@ -2225,17 +2225,20 @@
 ;%0A  var 
-l
+bufL
 en = buf
@@ -2279,17 +2279,28 @@
 = 0;%0A%0A  
-s
+totalBufferS
 ize = bu
@@ -2326,12 +2326,22 @@
 on (
-a, b
+total, currBuf
 ) %7B%0A
@@ -2355,13 +2355,23 @@
 urn 
-a + b
+total + currBuf
 .len
@@ -2385,17 +2385,16 @@
 %7D, 0);%0A%0A
-%0A
   ctx = 
@@ -2409,17 +2409,23 @@
 xt();%0A  
-r
+sampleR
 ate = ct
@@ -2445,16 +2445,22 @@
 %0A  audio
+Buffer
  = ctx.c
@@ -2485,15 +2485,32 @@
 ls, 
-size, r
+totalBufferSize, sampleR
 ate)
@@ -2540,16 +2540,22 @@
 er(audio
+Buffer
 , ctx);%0A
@@ -2648,17 +2648,20 @@
  0; j %3C 
-l
+bufL
 en; ++j)
@@ -2731,16 +2731,22 @@
  = audio
+Buffer
 .getChan

reorder params / make variables more specific