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
5cr.define('print_preview', function() {
6  'use strict';
7
8  /**
9   * Print destination data object that holds data for both local and cloud
10   * destinations.
11   * @param {string} id ID of the destination.
12   * @param {!print_preview.Destination.Type} type Type of the destination.
13   * @param {!print_preview.Destination.Origin} origin Origin of the
14   *     destination.
15   * @param {string} displayName Display name of the destination.
16   * @param {boolean} isRecent Whether the destination has been used recently.
17   * @param {!print_preview.Destination.ConnectionStatus} connectionStatus
18   *     Connection status of the print destination.
19   * @param {{tags: Array.<string>,
20   *          isOwned: ?boolean,
21   *          account: ?string,
22   *          lastAccessTime: ?number,
23   *          isTosAccepted: ?boolean,
24   *          cloudID: ?string,
25   *          description: ?string}=} opt_params Optional parameters for the
26   *     destination.
27   * @constructor
28   */
29  function Destination(id, type, origin, displayName, isRecent,
30                       connectionStatus, opt_params) {
31    /**
32     * ID of the destination.
33     * @private {string}
34     */
35    this.id_ = id;
36
37    /**
38     * Type of the destination.
39     * @private {!print_preview.Destination.Type}
40     */
41    this.type_ = type;
42
43    /**
44     * Origin of the destination.
45     * @private {!print_preview.Destination.Origin}
46     */
47    this.origin_ = origin;
48
49    /**
50     * Display name of the destination.
51     * @private {string}
52     */
53    this.displayName_ = displayName || '';
54
55    /**
56     * Whether the destination has been used recently.
57     * @private {boolean}
58     */
59    this.isRecent_ = isRecent;
60
61    /**
62     * Tags associated with the destination.
63     * @private {!Array.<string>}
64     */
65    this.tags_ = (opt_params && opt_params.tags) || [];
66
67    /**
68     * Print capabilities of the destination.
69     * @private {print_preview.Cdd}
70     */
71    this.capabilities_ = null;
72
73    /**
74     * Whether the destination is owned by the user.
75     * @private {boolean}
76     */
77    this.isOwned_ = (opt_params && opt_params.isOwned) || false;
78
79    /**
80     * Account this destination is registered for, if known.
81     * @private {string}
82     */
83    this.account_ = (opt_params && opt_params.account) || '';
84
85    /**
86     * Cache of destination location fetched from tags.
87     * @private {?string}
88     */
89    this.location_ = null;
90
91    /**
92     * Printer description.
93     * @private {string}
94     */
95    this.description_ = (opt_params && opt_params.description) || '';
96
97    /**
98     * Connection status of the destination.
99     * @private {!print_preview.Destination.ConnectionStatus}
100     */
101    this.connectionStatus_ = connectionStatus;
102
103    /**
104     * Number of milliseconds since the epoch when the printer was last
105     * accessed.
106     * @private {number}
107     */
108    this.lastAccessTime_ = (opt_params && opt_params.lastAccessTime) ||
109                           Date.now();
110
111    /**
112     * Whether the user has accepted the terms-of-service for the print
113     * destination. Only applies to the FedEx Office cloud-based printer.
114     * {@code null} if terms-of-service does not apply to the print destination.
115     * @private {?boolean}
116     */
117    this.isTosAccepted_ = opt_params && opt_params.isTosAccepted;
118
119    /**
120     * Cloud ID for Privet printers.
121     * @private {string}
122     */
123    this.cloudID_ = (opt_params && opt_params.cloudID) || '';
124  };
125
126  /**
127   * Prefix of the location destination tag.
128   * @type {!Array.<string>}
129   * @const
130   */
131  Destination.LOCATION_TAG_PREFIXES = [
132    '__cp__location=',
133    '__cp__printer-location='
134  ];
135
136  /**
137   * Enumeration of Google-promoted destination IDs.
138   * @enum {string}
139   */
140  Destination.GooglePromotedId = {
141    DOCS: '__google__docs',
142    FEDEX: '__google__fedex',
143    SAVE_AS_PDF: 'Save as PDF'
144  };
145
146  /**
147   * Enumeration of the types of destinations.
148   * @enum {string}
149   */
150  Destination.Type = {
151    GOOGLE: 'google',
152    LOCAL: 'local',
153    MOBILE: 'mobile'
154  };
155
156  /**
157   * Enumeration of the origin types for cloud destinations.
158   * @enum {string}
159   */
160  Destination.Origin = {
161    LOCAL: 'local',
162    COOKIES: 'cookies',
163    PROFILE: 'profile',
164    DEVICE: 'device',
165    PRIVET: 'privet'
166  };
167
168  /**
169   * Enumeration of the connection statuses of printer destinations.
170   * @enum {string}
171   */
172  Destination.ConnectionStatus = {
173    DORMANT: 'DORMANT',
174    OFFLINE: 'OFFLINE',
175    ONLINE: 'ONLINE',
176    UNKNOWN: 'UNKNOWN',
177    UNREGISTERED: 'UNREGISTERED'
178  };
179
180  /**
181   * Enumeration of relative icon URLs for various types of destinations.
182   * @enum {string}
183   * @private
184   */
185  Destination.IconUrl_ = {
186    CLOUD: 'images/printer.png',
187    CLOUD_SHARED: 'images/printer_shared.png',
188    LOCAL: 'images/printer.png',
189    MOBILE: 'images/mobile.png',
190    MOBILE_SHARED: 'images/mobile_shared.png',
191    THIRD_PARTY: 'images/third_party.png',
192    PDF: 'images/pdf.png',
193    DOCS: 'images/google_doc.png',
194    FEDEX: 'images/third_party_fedex.png'
195  };
196
197  Destination.prototype = {
198    /** @return {string} ID of the destination. */
199    get id() {
200      return this.id_;
201    },
202
203    /** @return {!print_preview.Destination.Type} Type of the destination. */
204    get type() {
205      return this.type_;
206    },
207
208    /**
209     * @return {!print_preview.Destination.Origin} Origin of the destination.
210     */
211    get origin() {
212      return this.origin_;
213    },
214
215    /** @return {string} Display name of the destination. */
216    get displayName() {
217      return this.displayName_;
218    },
219
220    /** @return {boolean} Whether the destination has been used recently. */
221    get isRecent() {
222      return this.isRecent_;
223    },
224
225    /**
226     * @param {boolean} isRecent Whether the destination has been used recently.
227     */
228    set isRecent(isRecent) {
229      this.isRecent_ = isRecent;
230    },
231
232    /**
233     * @return {boolean} Whether the user owns the destination. Only applies to
234     *     cloud-based destinations.
235     */
236    get isOwned() {
237      return this.isOwned_;
238    },
239
240    /**
241     * @return {string} Account this destination is registered for, if known.
242     */
243    get account() {
244      return this.account_;
245    },
246
247    /** @return {boolean} Whether the destination is local or cloud-based. */
248    get isLocal() {
249      return this.origin_ == Destination.Origin.LOCAL ||
250             (this.origin_ == Destination.Origin.PRIVET &&
251              this.connectionStatus_ !=
252              Destination.ConnectionStatus.UNREGISTERED);
253    },
254
255    /** @return {boolean} Whether the destination is a Privet local printer */
256    get isPrivet() {
257      return this.origin_ == Destination.Origin.PRIVET;
258    },
259
260    /**
261     * @return {string} The location of the destination, or an empty string if
262     *     the location is unknown.
263     */
264    get location() {
265      if (this.location_ == null) {
266        this.location_ = '';
267        this.tags_.some(function(tag) {
268          return Destination.LOCATION_TAG_PREFIXES.some(function(prefix) {
269            if (tag.indexOf(prefix) == 0) {
270              this.location_ = tag.substring(prefix.length) || '';
271              return true;
272            }
273          }, this);
274        }, this);
275      }
276      return this.location_;
277    },
278
279    /**
280     * @return {string} The description of the destination, or an empty string,
281     *     if it was not provided.
282     */
283    get description() {
284      return this.description_;
285    },
286
287    /**
288     * @return {string} Most relevant string to help user to identify this
289     *     destination.
290     */
291    get hint() {
292      if (this.id_ == Destination.GooglePromotedId.DOCS ||
293          this.id_ == Destination.GooglePromotedId.FEDEX) {
294        return this.account_;
295      }
296      return this.location || this.description;
297    },
298
299    /** @return {!Array.<string>} Tags associated with the destination. */
300    get tags() {
301      return this.tags_.slice(0);
302    },
303
304    /** @return {string} Cloud ID associated with the destination */
305    get cloudID() {
306      return this.cloudID_;
307    },
308
309    /** @return {print_preview.Cdd} Print capabilities of the destination. */
310    get capabilities() {
311      return this.capabilities_;
312    },
313
314    /**
315     * @param {!print_preview.Cdd} capabilities Print capabilities of the
316     *     destination.
317     */
318    set capabilities(capabilities) {
319      this.capabilities_ = capabilities;
320    },
321
322    /**
323     * @return {!print_preview.Destination.ConnectionStatus} Connection status
324     *     of the print destination.
325     */
326    get connectionStatus() {
327      return this.connectionStatus_;
328    },
329
330    /**
331     * @param {!print_preview.Destination.ConnectionStatus} status Connection
332     *     status of the print destination.
333     */
334    set connectionStatus(status) {
335      this.connectionStatus_ = status;
336    },
337
338    /** @return {boolean} Whether the destination is considered offline. */
339    get isOffline() {
340      return arrayContains([print_preview.Destination.ConnectionStatus.OFFLINE,
341                            print_preview.Destination.ConnectionStatus.DORMANT],
342                            this.connectionStatus_);
343    },
344
345    /** @return {string} Human readable status for offline destination. */
346    get offlineStatusText() {
347      if (!this.isOffline) {
348        return '';
349      }
350      var offlineDurationMs = Date.now() - this.lastAccessTime_;
351      var offlineMessageId;
352      if (offlineDurationMs > 31622400000.0) {  // One year.
353        offlineMessageId = 'offlineForYear';
354      } else if (offlineDurationMs > 2678400000.0) {  // One month.
355        offlineMessageId = 'offlineForMonth';
356      } else if (offlineDurationMs > 604800000.0) {  // One week.
357        offlineMessageId = 'offlineForWeek';
358      } else {
359        offlineMessageId = 'offline';
360      }
361      return loadTimeData.getString(offlineMessageId);
362    },
363
364    /**
365     * @return {number} Number of milliseconds since the epoch when the printer
366     *     was last accessed.
367     */
368    get lastAccessTime() {
369      return this.lastAccessTime_;
370    },
371
372    /** @return {string} Relative URL of the destination's icon. */
373    get iconUrl() {
374      if (this.id_ == Destination.GooglePromotedId.DOCS) {
375        return Destination.IconUrl_.DOCS;
376      } else if (this.id_ == Destination.GooglePromotedId.FEDEX) {
377        return Destination.IconUrl_.FEDEX;
378      } else if (this.id_ == Destination.GooglePromotedId.SAVE_AS_PDF) {
379        return Destination.IconUrl_.PDF;
380      } else if (this.isLocal) {
381        return Destination.IconUrl_.LOCAL;
382      } else if (this.type_ == Destination.Type.MOBILE && this.isOwned_) {
383        return Destination.IconUrl_.MOBILE;
384      } else if (this.type_ == Destination.Type.MOBILE) {
385        return Destination.IconUrl_.MOBILE_SHARED;
386      } else if (this.isOwned_) {
387        return Destination.IconUrl_.CLOUD;
388      } else {
389        return Destination.IconUrl_.CLOUD_SHARED;
390      }
391    },
392
393    /**
394     * @return {?boolean} Whether the user has accepted the terms-of-service of
395     *     the print destination or {@code null} if a terms-of-service does not
396     *     apply.
397     */
398    get isTosAccepted() {
399      return this.isTosAccepted_;
400    },
401
402    /**
403     * @param {?boolean} isTosAccepted Whether the user has accepted the
404     *     terms-of-service of the print destination or {@code null} if
405     *     a terms-of-service does not apply.
406     */
407    set isTosAccepted(isTosAccepted) {
408      this.isTosAccepted_ = isTosAccepted;
409    },
410
411    /**
412     * @return {!Array.<string>} Properties (besides display name) to match
413     *     search queries against.
414     */
415    get extraPropertiesToMatch() {
416      return [this.location, this.description];
417    },
418
419    /**
420     * Matches a query against the destination.
421     * @param {!RegExp} query Query to match against the destination.
422     * @return {boolean} {@code true} if the query matches this destination,
423     *     {@code false} otherwise.
424     */
425    matches: function(query) {
426      return this.displayName_.match(query) ||
427          this.extraPropertiesToMatch.some(function(property) {
428            return property.match(query);
429          });
430    }
431  };
432
433  /**
434   * The CDD (Cloud Device Description) describes the capabilities of a print
435   * destination.
436   *
437   * @typedef {{
438   *   version: string,
439   *   printer: {
440   *     vendor_capability: !Array.<{Object}>,
441   *     collate: {default: boolean=}=,
442   *     color: {
443   *       option: !Array.<{
444   *         type: string=,
445   *         vendor_id: string=,
446   *         custom_display_name: string=,
447   *         is_default: boolean=
448   *       }>
449   *     }=,
450   *     copies: {default: number=, max: number=}=,
451   *     duplex: {option: !Array.<{type: string=, is_default: boolean=}>}=,
452   *     page_orientation: {
453   *       option: !Array.<{type: string=, is_default: boolean=}>
454   *     }=
455   *   }
456   * }}
457   */
458  var Cdd = Object;
459
460  // Export
461  return {
462    Destination: Destination,
463    Cdd: Cdd
464  };
465});
466