/**
* @fileoverview Client layer for DS. The DS stack will roughly consist of
* Layer 1: GUI, Layer 2: Client, Layer 3: Server
*
* NOTE: All public/exported functions in this module should implement runtime
* type checking for arguments to allow easier debugging when calling
* from uncompiled code.
*
* @author anders.rejdebrant@spark-vision.com (Anders Rejdebrant)
*/
goog.provide('spv.ds.DsClient');
goog.require('spv.assert');
goog.require('spv.RequestQueue');
goog.require('spv.ds.Config');
goog.require('spv.ds.ConfigLoadResult');
goog.require('spv.ds.Disclaimer')
goog.require('spv.ds.DsClientSettings');
goog.require('spv.ds.FacebookShareData');
goog.require('spv.ds.FreshConfig');
goog.require('spv.ds.ImageParams');
goog.require('spv.ds.ImageResult');
goog.require('spv.ds.ImageSerieInfo');
goog.require('spv.ds.IntroPage');
goog.require('spv.ds.MenuQuery');
goog.require('spv.ds.PresentationStructureQuery');
goog.require('spv.ds.SavedConfig');
goog.require('spv.ds.SessionStateUpdate');
goog.require('spv.ds.Suggestion');
goog.require('spv.ds.Summary');
goog.require('spv.ds.assert');
goog.require('spv.ds.impl.GoalStateResolver');
goog.require('spv.ds.impl.IPPNovaAdaptor');
goog.require('spv.ds.impl.IDsProtocol');
goog.require('spv.ds.impl.SessionInitData');
goog.require('spv.ds.impl.SessionState');
goog.require('spv.ds.ipprot_nova.input.BopReadMoreMode');
/**
* DsClient provides a layer of abstraction between GUI code and
* session-/protocol-handling.
*
* The configurator system is stateful. Session state is shared between server
* and client, this is a source of complexity and can hopefully be removed at
* some point in the future. DsClient provides synchronization of session state
* between server and client by centralizing management of the shared state
* inside this class.
*
* Member functions are stateful if the member function name begins with
* "session". Other member functions are state- and session-less and can be
* called at any time, in any order.
*
* Most session dependent functions also require a loaded configuration.
* Preconditions should be documented for each member function in this class.
*
* The configurator system can be simplified as the following three phases:
* A. The user finds the configurator application on the web or in the showroom.
* B. The user choose and change the product components (called items) until
* the user is satisfied or leaved the application.
* C. The user saves the configuration for a later time or choose to place an
* order or request a sales contact for the built configuration.
*
* Technical usage example 1, Starting a new configuration session and
* interacting with the user. (Step-by-step example of phase B):
*
* 1. Construct an instance of spv.ds.Client
* 2. Call sessionInit
* 3. Call getIntroPage to retrieve the available start configurations
* 4. Generate images for the start configurations using getConfigImage
* 5. Display the available start configuration images to the user using the
* appropriate techniques for the GUI implementation.
* 6. The user chooses a start configuration
* 7. Send that start configuration to sessionLoadConfig
* 8. On success, call sessionGetRootMenuItems and sessionGetImage
* 9. Populate the GUI root menu with menu items and wait for the image response
* 10. On image success, load and display the configuration image
* 11. The user makes a choice about which menu to open
* 12. Call sessionToggleItem for the user chosen MenuItem
* (both menus and product components are MenuItems)
* 13. On success, call sessionGetStateUpdate to populate the currently open
* menu with menu items.
* 14. The user clicks an item in the currently open menu, send that MenuItem to
* sessionToggleItem and handle response.
* 15. On success, update the currently open menu with new MenuItems (most menu
* items will usually be unchanged, but some may change state and some may
* disappear while others may be added). Call sessionGetImage to get the new
* configuration image and wait for response.
* 16. On image success, load and display the configuration image
* 17. The user clicks a new item and the sessionToggleItem cycle continues
* until the user closes the application or decides to place an order for
* the built configuration. (this step is customized action for each
* configurator application, eg. cars and bathroom products require
* different types of shopping cart solutions)
*
*
*
*
* @export
* @constructor
* @param {!string} service_url
* @param {!spv.ds.DsClientSettings=} in_settings
*/
spv.ds.DsClient = function(service_url, in_settings)
{
// Default settings.
var default_settings = new spv.ds.DsClientSettings();
default_settings.use_jsonp = false;
default_settings.debug_print = false;
/** @type {!spv.ds.DsClientSettings} */
var settings = in_settings ? default_settings.overloadWith( in_settings ) : default_settings;
var valid_settings = new spv.ds.DsClientValidatedSettings( settings );
/**
* @protected
* @type {spv.ds.impl.IDsProtocol}
*/
this._protocol = new spv.ds.impl.IPPNovaAdaptor(service_url, valid_settings.use_jsonp);
/**
* @private
* @type {boolean}
*/
this._debug_print = valid_settings.debug_print;
/**
* @private
* @type {boolean}
*/
this._session_is_initialized = false;
/**
* @private
* @type {string}
*/
this._language = "";
/**
* @private
* @type {null|string}
*/
this._session_id = null;
/**
* @protected
* @type {spv.ds.impl.SessionState}
*/
this._session_state = null;
/**
* @protected
* @type {spv.RequestQueue}
*/
this._requestQueue = new spv.RequestQueue();
/**
* @private
* @type {?function( Error )}
*/
this._on_unauthorized_session = valid_settings.on_unauthorized_session;
/**
* @private
* @type {?function( Error )}
*/
this._on_service_unavailable = valid_settings.on_service_unavailable;
/**
* @private
* @type {?function( Error )}
*/
this._on_service_failure = valid_settings.on_service_failure;
/**
* @private
* @type {number}
*/
this._session_ttl = valid_settings.session_ttl;
/**
* @private
* @type {string}
*/
this._origin = valid_settings.origin;
/**
* @private
* @type {string}
*/
this._initial_category = valid_settings.initial_category;
/**
* @private
* @type {string}
*/
this._item_interpreter_options = valid_settings.item_interpreter_options;
};
/**
* Get the session id or throw if null
*
* @export
* @return {string}
*/
spv.ds.DsClient.prototype.getSessionId = function()
{
if (null == this._session_id)
{
throw new Error('Session id is null, session is not initialized.');
}
return this._session_id;
};
/**
* Create a ImageParams instance with default values, however, defaults are
* likely not good enough for most contexts.
*
* Preconditions: None.
*
* @export
* @return {spv.ds.ImageParams}
*/
spv.ds.DsClient.prototype.constructDefaultImageParams = function()
{
return new spv.ds.ImageParams();
};
/**
* Requests an image for a serialized configuration.
*
* Preconditions: None.
*
* @export
* @param {spv.ds.Config} conf
* @param {spv.ds.ImageParams} img_params
* @param {function(spv.ds.ImageResult)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.getConfigImage = function(
conf,
img_params,
on_success,
on_failure)
{
spv.ds.assert.isConfig(conf, 'conf');
spv.ds.assert.isImageParams(img_params, 'img_params');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
this._protocol.getConfigImage(
conf,
img_params,
on_success,
this.errorHandler(on_failure) );
};
/**
* Requests the "Intro page" data including available start-configurations,
* typically one config for each car model.
*
* Preconditions: None.
*
* @export
* @param {function(spv.ds.IntroPage)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.getIntroPage = function(on_success, on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
this._protocol.getIntroPage(
on_success,
this.errorHandler(on_failure) );
};
/**
* @param {string} item_id
* @param {string} model
* @param {string} category
* @param {function(Array.<spv.ds.ReadMoreResource>)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.getReadMore = function(
item_id,
model,
category,
language,
on_success,
on_failure)
{
this._protocol.getReadMore(
item_id,
model,
category,
language,
on_success,
on_failure );
};
/**
* @param {Array<string>} item_ids
* @param {Array<string>} resource_keys
* @param {string} category
* @param {string} model
* @param {string} language
* @param {string} model_group
* @param {function(Object<string,spv.ds.ItemResources>)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.getItemResources = function(
item_ids,
resource_keys,
category,
model,
language,
model_group,
on_success,
on_failure)
{
spv.assert.isArray(item_ids, 'item_ids');
spv.assert.isArray(resource_keys, 'resource_keys');
spv.assert.isString(category, 'category');
spv.assert.isString(model, 'model');
spv.assert.isString(language, 'language');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
this._protocol.getItemResources(
item_ids,
resource_keys,
category,
model,
language,
model_group,
on_success,
on_failure);
}
/**
* Gets all configurations stored in the database by the given username.
* This is a heavy operation and is included here for utility purposes.
*
* @export
* @param {string} username
* @param {function(Array.<spv.ds.SavedConfig>)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.getUserConfigList = function(
username,
on_success,
on_failure )
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
this._protocol.getUserConfigList(
username,
on_success,
this.errorHandler(on_failure) );
};
/**
* @export
* @param {Array.<string>} group_ids
* @param {function()} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionAddGuiGroupSubscriptions = function(
group_ids,
on_success,
on_failure )
{
var that = this;
this._requestQueue.push(function (wrap) {
that._protocol.sessionAddGuiGroupSubscriptions(
that.getSessionId(),
group_ids,
wrap(on_success),
wrap(that.errorHandler(on_failure)) );
});
};
/**
* @export
* @param {function()} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.getBuildInfo = function(
on_success,
on_failure )
{
var that = this;
this._requestQueue.push(function(wrap) {
that._protocol.getBuildInfo(
wrap(on_success),
wrap(that.errorHandler(on_failure)) );
});
};
/**
* @export
* @param {function()} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionClearGuiGroupSubscriptions = function(
on_success,
on_failure )
{
var that = this;
this._requestQueue.push(function(wrap) {
that._protocol.sessionClearGuiGroupSubscriptions(
that.getSessionId(),
wrap(on_success),
wrap(that.errorHandler(on_failure)) );
});
};
/**
* Apply a configuration change suggestion on the current configuration.
*
* Preconditions: Initialized session, loaded configuration, caller code has a
* valid instance of spv.ds.Suggestion retrieved by calling
* sessionToggleItem, no requests that modify the session
* configuration has been dispatched between suggestion
* construction and the call to this function.
*
* @export
* @param {spv.ds.Suggestion} suggestion
* The suggestion to be applied to the current configuration.
* @param {Function} on_success
* Called when the suggestion has been successfully applied.
* @param {function(Error)} on_failure
* Called on any kind of failure.
*/
spv.ds.DsClient.prototype.sessionApplySuggestion = function(
suggestion,
on_success,
on_failure)
{
spv.ds.assert.isSuggestion(suggestion, 'suggestion');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
this.assertInitializedSessionWithConfig();
var that = this;
// TODO: DSClient sessionBip (@protected), since there's a bit of code duplication here.
/** @param {spv.ds.SessionStateUpdate} ssu
* @param {spv.ds.impl.AuxData} aux_data */
var on_success_wrapper = function(ssu, aux_data)
{
that._session_state.update(ssu, aux_data);
on_success();
};
this._requestQueue.push(function(wrap) {
that._protocol.sessionBip(
that.getSessionId(),
'',
suggestion.internal_data,
that.getLanguage(),
wrap(on_success_wrapper),
wrap(that.errorHandler(on_failure)));
});
};
/**
* @param {spv.ds.FlexImageParameters} input
* @param {function(spv.ds.FlexImageResult)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGetFlexImage = function(
input,
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSessionWithConfig();
that._protocol.sessionGetFlexImage(
that.getSessionId(),
input,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Create a pdf using current session state and returns the pdf url through a
* callback if a pdf was generated successfully.
*
* Preconditions: Initialized session, loaded configuration.
*
* @export
* @param {function(string)} on_success Callback taking the generated pdf url
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGeneratePdf = function(
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSessionWithConfig();
that._protocol.sessionGeneratePdf(
that.getSessionId(),
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Get the root menu items for the current configuration
*
* Preconditions: Initialized session, loaded config.
*
* @export
* @return {Array.<spv.ds.MenuItem>}
*/
spv.ds.DsClient.prototype.sessionGetRootMenuItems = function()
{
this.assertInitializedSessionWithConfig();
return this._session_state.getRootMenuItems();
};
/**
* Requests the current session config
*
* Available encodings are:
* "" : internal encoding, only for debug
*
* Preconditions: Initialized session, loaded config.
*
* @export
* @param {string} encoding
* @param {function(spv.ds.Config)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGetConfig = function(
encoding,
on_success,
on_failure)
{
spv.assert.isString(encoding, 'encoding');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSessionWithConfig();
that._protocol.sessionGetConfig(
that.getSessionId(),
encoding,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Get the saved configs for the logged in user
*
* Preconditions: Initialized session, logged in user.
*
* @export
* @param {function(Array.<string>)} on_success
* A callback taking an array of names of saved configurations.
* The configuration names can be used to remove or load configs for the
* logged in user by sessionRemoveConfigByName and
* sessionLoadConfigByName.
*
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGetConfigNames = function(
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionGetConfigNames(
that.getSessionId(),
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Get 'short_text' text for item_id or empty string on failure
*
* Texts are configuration dependent.
* In practice updating texts is only needed after loading a configuration, not
* when simply toggling an item in the configuration.
*
* Preconditions: Initialized session, loaded configuration.
*
* @export
* @param {string} item_id
* @return {string}
*/
spv.ds.DsClient.prototype.sessionGetShortText = function(item_id)
{
spv.assert.isNonEmptyString(item_id, 'item_id');
this.assertInitializedSessionWithConfig();
return this._session_state.getShortText(item_id);
};
/**
* Get 'medium_text' text for item_id or empty string on failure
*
* Texts are configuration dependent.
* In practice updating texts is only needed after loading a configuration, not
* when simply toggling an item in the configuration.
*
* Preconditions: Initialized session, loaded configuration.
*
* @export
* @param {string} item_id
* @return {string}
*/
spv.ds.DsClient.prototype.sessionGetMediumText = function(item_id)
{
spv.assert.isNonEmptyString(item_id, 'item_id');
this.assertInitializedSessionWithConfig();
return this._session_state.getMediumText(item_id);
};
/**
* Get 'long_text' text for item_id or empty string on failure
*
* Texts are configuration dependent.
* In practice updating texts is only needed after loading a configuration, not
* when simply toggling an item in the configuration.
*
* Preconditions: Initialized session, loaded configuration.
*
* @export
* @param {string} item_id
* @return {string}
*/
spv.ds.DsClient.prototype.sessionGetLongText = function(item_id)
{
spv.assert.isNonEmptyString(item_id, 'item_id');
this.assertInitializedSessionWithConfig();
return this._session_state.getLongText(item_id);
};
/**
* @export
* @param {string} item_id
* @return {string}
*/
spv.ds.DsClient.prototype.sessionGetCampaignText = function(item_id)
{
spv.assert.isNonEmptyString(item_id,'item_id');
this.assertInitializedSessionWithConfig();
return this._session_state.getCampaignText(item_id)
}
/**
* Gets the disclaimer to be displayed when the configurator is started.
*
* @export
* @return {spv.ds.Disclaimer}
*/
spv.ds.DsClient.prototype.sessionGetIntroDisclaimer = function()
{
var state_update = this.sessionGetStateUpdate();
var disclaimer_id = "INTRO_DISCLAIMER";
return new spv.ds.Disclaimer( this.sessionGetShortText( disclaimer_id ) );
};
/**
* Get the disclaimer specific for a model.
*
* If no model id is passed, it'll default to the active configuration's model.
*
* @export
* @param {string=} model_id
* @return {spv.ds.Disclaimer}
*/
spv.ds.DsClient.prototype.sessionGetModelDisclaimer = function( model_id )
{
var id = model_id || this.sessionGetStateUpdate().model_id;
var disclaimer_id = id + "_DISCLAIMER";
return new spv.ds.Disclaimer( this.sessionGetShortText( disclaimer_id ) );
};
/**
* Get base urls needed for most HTTP GET paths to images
*
* Preconditions: Initialized session.
*
* @export
* @return {spv.ds.UrlSettings}
*/
spv.ds.DsClient.prototype.sessionGetUrlSettings = function()
{
this.assertInitializedSession();
return this._session_state.getUrlSettings();
};
/**
* Get image serie info for the current configuration
*
* Preconditions: Initialized session, loaded configuration.
*
* @export
* @return {Array.<spv.ds.ImageSerieInfo>}
*/
spv.ds.DsClient.prototype.sessionGetImageSerieInfos = function()
{
this.assertInitializedSessionWithConfig();
return this._session_state.getImageSerieInfos();
};
/**
* Get complete item info for items by item id
*
* Preconditions: Initialized session, loaded configuration.
*
* @export
* @param {Array.<string>} item_ids
* @param {function(Array.<spv.ds.MenuItem>)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGetItemInfo = function(
item_ids,
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSessionWithConfig();
that._protocol.sessionGetItemInfo(
that.getSessionId(),
item_ids,
that.getLanguage(),
wrap(on_success),
wrap(that.errorHandler(on_failure)) );
})
};
/**
* Gets an URL to a zipfile containing the images.
*
* @export
* @param {number} serie_index
* @param {number} frame_index
* @param {string} file_type
* @param {boolean} separate_background
* @param {boolean} separate_shadow
* @param {boolean} all_frames
* @param {boolean} use_hd
* @param {number} image_width
* @param {number} image_height
* @param {function(string)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGetMediaKit = function(
serie_index,
frame_index,
file_type,
separate_background,
separate_shadow,
all_frames,
use_hd,
image_width,
image_height,
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that._protocol.sessionGetMediaKit(
that.getSessionId(),
serie_index,
frame_index,
file_type,
separate_background,
separate_shadow,
all_frames,
use_hd,
image_width,
image_height,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Requests the text, images etc used for facebook sharing.
*
* Preconditions: Initialized session, loaded configuration.
*
* @export
* @param {function(spv.ds.FacebookShareData)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGetFacebookShareData = function(
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSessionWithConfig();
that._protocol.sessionGetFacebookShareData(
that.getSessionId(),
wrap(on_success),
wrap(that.errorHandler(on_failure)) );
});
};
/**
* Requests the most recently built car configurations.
*
* @export
* @param {number} limit Max number of configs in result
* @param {number} scale_width
* @param {number} scale_height
* @param {function(Array.<spv.ds.FreshConfig>)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.getFreshConfigs = function(
limit,
scale_width,
scale_height,
on_success,
on_failure)
{
spv.assert.isNumber(limit, 'limit');
spv.assert.isNumber(scale_width, 'scale_width');
spv.assert.isNumber(scale_height, 'scale_height');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
this._protocol.getFreshConfigs(
limit,
scale_width,
scale_height,
on_success,
this.errorHandler(on_failure) );
};
/**
* Requests the most recently built car configurations.
*
* @deprecated
* @export
* @param {number} limit Max number of configs in result
* @param {number} scale_width
* @param {number} scale_height
* @param {function(Array.<spv.ds.FreshConfig>)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGetFreshConfigs = function(
limit,
scale_width,
scale_height,
on_success,
on_failure)
{
spv.assert.isNumber(limit, 'limit');
spv.assert.isNumber(scale_width, 'scale_width');
spv.assert.isNumber(scale_height, 'scale_height');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionGetFreshConfigs(
that.getSessionId(),
limit,
scale_width,
scale_height,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Builds an image for the current configuration state in this session.
*
* Preconditions: Initialized session, loaded configuration.
*
* @export
* @param {spv.ds.ImageParams} img_params
* @param {function(spv.ds.ImageResult)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGetImage = function(
img_params,
on_success,
on_failure)
{
spv.ds.assert.isImageParams(img_params, 'img_params');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSessionWithConfig();
that._protocol.sessionGetImage(
that.getSessionId(),
img_params,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Get the summary for the current session and configuration
*
* Preconditions: Initialized session, loaded configuration.
*
* @export
* @param {function(spv.ds.Summary)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGetSummary = function(on_success, on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSessionWithConfig();
that._protocol.sessionGetSummary(
that.getSessionId(),
wrap(on_success),
wrap(that.errorHandler(on_failure)) );
});
};
/**
* Returns the auxiliary data arriving with the latest bop.
*
* Preconditions: Initialized session, loaded configuration.
*
* @protected
* @return {Object.<string, Object>}
*/
spv.ds.DsClient.prototype.sessionGetAuxiliaryData = function()
{
this.assertInitializedSessionWithConfig();
return this._session_state.getAuxiliaryData();
};
/**
* Get the last state update. Call this function on successful load of configs
* or on successful sessionToggleItem.
*
* Preconditions: Initialized session, loaded configuration.
*
* @export
* @return {spv.ds.SessionStateUpdate}
*/
spv.ds.DsClient.prototype.sessionGetStateUpdate = function()
{
this.assertInitializedSessionWithConfig();
return this._session_state.getUpdate();
};
/**
* Requests an image for a saved configuration
*
* Preconditions: Initialized session, logged in user.
*
* @export
* @param {string} config_name
* @param {spv.ds.ImageParams} img_params
* @param {function(spv.ds.ImageResult)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGetUserConfigImage = function(
config_name,
img_params,
on_success,
on_failure)
{
spv.assert.isNonEmptyString(config_name, 'config_name');
spv.ds.assert.isImageParams(img_params, 'img_params');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionGetUserConfigImage(
that.getSessionId(),
config_name,
img_params,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* @param {string} filter_name
* @param {spv.ds.PresentationStructureQuery} query
* @param {function(spv.ds.PresentationStructure)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGetPresentationStructure = function(
filter_name,
query,
on_success,
on_failure )
{
var that = this;
this._requestQueue.push(function(wrap) {
that._protocol.sessionGetPresentationStructure(
that.getSessionId(),
filter_name,
query,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
}
/**
* Initialize session.
* This must be called before calling any other member function with "session".
* For most other session calls a configuration needs to be loaded as well.
*
* This is not done in the constructor in order to allow state-/session-less
* calls without initializing a session.
*
* Preconditions: None.
*
* @export
* @param {string} menu_query
* @param {spv.ds.ipprot_nova.input.BopReadMoreMode} readmore_mode
* @param {function(spv.ds.IntroPage)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionInit = function(
menu_query,
readmore_mode,
on_success,
on_failure)
{
spv.assert.isString(menu_query, 'menu_query');
spv.assert.isNonEmptyString(readmore_mode, 'readmore_mode');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
/**
* @param {spv.ds.impl.SessionInitData} init_data
*/
var on_success_wrapper = function(init_data)
{
that._session_state = new spv.ds.impl.SessionState(init_data);
that._session_is_initialized = true;
that._session_id = init_data.session_id;
on_success(init_data.intro_page);
};
this._requestQueue.clear();
this._requestQueue.push( function(wrap) {
that._protocol.sessionCreate(
menu_query,
readmore_mode,
that.getLanguage(),
that._session_ttl,
that._origin,
that._initial_category,
that._item_interpreter_options,
wrap(on_success_wrapper),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Initialize with existing session.
* Used instead of sessionInit.
*
* Preconditions: Client not initialized.
*
* @export
* @param {string} session_id
* @param {function(spv.ds.IntroPage)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionResume = function(
session_id,
on_success,
on_failure)
{
spv.assert.isString( session_id, 'session_id' );
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
if (this._session_is_initialized)
{
throw new Error("Cannot resume session when the client is already initialized.");
}
this._requestQueue.clear();
this._requestQueue.push( function(wrap) {
that._protocol.sessionResume(
session_id,
that.getLanguage(),
wrap(on_success_wrapper),
wrap(that.errorHandler(on_failure)) );
});
/**
* @param {spv.ds.impl.SessionInitData} init_data
*/
function on_success_wrapper(init_data)
{
that._session_state = new spv.ds.impl.SessionState(init_data);
that._session_is_initialized = true;
that._session_id = init_data.session_id;
on_success(init_data.intro_page);
}
};
/**
* Loads a configuration into the current session and replaces to current
* configuration state.
*
* Preconditions: Initialized session.
*
* @export
* @param {spv.ds.Config} config
* @param {function(spv.ds.ConfigLoadResult)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionLoadConfig = function(
config,
on_success,
on_failure)
{
spv.ds.assert.isConfig(config, 'config');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
/**
* @param {spv.ds.ConfigLoadResult} result
* @param {spv.ds.SessionStateUpdate} ssu
* @param {spv.ds.impl.AuxData} aux_data
*/
var on_success_wrapper = function(result, ssu, aux_data)
{
that._session_state.update(ssu, aux_data);
on_success(result);
};
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionLoadConfig(
that.getSessionId(),
config,
that.getLanguage(),
wrap(on_success_wrapper),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Loads a configuration into the current session and replaces to current
* configuration state.
*
* Preconditions: Initialized session.
*
* @export
* @param {spv.ds.Config} config
* @param {function(spv.ds.ConfigLoadResult)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionLoadConfigMemorizeAll = function(
config,
on_success,
on_failure)
{
spv.ds.assert.isConfig(config, 'config');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
/**
* @param {spv.ds.ConfigLoadResult} result
* @param {spv.ds.SessionStateUpdate} ssu
* @param {spv.ds.impl.AuxData} aux_data
*/
var on_success_wrapper = function(result, ssu, aux_data)
{
that._session_state.update(ssu, aux_data);
on_success(result);
};
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionLoadConfigMemorizeAll(
that.getSessionId(),
config,
that.getLanguage(),
wrap(on_success_wrapper),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Loads a configuration into the current session and replaces to current
* configuration state. The config is referenced by it's name retrieved from
* sessionGetConfigNames.
*
* Preconditions: Initialized session, logged in user.
*
* @export
* @param {string} config_name
* @param {function(spv.ds.ConfigLoadResult)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionLoadConfigByName = function(
config_name,
on_success,
on_failure)
{
spv.assert.isNonEmptyString(config_name, 'config_name');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
/**
* @param {spv.ds.ConfigLoadResult} result
* @param {spv.ds.SessionStateUpdate} ssu
* @param {spv.ds.impl.AuxData} aux_data
*/
var on_success_wrapper = function(result, ssu, aux_data)
{
that._session_state.update(ssu, aux_data);
on_success(result);
};
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionLoadConfigByName(
that.getSessionId(),
config_name,
wrap(on_success_wrapper),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Loads a configuration from the "public" database into the current session
* replacing the current configuration state.
*
* "Public Configs" are anonymous configurations saved without any user
* information that can be loaded by a unique key.
*
* Preconditions: Initialized session.
*
* @export
* @param {string} public_config_id
* @param {function(spv.ds.ConfigLoadResult)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionLoadPublicConfig = function(
public_config_id,
on_success,
on_failure)
{
spv.assert.isNonEmptyString(public_config_id, 'public_config_id');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
/**
* @param {spv.ds.ConfigLoadResult} result
* @param {spv.ds.SessionStateUpdate} ssu
* @param {spv.ds.impl.AuxData} aux_data
*/
var on_success_wrapper = function(result, ssu, aux_data)
{
that._session_state.update(ssu, aux_data);
on_success(result);
};
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionLoadPublicConfig(
that.getSessionId(),
public_config_id,
wrap(on_success_wrapper),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Save the current configuration for the logged in user as a public config.
* The generated name is returned as a string to the on_success function.
*
* Preconditions: Initialized session, loaded configuration, logged in user.
*
* @export
* @param {function(string)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.generatePublicConfig = function(
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSessionWithConfig();
that._protocol.sessionGeneratePublicConfig(
that.getSessionId(),
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* User login
* Password may be required depending on backend settings.
*
* May create the user if it doesn't exist, depending on backend settings.
*
* success and failure callbacks are always at the end.
*
* sessionLogin( session_id, name, password, success, failure );
* sessionLogin( session_id, name, success, failure );
*
* Preconditions: Initialized session.
*
* @export
* @param {string} user_name
* @param {string|Function} password_or_success
* @param {Function|function(Error)} success_or_failure
* @param {function(Error)=} failure
*/
spv.ds.DsClient.prototype.sessionLogin = function(
user_name,
password_or_success,
success_or_failure,
failure )
{
/** @type {Function} **/
var on_success;
/** @type {function(Error)} **/
var on_failure;
/** @type {string} **/
var password;
/* Argument swapping to make password an optional parameter.
* (For backwards compatibility)
*/
if( arguments.length === 3 )
{
password = "";
on_success = /** @type {Function} */ (password_or_success);
on_failure = /** @type {function(Error)} */ (success_or_failure);
}
else if( arguments.length === 4 )
{
password = /** @type {string} */ (password_or_success);
on_success = /** @type {Function} */ (success_or_failure);
on_failure = /** @type {function(Error)} */ (failure);
}
spv.assert.isNonEmptyString(user_name, 'user_name');
spv.assert.isString(password, 'password');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionLogin(
that.getSessionId(),
user_name,
password,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Logout the user from the session.
*
* @export
* @param {Function} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionLogout = function(
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionLogout(
that.getSessionId(),
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Create a new user in the user database.
*
* May not be required to create a user, depending on backend settings.
*
* @export
* @param {string} user_name
* @param {string} password
* @param {function(number)} on_success
* @param {function(Error)} on_failure
* @param {string=} language
*/
spv.ds.DsClient.prototype.sessionCreateUser = function(
user_name,
password,
on_success,
on_failure,
language)
{
spv.assert.isNonEmptyString(user_name, 'user_name');
spv.assert.isNonEmptyString(password, 'password');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionCreateUser(
that.getSessionId(),
user_name,
password,
wrap(on_success),
wrap(that.errorHandler(on_failure)),
language);
});
}
/**
* Sets a users GDPR consent in the user database.
*
* @export
* @param {number} user_id
* @param {string} consent_id
* @param {string} consent_text
* @param {Function} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionSetUserConsent = function(
user_id,
consent_id,
consent_text,
on_success,
on_failure)
{
spv.assert.isNumber(user_id, 'user_id');
spv.assert.isNonEmptyString(consent_id, 'consent_id');
spv.assert.isNonEmptyString(consent_text, 'consent_text');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionSetUserConsent(
user_id,
consent_id,
consent_text,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
}
/**
* Gets a users GDPR consents from a session id. Used when existing user logs in.
*
* @export
* @param {string} session_id
* @param {function(Array.<spv.ds.ipprot_nova.output.UserConsent>)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGetUserConsents = function(
session_id,
on_success,
on_failure)
{
spv.assert.isNonEmptyString(session_id, 'session_id');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionGetUserConsents(
session_id,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
}
/**
* Sets a users GDPR consent from session id in the user database.
*
* @export
* @param {string} session_id
* @param {string} consent_id
* @param {string} consent_text
* @param {Function} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionSetUserConsentSession = function(
session_id,
consent_id,
consent_text,
on_success,
on_failure)
{
spv.assert.isNonEmptyString(session_id, 'session_id');
spv.assert.isNonEmptyString(consent_id, 'consent_id');
spv.assert.isNonEmptyString(consent_text, 'consent_text');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionSetUserConsentSession(
session_id,
consent_id,
consent_text,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
}
/**
* Check with backend if the session has a logged in user.
*
* Preconditions: Initialized session.
*
* @export
* @param {function(boolean)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionHasLoggedInUser = function(
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionHasLoggedInUser(
that.getSessionId(),
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Precondition: Initialized session
*
* @export
* @param {string} password_form_url
* @param {string} user_name
* @param {string} language
* @param {Function} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionSendResetPasswordMail = function(
password_form_url,
user_name,
language,
on_success,
on_failure)
{
spv.assert.isNonEmptyString(password_form_url, 'password_form_url');
spv.assert.isNonEmptyString(user_name, 'user_name');
spv.assert.isNonEmptyString(language, 'language');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionSendResetPasswordMail(
that.getSessionId(),
password_form_url,
user_name,
language,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
}
/**
* Resets user password.
*
* Token is retrieved via email, sent by sessionSendResetPasswordMail.
*
* @export
* @param {string} token
* @param {string} new_password
* @param {Function} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.resetPassword = function(
token,
new_password,
on_success,
on_failure)
{
spv.assert.isNonEmptyString(token, 'token');
spv.assert.isNonEmptyString(new_password, 'new_password');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
this._protocol.resetPassword( token, new_password, on_success, on_failure );
}
/**
* Remove a saved configuration for the logged in user
*
* Preconditions: Initialized session, logged in user.
*
* @export
* @param {string} config_name Name retrieved by sessionGetConfigNames
* @param {Function} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionRemoveConfigByName = function(
config_name,
on_success,
on_failure)
{
spv.assert.isNonEmptyString(config_name, 'config_name');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionRemoveConfigByName(
that.getSessionId(),
config_name,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Save the current configuration for the logged in user
*
* Preconditions: Initialized session, loaded configuration, logged in user.
*
* @export
* @param {string} config_name
* @param {boolean} allow_overwrite
* @param {Function} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionSaveConfigByName = function(
config_name,
allow_overwrite,
on_success,
on_failure)
{
spv.assert.isNonEmptyString(config_name, 'config_name');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSessionWithConfig();
that._protocol.sessionSaveConfigByName(
that.getSessionId(),
config_name,
allow_overwrite,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Choose which collection of price rules to use for the current session
*
* Preconditions: Initialized session.
*
* @export
* @param {string} price_localization_id
* @param {Function} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionSetPriceLocalization = function(
price_localization_id,
on_success,
on_failure)
{
spv.assert.isNonEmptyString(price_localization_id, 'price_localization_id');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.sessionSetPriceLocalization(
that.getSessionId(),
price_localization_id,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* @param {string} language
* @param {function()} on_success
* @param {function()} on_failure
*/
spv.ds.DsClient.prototype.setLanguage = function( language, on_success, on_failure )
{
this._language = language;
on_success();
};
/**
* @export
* @return {string}
*/
spv.ds.DsClient.prototype.getLanguage = function()
{
return this._language;
}
/**
* Try to change item state for one item in the current configuration.
* An item has two states, On or Off, eg. an item is part of the current
* configuration or it is not. The result of this operation can only be
* determined by the server. Any call to this function may result in suggestions
* being returned through the callback on_suggestions. If suggestions
*
* Use DsClient.setLanguage in order to specify language. Leaving it undefined
* will cause the backend to resolve a preferred instead.
*
* Preconditions: Initialized session, loaded configuration, caller code has a
* valid instance of spv.ds.MenuItem.
*
* @export
* @param {spv.ds.MenuItem} menu_item
* Menu item to toggle on or off. User code should not modify or
* construct instances of MenuItem, only pass MenuItem instances returned
* by this class.
*
* @param {Function} on_success
* Will be called on toggle success if toggle has no important side
* effects. Caller code should call sessionGetStateUpdate on this object
* to get the latest session state update.
*
* @param {function(Array.<spv.ds.Suggestion>, spv.ds.BipAttemptResultCode, string)} on_suggestions
* Will be called if item toggle has important side effects or if
* relevant alternative configuration states has been found.
*
* @param {function(Error)} on_failure
* Called on any kind of failure.
*/
spv.ds.DsClient.prototype.sessionToggleItem = function(
menu_item,
on_success,
on_suggestions,
on_failure)
{
spv.ds.assert.isMenuItem(menu_item, 'menu_item');
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_suggestions, 'on_suggestions');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
var category_id = menu_item.category;
var item_id = menu_item.id;
/** @param {spv.ds.SessionStateUpdate} ssu
* @param {spv.ds.impl.AuxData} aux_data */
var on_success_wrapper = function(ssu, aux_data) {
that._session_state.update(ssu, aux_data);
on_success();
};
var on_resolvers = function(goal_resolvers, attempt_code, resolvers_display_text) {
var suggestions = that.constructSuggestions(goal_resolvers);
on_suggestions(suggestions, attempt_code, resolvers_display_text);
};
this._requestQueue.push(function(wrap) {
that.assertInitializedSessionWithConfig();
that._protocol.sessionToggleItem(
that.getSessionId(),
item_id,
category_id,
that.getLanguage(),
wrap(on_success_wrapper),
wrap(on_resolvers),
wrap(that.errorHandler(on_failure)));
});
};
/**
* To be called after loading a config to retrieve the potential changes
* made during loading.
*
* A stored configuration may no longer be possible to load with the exact
* specification. For instance, an option may have been removed since the
* configuration was first built. The system will try to adapt it to the current
* logic, in which case you'll use this method to present the user with the
* changes made by the system.
*
* @param {function(Array.<spv.ds.Suggestion>)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionGetInitialConsequenceOfChange = function(
on_success,
on_failure)
{
var that = this;
this._requestQueue.push(function(wrap) {
that._protocol.sessionGetInitialConsequenceOfChange(
that.getSessionId(),
that.getLanguage(),
wrap(wrapped_on_success),
wrap(that.errorHandler(on_failure))
);
});
/** @param {Array.<spv.ds.impl.GoalStateResolver>} goal_resolvers */
function wrapped_on_success(goal_resolvers) {
var suggestions = that.constructSuggestions(goal_resolvers);
on_success(suggestions);
}
};
/**
* Call this function to keep the session alive
*
* Preconditions: Initialized session.
*
* @export
* @param {function()} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionSendHeartBeat = function(on_success, on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
this.assertInitializedSession();
var that = this;
this._requestQueue.push(function(wrap) {
that._protocol.sessionSendHeartBeat(
that.getSessionId(),
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Preconditions: Initialized session.
*
* @param {number} config_id
* @param {string} config_description
* @param {Object.<string,string>} user_config_aux
* @param {Object.<string,string>} config_storage_aux
* @param {function()} on_success
* @param {function(Error)} on_failure
*
* @export
*/
spv.ds.DsClient.prototype.userConfigV2Save = function(
config_id,
config_description,
user_config_aux,
config_storage_aux,
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.userConfigV2Save(
that.getSessionId(),
config_id,
config_description,
user_config_aux,
config_storage_aux,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
}
/**
* Preconditions: Initialized session.
*
* @param {string} config_name
* @param {string} config_description
* @param {Object.<string,string>} user_config_aux
* @param {Object.<string,string>} config_storage_aux
* @param {function(number)} on_success
* @param {function(Error)} on_failure
*
* @export
*/
spv.ds.DsClient.prototype.userConfigV2SaveAs = function(
config_name,
config_description,
user_config_aux,
config_storage_aux,
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.userConfigV2SaveAs(
that.getSessionId(),
config_name,
config_description,
user_config_aux,
config_storage_aux,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
}
/**
* Preconditions: Initialized session.
*
* @param {string} session_id
* @param {number} user_config_id
* @param {string} new_name
* @param {function()} on_success
* @param {function(Error)} on_failure
*
* @export
*/
spv.ds.DsClient.prototype.userConfigV2ChangeName = function(
session_id,
user_config_id,
new_name,
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.userConfigV2ChangeName(
session_id,
user_config_id,
new_name,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
}
/**
* Preconditions: Initialized session.
*
* @param {number} config_id
* @param {function()} on_success
* @param {function(Error)} on_failure
*
* @export
*/
spv.ds.DsClient.prototype.userConfigV2Delete = function(
config_id,
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.userConfigV2Delete(
that.getSessionId(),
config_id,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
}
/**
* Preconditions: Initialized session.
*
* @export
*
* @param {function(Array<spv.ds.UserConfigInfo>)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.userConfigV2List = function(
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.userConfigV2List(
that.getSessionId(),
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
}
/**
* Preconditions: Initialized session.
*
* The callback on_coc is optional. If provided, it will be called independently
* of on_success and on_failure. I.e. if there is coc and the load was successful,
* both on_success and on_coc will be called.
*
* @export
*
* @param {number} config_id
* @param {function()} on_success
* @param {function(Error)} on_failure
* @param {function(Array.<spv.ds.Suggestion>=)} on_coc (optional)
*/
spv.ds.DsClient.prototype.userConfigV2Load = function(
config_id,
on_success,
on_failure,
on_coc)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.userConfigV2Load(
that.getSessionId(),
config_id,
wrap(on_config_loaded),
wrap(that.errorHandler(on_failure))
);
});
function on_config_loaded()
{
if(on_coc) {
that.sessionGetInitialConsequenceOfChange(
function(suggestions) {
bopit(function() {
on_coc(suggestions);
on_success();
});
},
on_failure
);
}
else {
bopit(on_success);
}
}
function bopit(on_success) {
that.sessionUpdateBop(on_success, on_failure);
}
};
/**
* @param {string} public_config_id
* @param {function()} on_success
* @param {function(Error)} on_failure
* @param {function(Array.<spv.ds.Suggestion>=)} on_coc (optional)
*/
spv.ds.DsClient.prototype.publicConfigV2Load = function(
public_config_id,
on_success,
on_failure,
on_coc
){
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.publicConfigV2Load(
that.getSessionId(),
public_config_id,
wrap(on_config_loaded),
wrap(that.errorHandler(on_failure))
);
});
function on_config_loaded()
{
if(on_coc) {
that.sessionGetInitialConsequenceOfChange(
function(suggestions) {
bopit(function() {
on_coc(suggestions);
on_success();
});
},
on_failure
);
}
else {
bopit(on_success);
}
}
function bopit(on_success) {
that.sessionUpdateBop(on_success, on_failure);
}
};
/**
* @param {string} description
* @param {Object.<string, string>} config_storage_aux
* @param {function(spv.ds.PublicConfigInfo)} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.publicConfigV2Save = function(
description,
config_storage_aux,
on_success,
on_failure)
{
spv.assert.isFunction(on_success, 'on_success');
spv.assert.isFunction(on_failure, 'on_failure');
var that = this;
this._requestQueue.push(function(wrap) {
that.assertInitializedSession();
that._protocol.publicConfigV2Save(
that.getSessionId(),
description,
config_storage_aux,
wrap(on_success),
wrap(that.errorHandler(on_failure)));
});
}
/**
* @protected
* @param {function()} on_heartbeat
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionAutomaticHeartbeat = function(on_heartbeat, on_failure) {
var that = this;
this.stopAutomaticHeartbeat();
if( 0 < this._automatic_heartbeat_interval && this._session_is_initialized )
{
this.sessionSendHeartBeat( repeat, handleFailure );
}
function repeat() {
spv.assert( !that._heartbeat_timeout_id );
that._heartbeat_timeout_id = setTimeout(
function() {
that.sessionAutomaticHeartbeat(on_heartbeat, handleFailure);
},
that._automatic_heartbeat_interval );
on_heartbeat();
}
function handleFailure( err )
{
/** Keep heartbeating if no connection is made with the server.
* User's internet connection may be temporarily down. */
if( err.status === 'ServiceUnavailable' || err.connectionStatusCode === 0 )
repeat();
else
on_failure(err);
}
};
/**
* Starts the automatic heartbeat for the session.
* Don't forget to call stopAutomaticHeartbeat if you attempt to destroy or
* replace the DsClient object.
* If you don't, there'll be an orphaned DsClient object heartbeating forever.
* (Well, until the browser session ends. )
* @public
* @param {number} interval How often the heartbeat is triggered, in milliseconds.
* @param {function()} on_heartbeat This callback is called for every heartbeat.
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.startAutomaticHeartbeat = function(
interval,
on_heartbeat,
on_failure )
{
spv.assert( 0 <= interval );
this._automatic_heartbeat_interval = interval;
this.sessionAutomaticHeartbeat( on_heartbeat, on_failure );
};
/**
* @public
*/
spv.ds.DsClient.prototype.stopAutomaticHeartbeat = function()
{
if( this._heartbeat_timeout_id ) {
clearTimeout( this._heartbeat_timeout_id );
this._heartbeat_timeout_id = undefined;
}
};
/**
* @protected
* @param {spv.ds.impl.GoalStateResolver} goal_resolver
* @return {spv.ds.Suggestion}
*/
spv.ds.DsClient.prototype.constructSuggestion = function(goal_resolver)
{
var items_to_add = goal_resolver.items_to_add;
var items_to_remove = goal_resolver.items_to_remove;
var internal_data = gatherItemIdsForActivation(goal_resolver);
var result = new spv.ds.Suggestion(
items_to_add,
items_to_remove,
internal_data);
return result;
};
/**
* Convert state resolvers to suggestions for user presentation and bind each
* suggestion to a .activate function to allow hiding of implemention.
*
* @protected
* @param {Array.<spv.ds.impl.GoalStateResolver>} goal_resolvers
* @return {Array.<spv.ds.Suggestion>}
*/
spv.ds.DsClient.prototype.constructSuggestions = function(goal_resolvers)
{
/** @type {Array.<spv.ds.Suggestion>} */
var result = [];
for (var i = 0; i < goal_resolvers.length; i++)
{
var goal_resolver = goal_resolvers[i];
result.push(this.constructSuggestion(goal_resolver));
}
return result;
};
/**
* Requests a fresh bop and stores the new state in the client.
*
* @protected
* @param {function()} on_success
* @param {function(Error)} on_failure
*/
spv.ds.DsClient.prototype.sessionUpdateBop = function( on_success, on_failure )
{
var that = this;
/** @param {spv.ds.SessionStateUpdate} ssu
* @param {spv.ds.impl.AuxData} aux_data */
var on_success_wrapper = function(ssu, aux_data)
{
that._session_state.update(ssu, aux_data);
on_success();
};
this._requestQueue.push(function(wrap) {
that._protocol.sessionUpdateBop(
that.getSessionId(),
that.getLanguage(),
wrap(on_success_wrapper),
wrap(that.errorHandler(on_failure)));
});
};
/**
* Throw exception if session is not initialized.
*
* @protected
*/
spv.ds.DsClient.prototype.assertInitializedSession = function()
{
if (!this._session_is_initialized)
{
throw new Error('Session is not initialized');
}
};
/**
* Throw exception if session is not initialized or is missing a configuration.
*
* @protected
*/
spv.ds.DsClient.prototype.assertInitializedSessionWithConfig = function()
{
this.assertInitializedSession();
this._session_state.assertHasLoadedConfig();
};
/**
* @param {!string} str
* @private
*/
spv.ds.DsClient.prototype.debugPrint = function( str )
{
console.log( "DsClient: " + str );
};
/**
* @param {function(Error)} on_failure
* @protected
* @return {function(Error)}
*/
spv.ds.DsClient.prototype.errorHandler = function( on_failure )
{
var client = this;
return function client_error_handler( err )
{
if( err )
{
if( err.status === 'UnauthorizedSession' && client._on_unauthorized_session )
{
client._on_unauthorized_session( err );
}
else if( err.status === 'ServiceUnavailable' && client._on_service_unavailable )
{
client._on_service_unavailable( err );
}
else if( err.status === 'ServiceFailure' && client._on_service_failure )
{
client._on_service_failure( err );
}
}
return on_failure( err );
}
};
// -----------------------------------------------------------------------------
// Private utility functions.
//
// These look like members of global scope but they are not as long as you
// compile with an outer function wrapper. /AR
/**
* @private
* @param {spv.ds.impl.GoalStateResolver} goal_resolver
* @return {Array.<string>}
*/
var gatherItemIdsForActivation = function(goal_resolver)
{
var menu_items = goal_resolver.items_to_add;
/** @type {Array.<string>} */
var result = [];
for (var i = 0; i < menu_items.length; i++)
{
var menu_item = menu_items[i];
result.push(menu_item.id);
}
return result;
};