var async = require('./async.js')

, abort = require('./abort.js')
;

// API module.exports = iterate;

/**

* Iterates over each job object
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {object} state - current job status
* @param {function} callback - invoked when all elements processed
*/

function iterate(list, iterator, state, callback) {

// store current index
var key = state['keyedList'] ? state['keyedList'][state.index] : state.index;

state.jobs[key] = runJob(iterator, key, list[key], function(error, output)
{
  // don't repeat yourself
  // skip secondary callbacks
  if (!(key in state.jobs))
  {
    return;
  }

  // clean up jobs
  delete state.jobs[key];

  if (error)
  {
    // don't process rest of the results
    // stop still active jobs
    // and reset the list
    abort(state);
  }
  else
  {
    state.results[key] = output;
  }

  // return salvaged results
  callback(error, state.results);
});

}

/**

* Runs iterator over provided job element
*
* @param   {function} iterator - iterator to invoke
* @param   {string|number} key - key/index of the element in the list of jobs
* @param   {mixed} item - job description
* @param   {function} callback - invoked after iterator is done with the job
* @returns {function|mixed} - job abort function or something else
*/

function runJob(iterator, key, item, callback) {

var aborter;

// allow shortcut if iterator expects only two arguments
if (iterator.length == 2)
{
  aborter = iterator(item, async(callback));
}
// otherwise go with full three arguments
else
{
  aborter = iterator(item, key, async(callback));
}

return aborter;

}