1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 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) 2012, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * Dialog containing the ZmResolveLocationView list.
 26  * @constructor
 27  * @class
 28  *
 29  *  @author Vince Bellows
 30  *
 31  * @param controller		[ZmApptComposeController]	the appt compose controller
 32  * @param composeView		[ZmApptEditView]	        the appt edit view
 33  * @param okCallback		[function]	                callback upon OK
 34  * @param assistantView		[ZmScheduleAssistantView]	Assistant that provides location FB info
 35  *
 36  */
 37 
 38 ZmResolveLocationConflictDialog = function(controller, composeView, okCallback, assistantView) {
 39     this._controller = controller;
 40     this._composeView = composeView;
 41 
 42     this._okCallback = okCallback;
 43     // The location assistant view associated with the parent appt view will
 44     // provide the set of viable locations for each conflict date
 45     this._assistantView = assistantView;
 46 
 47 	DwtDialog.call(this, {parent:appCtxt.getShell(),
 48         title:ZmMsg.resolveLocationConflicts});
 49 
 50 	this.setButtonListener(DwtDialog.OK_BUTTON, new AjxListener(this, this._handleOkButton));
 51 	this.setButtonListener(DwtDialog.CANCEL_BUTTON, new AjxListener(this, this._handleCancelButton));
 52 };
 53 
 54 ZmResolveLocationConflictDialog.prototype = new DwtDialog;
 55 ZmResolveLocationConflictDialog.prototype.constructor = ZmResolveLocationConflictDialog;
 56 
 57 
 58 ZmResolveLocationConflictDialog.prototype.toString =
 59 function() {
 60 	return "ZmResolveLocationConflictDialog";
 61 };
 62 
 63 // For each conflict dateTime, find the set of available locations.  These will be used to
 64 // populate the alternate location pulldowns
 65 ZmResolveLocationConflictDialog.prototype._determineAlternateLocations =
 66 function(params) {
 67     var addr;
 68     var durationInfo;
 69     var locInfo;
 70     var resolveLocInfo;
 71 
 72     this._resolveLocList = new AjxVector();
 73 
 74     for (var i = 0; i < this._inst.length; i++) {
 75         if (this._inst[i].usr) {
 76             // A Conflict exists - add an entry to the resolution list
 77             resolveLocInfo = {};
 78             resolveLocInfo.originalLocation = ZmResolveLocationView.NO_SELECTION;
 79             resolveLocInfo.enabled = true;
 80             var exceptionLoc = this._locationExceptions[this._inst[i].s];
 81             if (exceptionLoc) {
 82                 // Stored value (from either an existing exception in the DB or a
 83                 // previous use of this dialog).  Save it to use for indicating the
 84                 // selected location in the alternate locations pulldown.
 85                 var locationEmails = [];
 86                 for (var j = 0; j < exceptionLoc.length; j++) {
 87                     locationEmails.push(exceptionLoc[j].getEmail());
 88                 }
 89                 if (locationEmails.length > 1) {
 90                     // Multi select not currently supported.  If an exception was created
 91                     // outside this dialog specifying multiple locations, just display it
 92                     // (i.e. do not create a pulldown, just create a label)
 93                     resolveLocInfo.originalLocation  = locationEmails.join(',');
 94                     resolveLocInfo.enabled = false;
 95                 } else if (locationEmails.length == 1) {
 96                     resolveLocInfo.originalLocation = locationEmails[0];
 97                 }
 98              }
 99 
100             durationInfo = {};
101             durationInfo.startTime = this._inst[i].s;
102             durationInfo.endTime   = this._inst[i].s + this._inst[i].dur;
103             durationInfo.duration  = this._inst[i].dur;
104 
105             params.duration = durationInfo
106             resolveLocInfo.inst = this._inst[i];
107 
108             // Get locations that are available for this conflict's startTime to endTime
109             locInfo = this._assistantView.computeLocationAvailability(durationInfo, params);
110             resolveLocInfo.alternateLocationInfo = locInfo.locations;
111             // Add to the list for display by the ZmResolveLocationView
112             this._resolveLocList.add(resolveLocInfo);
113         }
114     }
115     params.list = this._resolveLocList;
116     this._resolveLocationView.set(params);
117 
118 };
119 
120 ZmResolveLocationConflictDialog.prototype._handleOkButton =
121 function(event) {
122     var alteredLocations   = {};
123     var locationExceptions = {};
124     var location;
125     var newLocation;
126     var resolveInfo;
127 
128     for (var i = 0; i < this._resolveLocList.size(); i++) {
129         resolveInfo = this._resolveLocList.get(i);
130         if (resolveInfo.enabled) {
131             // Get the selected alternate (if any)
132             newLocation = this._resolveLocationView.getAlternateLocation(i);
133         } else {
134             // Pulldown was not used due to multiple locations already set for entry
135             newLocation = resolveInfo.originalLocation;
136         }
137         if (newLocation != ZmResolveLocationView.NO_SELECTION) {
138             location = this._composeView.getAttendeesFromString(ZmCalBaseItem.LOCATION, newLocation, false);
139             if (location) {
140                 locationExceptions[resolveInfo.inst.s] = location.getArray();
141             }
142             if (newLocation != resolveInfo.originalLocation) {
143                 // Location changed - pass to caller to apply upon Save
144                 alteredLocations[resolveInfo.inst.s] = locationExceptions[resolveInfo.inst.s];
145             }
146         }
147 
148     }
149 
150     this.popdown();
151     if(this._okCallback) this._okCallback.run(locationExceptions, alteredLocations);
152 
153 };
154 
155 ZmResolveLocationConflictDialog.prototype._handleCancelButton =
156 function(event) {
157 	this.popdown();
158 };
159 
160 ZmResolveLocationConflictDialog.prototype.popup =
161 function(appt, inst, locationExceptions) {
162     this._appt = appt;
163     this._inst = inst ? inst : [];
164 
165     // Existing set of location exceptions - either persisted to the DB, or specified
166     // by a previous use of this dialog.
167     this._locationExceptions = locationExceptions ? locationExceptions : {};
168 
169     DwtDialog.prototype.popup.call(this);
170     this._resolveLocationView.setLoadingHtml();
171 
172     // Use the assistantView to get sets of locations for each conflict date.
173     // These will be used to populate the alternative location dropdown.
174     var fbEndTime = 0;
175     if (this._inst.length > 0) {
176         var inst = this._inst[this._inst.length-1];
177         fbEndTime = inst.s + inst.dur;
178         this._assistantView.getLocationFBInfo(
179             this._determineAlternateLocations, this, fbEndTime);
180     }
181 };
182 
183 ZmResolveLocationConflictDialog.prototype.setContent =
184 function(text) {
185 	var contentDiv = this._getContentDiv();
186 
187     this._resolveLocationView = new ZmResolveLocationView(
188         this, this._controller, this._apptView);
189     this._resolveLocationView.reparentHtmlElement(contentDiv);
190 
191 
192 };
193 
194 ZmResolveLocationConflictDialog.prototype.cleanup =
195 function() {
196     if(this._resolveLocationView) this._resolveLocationView.removeAll();
197 };
198 
199 
200 
201