blob: a2372f9f146ce21e9d8981138161a4e5d1decfd2 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
/**
* @class FunctionSequence to invoke steps in sequence
*
* @param {string} name // TODO(JSDOC).
* @param {Array} steps array of functions to invoke in sequence.
* @param {Object} logger logger.
* @param {function} callback callback to invoke on success.
* @param {function} failureCallback callback to invoke on failure.
* @constructor
*/
function FunctionSequence(name, steps, logger, callback, failureCallback) {
// Private variables hidden in closure
this.currentStepIdx_ = -1;
this.failed_ = false;
this.steps_ = steps;
this.callback_ = callback;
this.failureCallback_ = failureCallback;
this.logger = logger;
this.name = name;
this.onError = this.onError_.bind(this);
this.finish = this.finish_.bind(this);
this.nextStep = this.nextStep_.bind(this);
this.apply = this.apply_.bind(this);
}
/**
* Sets new callback
*
* @param {function} callback new callback to call on succeed.
*/
FunctionSequence.prototype.setCallback = function(callback) {
this.callback_ = callback;
};
/**
* Sets new error callback
*
* @param {function} failureCallback new callback to call on failure.
*/
FunctionSequence.prototype.setFailureCallback = function(failureCallback) {
this.failureCallback_ = failureCallback;
};
/**
* Error handling function, which traces current error step, stops sequence
* advancing and fires error callback.
*
* @param {string} err Error message.
* @private
*/
FunctionSequence.prototype.onError_ = function(err) {
this.logger.vlog('Failed step: ' + this.steps_[this.currentStepIdx_].name +
': ' + err);
if (!this.failed_) {
this.failed_ = true;
this.failureCallback_(err);
}
};
/**
* Finishes sequence processing and jumps to the last step.
* This method should not be used externally. In external
* cases should be used finish function, which is defined in closure and thus
* has access to internal variables of functionsequence.
* @private
*/
FunctionSequence.prototype.finish_ = function() {
if (!this.failed_ && this.currentStepIdx_ < this.steps_.length) {
this.currentStepIdx_ = this.steps_.length;
this.callback_();
}
};
/**
* Advances to next step.
* This method should not be used externally. In external
* cases should be used nextStep function, which is defined in closure and thus
* has access to internal variables of functionsequence.
* @private
* @param {...} var_args // TODO(JSDOC).
*/
FunctionSequence.prototype.nextStep_ = function(var_args) {
if (this.failed_) {
return;
}
if (++this.currentStepIdx_ >= this.steps_.length) {
this.logger.vlog('Sequence ended');
this.callback_.apply(this, arguments);
} else {
this.logger.vlog('Attempting to start step [' +
this.steps_[this.currentStepIdx_].name +
']');
try {
this.steps_[this.currentStepIdx_].apply(this, arguments);
} catch (e) {
this.onError(e.toString());
}
}
};
/**
* This function should be called only once on start, so start sequence pipeline
* @param {...} var_args // TODO(JSDOC).
*/
FunctionSequence.prototype.start = function(var_args) {
if (this.started) {
throw new Error('"Start" method of FunctionSequence was called twice');
}
this.logger.log('Starting sequence with ' + arguments.length + ' arguments');
this.started = true;
this.nextStep.apply(this, arguments);
};
/**
* Add Function object mimics to FunctionSequence
* @private
* @param {*} obj // TODO(JSDOC).
* @param {Array.*} args // TODO(JSDOC).
*/
FunctionSequence.prototype.apply_ = function(obj, args) {
this.start.apply(this, args);
};