1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2011, 2012, 2013, 2014, 2016 Synacor, Inc.
  5  *
  6  * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at: https://www.zimbra.com/license
  9  * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15
 10  * have been added to cover use of software over a computer network and provide for limited attribution
 11  * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B.
 12  *
 13  * Software distributed under the License is distributed on an "AS IS" basis,
 14  * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 15  * See the License for the specific language governing rights and limitations under the License.
 16  * The Original Code is Zimbra Open Source Web Client.
 17  * The Initial Developer of the Original Code is Zimbra, Inc.  All rights to the Original Code were
 18  * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015.
 19  *
 20  * All portions of the code are Copyright (C) 2011, 2012, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * Creates a left pane view for suggesting locations
 26  * @constructor
 27  * @class
 28  * This class displays suggested free locations for a new appointment
 29  *
 30  *  @author Vince Bellows
 31  *
 32  * @param newApptDialog     [ZmApptQuickAddDialog]	    the new appt dialog
 33  * @param container         [DOM Element]	            the dialog's content Element
 34  * @param controller		[ZmApptComposeController]	the appt compose controller
 35  * @param closeCallback     [Callback Function]			Function to invoke upon close
 36  */
 37 ZmLocationAssistantView = function(parent, controller, newApptDialog, closeCallback) {
 38 	ZmApptAssistantView.call(this, parent, controller, newApptDialog, closeCallback);
 39 };
 40 
 41 ZmLocationAssistantView.prototype = new ZmApptAssistantView;
 42 ZmLocationAssistantView.prototype.constructor = ZmLocationAssistantView;
 43 
 44 
 45 ZmLocationAssistantView.prototype.toString =
 46 function() {
 47 	return "ZmLocationAssistantView";
 48 }
 49 
 50 ZmLocationAssistantView.prototype.cleanup =
 51 function() {
 52     if(this._locationSuggestions) this._locationSuggestions.removeAll();
 53 };
 54 
 55 
 56 ZmLocationAssistantView.prototype._configureSuggestionWidgets =
 57 function() {
 58     var locClassName = "DwtListView ZmSuggestLocationList";
 59     this._locationSuggestions = new ZmLocationSuggestionView(this, this._controller,
 60                                     this._apptView, locClassName);
 61     this._locationSuggestions.reparentHtmlElement(this._suggestionsView);
 62 
 63     Dwt.setInnerHtml(this._suggestionName, ZmMsg.suggestedLocations);
 64 
 65     this._suggestionsView.style.overflow = 'auto';
 66     Dwt.setVisible(this._suggestMinical, false);
 67 };
 68 
 69 ZmLocationAssistantView.prototype.show =
 70 function(containerSize) {
 71     this._enabled = true;
 72     if (!this._containerHeight) {
 73         this._containerHeight = containerSize.y;
 74 
 75         var nameSize        = Dwt.getSize(this._suggestionName);
 76         this._yAdjustment   = nameSize.y + 20;
 77     }
 78 };
 79 
 80 ZmLocationAssistantView.prototype.suggestAction =
 81 function(freeBusyCallback) {
 82 
 83     if(appCtxt.isOffline && !appCtxt.isZDOnline()) { return; }
 84 
 85     var params = {
 86         items: [],
 87         itemIndex: {},
 88         focus: true,
 89         showOnlyGreenSuggestions: true,
 90         fbCallback: freeBusyCallback
 91     };
 92 
 93     this._locationSuggestions.setLoadingHtml();
 94     if(this._resources.length == 0) {
 95         this.searchCalendarResources(new AjxCallback(this, this._findFreeBusyInfo, [params]));
 96     } else {
 97         this._findFreeBusyInfo(params);
 98     }
 99 };
100 
101 ZmLocationAssistantView.prototype._getTimeFrame =
102 function() {
103     var di = {};
104     ZmApptViewHelper.getDateInfo(this._apptView, di);
105     var startDate = AjxDateUtil.simpleParseDateStr(di.startDate);
106     startDate.setHours(0, 0, 0, 0);
107     var endDate = AjxDateUtil.simpleParseDateStr(di.endDate);
108     endDate.setHours(23, 59, 59, 9999);
109     return {start:startDate, end:endDate};
110 };
111 
112 ZmLocationAssistantView.prototype.updateTime =
113 function() {
114     var tf = this._getTimeFrame();
115     this.reset(tf.start);
116 };
117 
118 ZmLocationAssistantView.prototype.reset =
119 function(date) {
120     var newDurationInfo = this._apptView.getDurationInfo();
121     if(!this._duration ||
122        ((newDurationInfo.startTime != this._duration.startTime) ||
123         (newDurationInfo.endTime   != this._duration.endTime))) {
124         this._duration = newDurationInfo;
125         if(this._locationSuggestions){
126             this._locationSuggestions.removeAll();
127         }
128         this.suggestAction();
129     }
130 };
131 
132 ZmLocationAssistantView.prototype._findFreeBusyInfo =
133 function(params) {
134 
135     var currAcct = this._apptView.getCalendarAccount();
136 	// Bug: 48189 Don't send GetFreeBusyRequest for non-ZCS accounts.
137 	if (appCtxt.isOffline && (!currAcct.isZimbraAccount || currAcct.isMain)) {
138         //todo: avoid showing smart scheduler button for non-ZCS accounts - offline client
139         return;
140     }
141 
142     var tf = this._getTimeFrame();
143 
144     params.itemIndex = {};
145     params.items = [];
146     params.timeFrame = tf;
147     params.attendeeEmails = [];
148 
149     var emails = [];
150     this._copyResourcesToParams(params, emails);
151     params.emails = emails;
152 
153     if (this._freeBusyRequest) {
154         appCtxt.getRequestMgr().cancelRequest(this._freeBusyRequest, null, true);
155     }
156 
157     var callback = params.fbCallback ? params.fbCallback :
158         new AjxCallback(this, this.suggestLocations, [params]);
159     var acct = (appCtxt.multiAccounts) ? this._apptView.getCalendarAccount() : null;
160     var fbParams = {
161                     startTime:     tf.start.getTime(),
162                     endTime:       tf.end.getTime(),
163                     emails:        emails,
164                     callback:      callback,
165                     errorCallback: callback,
166                     noBusyOverlay: true,
167                     account:       acct
168     };
169 
170     this._freeBusyRequest = this._fbCache.getFreeBusyInfo(fbParams);
171 };
172 
173 
174 ZmLocationAssistantView.prototype.suggestLocations =
175 function(params) {
176     ZmApptAssistantView.prototype.suggestLocations.call(this, params);
177     Dwt.setSize(this._suggestionsView, Dwt.DEFAULT, this._containerHeight - this._yAdjustment);
178 };
179 
180 ZmLocationAssistantView.prototype.renderSuggestions =
181 function(params) {
182     params.list = params.locationInfo.locations;
183     params.totalLocations = this._totalLocations;
184     var warning = false;
185     if (params.list.size() >= ZmContactsApp.SEARCHFOR_MAX) {
186         // Problem: the locations search returned the Limit, implying there may
187         // be even more - and the location suggestion pane does not have a 'Next'
188         // button to get the next dollop, since large numbers of suggestions are
189         // not useful. Include a warning that the user should set their location prefs.
190         warning = true;
191     }
192     this._locationSuggestions.setWarning(warning);
193 
194     this._locationSuggestions.set(params);
195     if(params.focus) this._locationSuggestions.focus();
196 };
197