1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Custom binding for the webstore API.
6
7var webstoreNatives = requireNative('webstore');
8var Event = require('event_bindings').Event;
9
10function Installer() {
11  this._pendingInstall = null;
12  this.onInstallStageChanged =
13      new Event(null, [{name: 'stage', type: 'string'}], {unmanaged: true});
14  this.onDownloadProgress =
15      new Event(null, [{name: 'progress', type: 'number'}], {unmanaged: true});
16}
17
18Installer.prototype.install = function(url, onSuccess, onFailure) {
19  if (this._pendingInstall)
20    throw new Error('A Chrome Web Store installation is already pending.');
21  if (url !== undefined && typeof(url) !== 'string') {
22    throw new Error(
23        'The Chrome Web Store item link URL parameter must be a string.');
24  }
25  if (onSuccess !== undefined && typeof(onSuccess) !== 'function')
26    throw new Error('The success callback parameter must be a function.');
27  if (onFailure !== undefined && typeof(onFailure) !== 'function')
28    throw new Error('The failure callback parameter must be a function.');
29
30  // Since we call Install() with a bool for if we have listeners, listeners
31  // must be set prior to the inline installation starting (this is also
32  // noted in the Event documentation in
33  // chrome/common/extensions/api/webstore.json).
34  var installId = webstoreNatives.Install(
35      this.onInstallStageChanged.hasListeners(),
36      this.onDownloadProgress.hasListeners(),
37      url,
38      onSuccess,
39      onFailure);
40  if (installId !== undefined) {
41    this._pendingInstall = {
42      installId: installId,
43      onSuccess: onSuccess,
44      onFailure: onFailure
45    };
46  }
47};
48
49Installer.prototype.onInstallResponse =
50    function(installId, success, error, resultCode) {
51  var pendingInstall = this._pendingInstall;
52  if (!pendingInstall || pendingInstall.installId != installId) {
53    // TODO(kalman): should this be an error?
54    return;
55  }
56
57  try {
58    if (success && pendingInstall.onSuccess)
59      pendingInstall.onSuccess();
60    else if (!success && pendingInstall.onFailure)
61      pendingInstall.onFailure(error, resultCode);
62  } catch (e) {
63    console.error('Exception in chrome.webstore.install response handler: ' +
64                  e.stack);
65  } finally {
66    this._pendingInstall = null;
67  }
68};
69
70Installer.prototype.onInstallStageChanged = function(installStage) {
71  this.onInstallStageChanged.dispatch(installStage);
72};
73
74Installer.prototype.onDownloadProgress = function(progress) {
75  this.onDownloadProgress.dispatch(progress);
76};
77
78var installer = new Installer();
79
80var chromeWebstore = {
81  install: function (url, onSuccess, onFailure) {
82    installer.install(url, onSuccess, onFailure);
83  },
84  onInstallStageChanged: installer.onInstallStageChanged,
85  onDownloadProgress: installer.onDownloadProgress
86};
87
88exports.binding = chromeWebstore;
89
90// Called by webstore_bindings.cc.
91exports.onInstallResponse =
92    Installer.prototype.onInstallResponse.bind(installer);
93exports.onInstallStageChanged =
94    Installer.prototype.onInstallStageChanged.bind(installer);
95exports.onDownloadProgress =
96    Installer.prototype.onDownloadProgress.bind(installer);
97