· 5 years ago · Oct 06, 2020, 09:48 AM
1// ----------------------------------------------------------------------------
2// Copyright 2007-2020, GeoTelematic Solutions, Inc.
3// All rights reserved
4// ----------------------------------------------------------------------------
5//
6// Licensed under the Apache License, Version 2.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
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17//
18// ----------------------------------------------------------------------------
19// Change History:
20// 2008/08/08 Martin D. Flynn
21// -Initial release
22// 2008/08/17 Martin D. Flynn
23// -Added "Distance" title line (below "Cursor Location")
24// -Fix display of View/Edit buttons on creation of first user.
25// 2008/09/01 Martin D. Flynn
26// -Added delete confirmation
27// 2008/10/16 Martin D. Flynn
28// -Update with new ACL usage
29// 2008/12/01 Martin D. Flynn
30// -Added ability to display multiple points
31// 2009/08/23 Martin D. Flynn
32// -Convert new entered IDs to lowercase
33// 2010/04/11 Martin D. Flynn
34// -Added support for drawing polygons and corridors, however, MapProvider
35// support for these features is also required (and in the case of corridors,
36// may also require add-on module support to use the corridor geozones
37// properly).
38// 2011/05/13 Martin D. Flynn
39// -Added support for limiting the number of displayed vertices.
40// (see property "zoneInfo.maximumDisplayedVertices")
41// 2013/04/08 Martin D. Flynn
42// -Added "zoneInfo.showAssignedDeviceGroup" support
43// 2014/11/30 Martin D. Flynn
44// -Added initial support for Geozone pushpin labelling (must be supported by MapProvider)
45// 2015/05/03 Martin D. Flynn
46// -"Pushpins" pull-down selection available for selecting an associated pushpin.
47// -Added arrive/depart status code selection option see (see "showArriveDepartCode")
48// 2015/08/16 Martin D. Flynn
49// -"setDepartureStatusCode" automatically set to paired "ArrivalStatusCode" [2.6.0-B49]
50// -Reduced the size of the displayed lat/lon fields.
51// 2016/01/04 Martin D. Flynn
52// -Changed "Client Upload" to "Device Upload".
53// 2018/09/10 GTS Development Team
54// -Changes no assigned groups to mean "all" geozones. [2.6.6-B38]
55// ----------------------------------------------------------------------------
56package org.opengts.war.track.page;
57
58import java.util.*;
59import java.io.*;
60
61import javax.servlet.*;
62import javax.servlet.http.*;
63
64import org.opengts.util.*;
65import org.opengts.dbtools.*;
66import org.opengts.db.*;
67import org.opengts.db.tables.*;
68import org.opengts.geocoder.GeocodeProvider;
69
70import org.opengts.war.tools.*;
71import org.opengts.war.track.*;
72
73public class ZoneInfo
74 extends WebPageAdaptor
75 implements Constants
76{
77
78 // ------------------------------------------------------------------------
79 // 'private.xml' properties
80
81 // PrivateLabel.PROP_ZoneInfo_mapControlLocation
82 private static final String CONTROLS_ON_LEFT[] = new String[] { "left", "true" };
83
84 // ------------------------------------------------------------------------
85
86 private static final double DEFAULT_ZONE_RADIUS = 20000.0;
87
88 // ------------------------------------------------------------------------
89
90 private static final String OVERLAP_PRIORITY[] = new String[] { "0", "1", "2", "3", "4", "5" };
91
92 // ------------------------------------------------------------------------
93 // Parameters
94
95 // forms
96 public static final String FORM_ZONE_SELECT = "ZoneInfoSelect";
97 public static final String FORM_ZONE_EDIT = "ZoneInfoEdit";
98 public static final String FORM_ZONE_NEW = "ZoneInfoNew";
99
100 // commands
101 public static final String COMMAND_INFO_UPDATE = "update";
102 public static final String COMMAND_INFO_SELECT = "select";
103 public static final String COMMAND_INFO_NEW = "new";
104
105 // submit
106 public static final String PARM_SUBMIT_EDIT = "z_subedit";
107 public static final String PARM_SUBMIT_VIEW = "z_subview";
108 public static final String PARM_SUBMIT_CHG = "z_subchg";
109 public static final String PARM_SUBMIT_DEL = "z_subdel";
110 public static final String PARM_SUBMIT_NEW = "z_subnew";
111
112 // buttons
113 public static final String PARM_BUTTON_CANCEL = "u_btncan";
114 public static final String PARM_BUTTON_BACK = "u_btnbak";
115
116 // parameters
117 public static final String PARM_NEW_ID = "z_newid";
118 public static final String PARM_NEW_TYPE = "z_newtype";
119
120 // parameters
121 public static final String PARM_ZONE_SELECT = "z_zone";
122 public static final String PARM_ZONE_ACTIVE = "z_actv";
123 public static final String PARM_PRIORITY = "z_priority";
124 public static final String PARM_REV_GEOCODE = "z_revgeo";
125 public static final String PARM_ARRIVE_NOTIFY = "z_arrive";
126 public static final String PARM_ARRIVE_CODE = "z_arrcode";
127 public static final String PARM_DEPART_NOTIFY = "z_depart";
128 public static final String PARM_DEPART_CODE = "z_depcode";
129 public static final String PARM_AUTO_NOTIFY = "z_autontfy";
130 public static final String PARM_CLIENT_UPLOAD = "z_upload";
131 public static final String PARM_CLIENT_ID = "z_clntid";
132 public static final String PARM_SPEED_LIMIT = "z_spdlim";
133 public static final String PARM_PURPOSE_ID = "z_purpid";
134 public static final String PARM_CORRIDOR_ID = "z_corrid";
135 public static final String PARM_GROUP_SELECT = "z_group";
136
137 public static final String PARM_ZONE_DESC = "z_desc";
138 public static final String PARM_ZONE_RADIUS = "z_radius";
139 public static final String PARM_ZONE_INDEX = "z_index";
140 public static final String PARM_ZONE_COLOR = "z_color";
141 public static final String PARM_ZONE_PUSHPIN = "z_ppin";
142
143 public static final String PARM_ZONE_LATITUDE_ = "z_lat";
144 private static String PARM_ZONE_LATITUDE(int ndx)
145 {
146 return PARM_ZONE_LATITUDE_ + ndx;
147 }
148 public static final String PARM_ZONE_LONGITUDE_ = "z_lon";
149 public static final String PARM_ZONE_LONGITUDE(int ndx)
150 {
151 return PARM_ZONE_LONGITUDE_ + ndx;
152 }
153
154 // sort ID
155 private static final int DEFAULT_SORT_ID = 0;
156
157 // point index
158 private static final int DEFAULT_POINT_INDEX = 0;
159
160 // ------------------------------------------------------------------------
161 // ------------------------------------------------------------------------
162
163 /* possible options for arrive/depart status codes */
164 private static int STATUS_CODES[][] = {
165 // ArrivalCodes DepartureCodes
166 { StatusCodes.STATUS_GEOFENCE_ARRIVE, StatusCodes.STATUS_GEOFENCE_DEPART },
167 { StatusCodes.STATUS_GEOFENCE_ACTIVE, StatusCodes.STATUS_GEOFENCE_INACTIVE },
168 { StatusCodes.STATUS_GEOBOUNDS_ENTER, StatusCodes.STATUS_GEOBOUNDS_EXIT },
169 { StatusCodes.STATUS_JOB_ARRIVE , StatusCodes.STATUS_JOB_DEPART },
170 { StatusCodes.STATUS_JOB_START , StatusCodes.STATUS_JOB_STOP },
171 { StatusCodes.STATUS_JOB_STOP , StatusCodes.STATUS_JOB_START },
172 { StatusCodes.STATUS_TRACK_START , StatusCodes.STATUS_TRACK_STOP },
173 { StatusCodes.STATUS_TRACK_STOP , StatusCodes.STATUS_TRACK_START },
174 { StatusCodes.STATUS_DUTY_ON , StatusCodes.STATUS_DUTY_OFF },
175 { StatusCodes.STATUS_DUTY_OFF , StatusCodes.STATUS_DUTY_ON },
176 { StatusCodes.STATUS_INTRUSION_ON , StatusCodes.STATUS_INTRUSION_OFF },
177 //{ StatusCodes.STATUS_BREACH_ON , StatusCodes.STATUS_BREACH_OFF },
178 //{ StatusCodes.STATUS_CORRIDOR_ARRIVE, StatusCodes.STATUS_CORRIDOR_DEPART },
179 //{ StatusCodes.STATUS_CORRIDOR_ACTIVE, StatusCodes.STATUS_CORRIDOR_INACTIVE },
180 //{ StatusCodes.STATUS_PERSON_ENTER , StatusCodes.STATUS_PERSON_EXIT },
181 };
182
183 private static ComboMap getArrivalCodeComboMap(BasicPrivateLabel bpl)
184 {
185 return ZoneInfo._getStatusCodeComboMap(0/*arrive*/, bpl);
186 }
187
188 private static ComboMap getDepartureCodeComboMap(BasicPrivateLabel bpl)
189 {
190 return ZoneInfo._getStatusCodeComboMap(1/*depart*/, bpl);
191 }
192
193 private static ComboMap _getStatusCodeComboMap(int scNdx, BasicPrivateLabel bpl)
194 {
195 ComboMap scList = new ComboMap();
196 for (int sca[] : STATUS_CODES) {
197 int sc = sca[(scNdx <= 0)? 0 : 1];
198 String key = "0x"+StringTools.toHexString(sc,16);
199 String desc = StatusCodes.GetDescription(sc,bpl);
200 scList.add(key, desc);
201 }
202 return scList;
203 }
204
205 // ------------------------------------------------------------------------
206 // ------------------------------------------------------------------------
207 // WebPage interface
208
209 public ZoneInfo()
210 {
211 this.setBaseURI(RequestProperties.TRACK_BASE_URI());
212 this.setPageName(PAGE_ZONE_INFO);
213 this.setPageNavigation(new String[] { PAGE_LOGIN, PAGE_MENU_TOP });
214 this.setLoginRequired(true);
215 }
216
217 // ------------------------------------------------------------------------
218
219 public String getMenuName(RequestProperties reqState)
220 {
221 return MenuBar.MENU_ADMIN;
222 }
223
224 public String getMenuDescription(RequestProperties reqState, String parentMenuName)
225 {
226 PrivateLabel privLabel = reqState.getPrivateLabel();
227 I18N i18n = privLabel.getI18N(ZoneInfo.class);
228 return super._getMenuDescription(reqState,i18n.getString("ZoneInfo.editMenuDesc","View/Edit Geozone Information"));
229 }
230
231 public String getMenuHelp(RequestProperties reqState, String parentMenuName)
232 {
233 PrivateLabel privLabel = reqState.getPrivateLabel();
234 I18N i18n = privLabel.getI18N(ZoneInfo.class);
235 return super._getMenuHelp(reqState,i18n.getString("ZoneInfo.editMenuHelp","View and Edit Geozone information"));
236 }
237
238 // ------------------------------------------------------------------------
239
240 public String getNavigationDescription(RequestProperties reqState)
241 {
242 PrivateLabel privLabel = reqState.getPrivateLabel();
243 I18N i18n = privLabel.getI18N(ZoneInfo.class);
244 return super._getNavigationDescription(reqState,i18n.getString("ZoneInfo.navDesc","Geozone"));
245 }
246
247 public String getNavigationTab(RequestProperties reqState)
248 {
249 PrivateLabel privLabel = reqState.getPrivateLabel();
250 I18N i18n = privLabel.getI18N(ZoneInfo.class);
251 return super._getNavigationTab(reqState,i18n.getString("ZoneInfo.navTab","Geozone Admin"));
252 }
253
254 // ------------------------------------------------------------------------
255
256 private static int parseClientUploadFlag(PrivateLabel privLabel)
257 {
258 String uplFlag = privLabel.getStringProperty(PrivateLabel.PROP_ZoneInfo_showClientUploadZone,"");
259 if (StringTools.isBlank(uplFlag)) {
260 return 0; // do not show
261 } else
262 if (uplFlag.equalsIgnoreCase("false")) {
263 return 0; // do not show
264 } else
265 if (uplFlag.equalsIgnoreCase("true") || uplFlag.equalsIgnoreCase("checkbox")) {
266 return 1; // show checkbox only
267 } else
268 if (uplFlag.equalsIgnoreCase("id")) {
269 return 2; // show id field only
270 } else {
271 return 0;
272 }
273 }
274
275 private static ComboMap GetColorComboMap(I18N i18n)
276 {
277 ComboMap cc = new ComboMap();
278 cc.add("" ,i18n.getString("ZoneInfo.color.default","Default"));
279 cc.add(ColorTools.BLACK.toString(true) ,i18n.getString("ZoneInfo.color.black" ,"Black" ));
280 cc.add(ColorTools.BROWN.toString(true) ,i18n.getString("ZoneInfo.color.brown" ,"Brown" ));
281 cc.add(ColorTools.RED.toString(true) ,i18n.getString("ZoneInfo.color.red" ,"Red" ));
282 cc.add(ColorTools.ORANGE.toString(true) ,i18n.getString("ZoneInfo.color.orange" ,"Orange" ));
283 cc.add(ColorTools.YELLOW.toString(true) ,i18n.getString("ZoneInfo.color.yellow" ,"Yellow" ));
284 cc.add(ColorTools.GREEN.toString(true) ,i18n.getString("ZoneInfo.color.green" ,"Green" ));
285 cc.add(ColorTools.BLUE.toString(true) ,i18n.getString("ZoneInfo.color.blue" ,"Blue" ));
286 cc.add(ColorTools.PURPLE.toString(true) ,i18n.getString("ZoneInfo.color.purple" ,"Purple" ));
287 cc.add(ColorTools.DARK_GRAY.toString(true) ,i18n.getString("ZoneInfo.color.gray" ,"Gray" ));
288 cc.add(ColorTools.WHITE.toString(true) ,i18n.getString("ZoneInfo.color.white" ,"White" ));
289 cc.add(ColorTools.CYAN.toString(true) ,i18n.getString("ZoneInfo.color.cyan" ,"Cyan" ));
290 cc.add(ColorTools.PINK.toString(true) ,i18n.getString("ZoneInfo.color.pink" ,"Pink" ));
291 return cc;
292 }
293
294 private static ComboMap GetPushpinComboMap(I18N i18n, RequestProperties reqState)
295 {
296 ComboMap cc = new ComboMap();
297 cc.add("",i18n.getString("ZoneInfo.pushpin.default","None"));
298 MapProvider mapProv = reqState.getMapProvider();
299 if (mapProv != null) {
300 Map<String,PushpinIcon> ppMap = mapProv.getPushpinIconMap(reqState);
301 for (String ppID : ppMap.keySet()) {
302 PushpinIcon ppIcon = ppMap.get(ppID);
303 if (ppIcon.getIconEval()) {
304 // -- skip pushpins that require evaluation
305 continue;
306 }
307 cc.add(ppID,ppID);
308 }
309 }
310 return cc;
311 }
312
313 private static int getGeozoneSupportedPointCount(RequestProperties reqState, int type)
314 {
315 PrivateLabel privLabel = reqState.getPrivateLabel(); // never null
316 MapProvider mapProvider = reqState.getMapProvider(); // may be null
317 int pointCount = (mapProvider != null)? mapProvider.getGeozoneSupportedPointCount(type) : 0;
318 int maxCount = privLabel.getIntProperty(PrivateLabel.PROP_ZoneInfo_maximumDisplayedVertices, -1);
319 if ((maxCount > 0) && (pointCount > maxCount)) {
320 pointCount = maxCount;
321 }
322 return pointCount;
323 }
324
325 private static String[] getGeozoneIDs(PrivateLabel privLabel, Account currAcct, User currUser)
326 {
327 DBReadWriteMode rwMode = DBReadWriteMode.READ_WRITE;
328 String acctID = currAcct.getAccountID();
329 String userID = (currUser != null)? currUser.getUserID() : User.getAdminUserID();
330 try {
331
332 // -- limit displayed Geozones?
333 boolean limitToGroups = privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_limitToUserDeviceGroups,false);
334 if (limitToGroups && !User.isAdminUser(userID)) {
335 // -- return only geozones that match the current users authorized groups
336 java.util.List<String> dgList = User.getExplicitlyAuthorizedDeviceGroupIDs(rwMode, acctID, userID, -1L);
337 if (ListTools.isEmpty(dgList)) {
338 // -- no DeviceGroups assigned to user (none is all? [2.6.6-B38])
339 //return new String[0]; <== removed [2.6.6-B38]
340 return Geozone.getGeozoneIDsForAccount(rwMode, currAcct, currUser, (String[])null); // has Account/User
341 } else {
342 // -- get Geozones assigned to a the users DeviceGroup
343 String dgIDs[] = dgList.toArray(new String[dgList.size()]);
344 return Geozone.getGeozoneIDsForAccount(rwMode, currAcct, currUser, dgIDs); // has Account/User
345 }
346 }
347
348 // -- no Geozone limits, get all Geozones
349 return Geozone.getGeozoneIDsForAccount(rwMode, currAcct, currUser, (String[])null); // has Account/User
350
351 } catch (DBException dbe) {
352
353 // -- error, return no geozones
354 Print.logError("[Error] Returning no Geozones: " + dbe);
355 return new String[0];
356
357 }
358 }
359
360 public void writePage(
361 final RequestProperties reqState,
362 String pageMsg)
363 throws IOException
364 {
365 final HttpServletRequest request = reqState.getHttpServletRequest();
366 final PrivateLabel privLabel = reqState.getPrivateLabel(); // never null
367 final I18N i18n = privLabel.getI18N(ZoneInfo.class);
368 final Locale locale = reqState.getLocale();
369 final Account currAcct = reqState.getCurrentAccount(); // never null
370 final User currUser = reqState.getCurrentUser(); // may be null
371 final String pageName = this.getPageName();
372 final boolean showOverlapPriority = Geozone.supportsPriority() && privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_showOverlapPriority,false);
373 final boolean showSpeedLimit = Geozone.supportsSpeedLimitKPH() && privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_showSpeedLimit,false);
374 final boolean showPurposeIDs = privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_showPurposeID,false);
375 final boolean showCorridorIDs = Geozone.supportsCorridor() && privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_showCorridorID,false);
376 final boolean showRevGeocodeZone = privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_showReverseGeocodeZone,true);
377 final boolean showArriveDepartZone = Device.hasRuleFactory() || privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_showArriveDepartZone,false);
378 final boolean showArriveDepartCode = showArriveDepartZone && privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_showArriveDepartCode,false);
379 final boolean showAutoNotify = showArriveDepartZone && privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_showAutoNotify,false);
380 final int showClientUploadZone = parseClientUploadFlag(privLabel);
381 final boolean showAssignedDevGroup = privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_showAssignedDeviceGroup,false);
382 final boolean showFilter = privLabel.getBooleanProperty(PrivateLabel.PROP_AdminPage_showSearchFilter,false) && Track.jsFileExists(FILTER_JS);
383
384 String m = pageMsg;
385 boolean error = false;
386
387 /* list of geozones */
388 String zoneList[] = ZoneInfo.getGeozoneIDs(privLabel, currAcct, currUser);
389
390 /* selected geozone */
391 String selZoneID = AttributeTools.getRequestString(reqState.getHttpServletRequest(), PARM_ZONE_SELECT, "");
392 if (StringTools.isBlank(selZoneID)) {
393 if ((zoneList.length > 0) && (zoneList[0] != null)) {
394 selZoneID = zoneList[0];
395 } else {
396 selZoneID = "";
397 }
398 //Print.logWarn("No Zone selected, choosing first zone: %s", selZoneID);
399 }
400 if (zoneList.length == 0) {
401 zoneList = new String[] { selZoneID };
402 }
403
404 /* Geozone db */
405 Geozone selZone = null;
406 try {
407 selZone = !selZoneID.equals("")? Geozone.getGeozone(currAcct,selZoneID,DEFAULT_SORT_ID,false/*RGOnly*/) : null;
408 } catch (DBException dbe) {
409 // ignore
410 }
411
412 /* ACL */
413 boolean allowNew = privLabel.hasAllAccess(currUser, this.getAclName());
414 boolean allowDelete = allowNew;
415 boolean allowEdit = allowNew || privLabel.hasWriteAccess(currUser, this.getAclName());
416 boolean allowView = allowEdit || privLabel.hasReadAccess(currUser, this.getAclName());
417
418 /* command */
419 String zoneCmd = reqState.getCommandName();
420 boolean listZones = false;
421 boolean updateZone = zoneCmd.equals(COMMAND_INFO_UPDATE);
422 boolean selectZone = zoneCmd.equals(COMMAND_INFO_SELECT);
423 boolean newZone = zoneCmd.equals(COMMAND_INFO_NEW);
424 boolean deleteZone = false;
425 boolean editZone = false;
426 boolean viewZone = false;
427
428 /* submit buttons */
429 String submitEdit = AttributeTools.getRequestString(request, PARM_SUBMIT_EDIT, "");
430 String submitView = AttributeTools.getRequestString(request, PARM_SUBMIT_VIEW, "");
431 String submitChange = AttributeTools.getRequestString(request, PARM_SUBMIT_CHG , "");
432 String submitNew = AttributeTools.getRequestString(request, PARM_SUBMIT_NEW , "");
433 String submitDelete = AttributeTools.getRequestString(request, PARM_SUBMIT_DEL , "");
434
435 /* MapProvider support */
436 final MapProvider mapProvider = reqState.getMapProvider(); // check below to make sure this is not null
437 final boolean mapSupportsCursorLocation = ((mapProvider != null) && mapProvider.isFeatureSupported(MapProvider.FEATURE_LATLON_DISPLAY));
438 final boolean mapSupportsDistanceRuler = ((mapProvider != null) && mapProvider.isFeatureSupported(MapProvider.FEATURE_DISTANCE_RULER));
439 final boolean mapSupportsGeozones = ((mapProvider != null) && mapProvider.isFeatureSupported(MapProvider.FEATURE_GEOZONES));
440
441 /* sub-command */
442 String newZoneID = null;
443 int newZoneType = Geozone.GeozoneType.POINT_RADIUS.getIntValue(); // default
444 if (newZone) {
445 if (!allowNew) {
446 // not authorized to create new Geozones
447 Print.logInfo("Not authorized to create a new Geozone ...");
448 newZone = false;
449 } else {
450 HttpServletRequest httpReq = reqState.getHttpServletRequest();
451 newZoneID = AttributeTools.getRequestString(httpReq,PARM_NEW_ID,"").trim().toLowerCase();
452 newZoneType = AttributeTools.getRequestInt(httpReq,PARM_NEW_TYPE, newZoneType);
453 if (StringTools.isBlank(newZoneID)) {
454 m = i18n.getString("ZoneInfo.enterNewZone","Please enter a new Geozone name."); // UserErrMsg
455 error = true;
456 newZone = false;
457 } else
458 if (!WebPageAdaptor.isValidID(reqState,/*PrivateLabel.PROP_ZoneInfo_validateNewIDs,*/newZoneID)) {
459 m = i18n.getString("ZoneInfo.invalidIDChar","ID contains invalid characters"); // UserErrMsg
460 error = true;
461 newZone = false;
462 }
463 }
464 } else
465 if (updateZone) {
466 if (!allowEdit) {
467 // not authorized to update Geozones
468 updateZone = false;
469 } else
470 if (!SubmitMatch(submitChange,i18n.getString("ZoneInfo.change","Change"))) {
471 updateZone = false;
472 } else
473 if (selZone == null) {
474 // should not occur
475 m = i18n.getString("ZoneInfo.unableToUpdate","Unable to update Geozone, ID not found"); // UserErrMsg
476 error = true;
477 updateZone = false;
478 }
479 } else
480 if (selectZone) {
481 if (SubmitMatch(submitDelete,i18n.getString("ZoneInfo.delete","Delete"))) {
482 if (allowDelete) {
483 deleteZone = true;
484 }
485 } else
486 if (SubmitMatch(submitEdit,i18n.getString("ZoneInfo.edit","Edit"))) {
487 if (allowEdit) {
488 if (selZone == null) {
489 m = i18n.getString("ZoneInfo.pleaseSelectGeozone","Please select a Geozone"); // UserErrMsg
490 error = true;
491 listZones = true;
492 } else {
493 editZone = true;
494 viewZone = true;
495 }
496 }
497 } else
498 if (SubmitMatch(submitView,i18n.getString("ZoneInfo.view","View"))) {
499 if (allowView) {
500 if (selZone == null) {
501 m = i18n.getString("ZoneInfo.pleaseSelectGeozone","Please select a Geozone"); // UserErrMsg
502 error = true;
503 listZones = true;
504 } else {
505 viewZone = true;
506 }
507 }
508 } else {
509 listZones = true;
510 }
511 } else {
512 listZones = true;
513 }
514
515 /* delete Geozone? */
516 if (deleteZone) {
517 if (selZone == null) {
518 m = i18n.getString("ZoneInfo.pleaseSelectGeozone","Please select a Geozone"); // UserErrMsg
519 error = true;
520 } else {
521 try {
522 Geozone.Key zoneKey = (Geozone.Key)selZone.getRecordKey();
523 Print.logWarn("Deleting Geozone: " + zoneKey);
524 zoneKey.delete(true); // will also delete dependencies
525 selZoneID = "";
526 selZone = null;
527 zoneList = ZoneInfo.getGeozoneIDs(privLabel, currAcct, currUser);
528 if ((zoneList != null) && (zoneList.length > 0)) {
529 selZoneID = zoneList[0];
530 try {
531 selZone = !selZoneID.equals("")?Geozone.getGeozone(currAcct,selZoneID,DEFAULT_SORT_ID,false):null;
532 } catch (DBException dbe) {
533 // ignore
534 }
535 }
536 } catch (DBException dbe) {
537 Print.logException("Deleting Geozone", dbe);
538 m = i18n.getString("ZoneInfo.errorDelete","Internal error deleting Geozone"); // UserErrMsg
539 error = true;
540 }
541 }
542 listZones = true;
543 }
544
545 /* new Geozone? */
546 if (newZone) {
547 boolean createZoneOK = true;
548 //Print.logInfo("Creating new Geozone: %s", newZoneID);
549 for (int u = 0; u < zoneList.length; u++) {
550 if (newZoneID.equalsIgnoreCase(zoneList[u])) {
551 m = i18n.getString("ZoneInfo.alreadyExists","This Geozone already exists"); // UserErrMsg
552 error = true;
553 createZoneOK = false;
554 break;
555 }
556 }
557 if (createZoneOK) {
558 try {
559 Geozone zone = Geozone.getGeozone(currAcct, newZoneID, DEFAULT_SORT_ID, true); // create
560 zone.setZoneType(newZoneType);
561 zone.setDefaultRadius(); // based on zone type
562 zone.save(); // needs to be saved to be created
563 zoneList = ZoneInfo.getGeozoneIDs(privLabel, currAcct, currUser);
564 selZone = zone;
565 selZoneID = selZone.getGeozoneID();
566 m = i18n.getString("ZoneInfo.createdZone","New Geozone has been created"); // UserErrMsg
567 } catch (DBException dbe) {
568 Print.logException("Error Creating Geozone", dbe);
569 m = i18n.getString("ZoneInfo.errorCreate","Internal error creating Geozone"); // UserErrMsg
570 error = true;
571 }
572 }
573 listZones = true;
574 }
575
576 /* change/update the Geozone info? */
577 if (updateZone) {
578 boolean zoneActive = !StringTools.isBlank( AttributeTools.getRequestString(request,PARM_ZONE_ACTIVE,null));
579 int zonePriority = StringTools.parseInt( AttributeTools.getRequestString(request,PARM_PRIORITY,null),0);
580 boolean zoneRevGeocode = !StringTools.isBlank( AttributeTools.getRequestString(request,PARM_REV_GEOCODE,null));
581 boolean zoneArrNotify = !StringTools.isBlank( AttributeTools.getRequestString(request,PARM_ARRIVE_NOTIFY,null));
582 int zoneArrCode = StringTools.parseInt( AttributeTools.getRequestString(request,PARM_ARRIVE_CODE,null),StatusCodes.STATUS_GEOFENCE_ARRIVE);
583 boolean zoneDepNotify = !StringTools.isBlank( AttributeTools.getRequestString(request,PARM_DEPART_NOTIFY,null));
584 int zoneDepCode = StringTools.parseInt( AttributeTools.getRequestString(request,PARM_DEPART_CODE,null),StatusCodes.STATUS_GEOFENCE_DEPART);
585 boolean zoneAutoNotify = !StringTools.isBlank( AttributeTools.getRequestString(request,PARM_AUTO_NOTIFY,null));
586 boolean zoneClientUpld = !StringTools.isBlank( AttributeTools.getRequestString(request,PARM_CLIENT_UPLOAD,null));
587 int zoneClientID = StringTools.parseInt( AttributeTools.getRequestString(request,PARM_CLIENT_ID,null),0);
588 double zoneSpeedLimit = StringTools.parseDouble(AttributeTools.getRequestString(request,PARM_SPEED_LIMIT,null),0.0);
589 long zoneRadius = StringTools.parseLong( AttributeTools.getRequestString(request,PARM_ZONE_RADIUS,null),100L);
590 String zoneColor = AttributeTools.getRequestString(request,PARM_ZONE_COLOR,null);
591 String zonePushpin = AttributeTools.getRequestString(request,PARM_ZONE_PUSHPIN,null);
592 String zoneDesc = AttributeTools.getRequestString(request,PARM_ZONE_DESC,"");
593 String zonePurpID = AttributeTools.getRequestString(request,PARM_PURPOSE_ID,"");
594 String zoneCorrID = AttributeTools.getRequestString(request,PARM_CORRIDOR_ID,"");
595 String zoneGroupID = AttributeTools.getRequestString(request,PARM_GROUP_SELECT, "");
596 if (zoneGroupID.equalsIgnoreCase(DeviceGroup.DEVICE_GROUP_ALL)) { zoneGroupID = ""; }
597
598 //Print.logInfo("Updating Zone: %s - %s", selZoneID, zoneDesc);
599 try {
600 if (selZone != null) {
601 boolean saveOK = true;
602 // -- Active
603 if (!Geozone.IsGlobalActive()) {
604 // -- GlobalActive is false, set user selected active state
605 selZone.setIsActive(zoneActive);
606 } else {
607 // -- GlobalActive is true, set this zone to true as well
608 selZone.setIsActive(true);
609 }
610 // -- Overlap priority
611 if (showOverlapPriority) {
612 selZone.setPriority(zonePriority);
613 }
614 // -- Speed limit
615 if (showSpeedLimit) {
616 Account.SpeedUnits speedUnit = Account.getSpeedUnits(currAcct); // not null
617 double kph = speedUnit.convertToKPH(zoneSpeedLimit);
618 selZone.setSpeedLimitKPH(kph);
619 }
620 // -- ReverseGeocode
621 if (showRevGeocodeZone) {
622 selZone.setReverseGeocode(zoneRevGeocode);
623 } else {
624 selZone.setReverseGeocode(true);
625 }
626 // -- Arrive/Depart notification
627 if (showArriveDepartZone) {
628 selZone.setArrivalZone(zoneArrNotify);
629 selZone.setDepartureZone(zoneDepNotify);
630 if (showArriveDepartCode) {
631 int pairedDepartSC = StatusCodes.GetPairedStatusCodesMate(zoneArrCode); // [2.6.0-B49]
632 selZone.setArrivalStatusCode(zoneArrCode);
633 selZone.setDepartureStatusCode(pairedDepartSC); // zoneDepCode);
634 } else {
635 selZone.setArrivalStatusCode(StatusCodes.STATUS_GEOFENCE_ARRIVE);
636 selZone.setDepartureStatusCode(StatusCodes.STATUS_GEOFENCE_DEPART);
637 }
638 if (showAutoNotify) {
639 selZone.setAutoNotify(zoneAutoNotify);
640 } else {
641 selZone.setAutoNotify(false);
642 }
643 } else {
644 selZone.setArrivalZone(true);
645 selZone.setDepartureZone(true);
646 selZone.setArrivalStatusCode(StatusCodes.STATUS_GEOFENCE_ARRIVE);
647 selZone.setDepartureStatusCode(StatusCodes.STATUS_GEOFENCE_DEPART);
648 selZone.setAutoNotify(false);
649 }
650 // -- Client upload zone
651 if (showClientUploadZone != 0) {
652 if (zoneClientID > 0) {
653 selZone.setClientUpload(true);
654 selZone.setClientID(zoneClientID);
655 } else
656 if (zoneClientUpld) {
657 selZone.setClientUpload(true);
658 selZone.setClientID(1);
659 } else {
660 selZone.setClientUpload(false);
661 selZone.setClientID(0);
662 }
663 }
664 // -- assigned group id
665 if (!selZone.getGroupID().equalsIgnoreCase(zoneGroupID)) {
666 selZone.setGroupID(zoneGroupID);
667 }
668 // -- Radius (meters)
669 if (zoneRadius > 0L) {
670 selZone.setRadius((int)zoneRadius);
671 }
672 // -- zone color
673 if (!StringTools.isBlank(zoneColor)) {
674 selZone.setShapeColor(zoneColor);
675 }
676 // -- zone pushpin
677 if (!selZone.getIconName().equals(zonePushpin)) {
678 selZone.setIconName(zonePushpin);
679 }
680 // -- GeoPoints
681 selZone.clearGeoPoints();
682 int pointCount = ZoneInfo.getGeozoneSupportedPointCount(reqState, selZone.getZoneType());
683 Vector<GeoPoint> gpList = new Vector<GeoPoint>();
684 for (int z = 0/*, p = 0*/; z < pointCount; z++) {
685 double zoneLat = StringTools.parseDouble(AttributeTools.getRequestString(request,PARM_ZONE_LATITUDE (z),null),0.0);
686 double zoneLon = StringTools.parseDouble(AttributeTools.getRequestString(request,PARM_ZONE_LONGITUDE(z),null),0.0);
687 if (GeoPoint.isValid(zoneLat,zoneLon)) {
688 //selZone.setGeoPoint(p++, zoneLat, zoneLon);
689 gpList.add(new GeoPoint(zoneLat,zoneLon));
690 }
691 }
692 selZone.setGeoPoints(gpList);
693 // -- description
694 if (!StringTools.isBlank(zoneDesc)) {
695 selZone.setDescription(zoneDesc);
696 }
697 // -- associated Purpose ID
698 if (showPurposeIDs && !selZone.getZonePurposeID().equals(zonePurpID)) {
699 selZone.setZonePurposeID(zonePurpID);
700 }
701 // -- associated GeoCorridor ID
702 if (showCorridorIDs && !selZone.getCorridorID().equals(zoneCorrID)) {
703 selZone.setCorridorID(zoneCorrID);
704 }
705 // -- save
706 if (saveOK) {
707 selZone.save();
708 m = i18n.getString("ZoneInfo.zoneUpdated","Geozone information updated"); // UserErrMsg
709 } else {
710 // -- error occurred, should stay on this page
711 editZone = true;
712 }
713 } else {
714 m = i18n.getString("ZoneInfo.noZones","There are currently no defined Geozones for this Account."); // UserErrMsg
715 }
716 } catch (Throwable t) {
717 Print.logException("Updating Geozone", t);
718 m = i18n.getString("ZoneInfo.errorUpdate","Internal error updating Geozone"); // UserErrMsg
719 error = true;
720 }
721 listZones = true;
722 }
723
724 /* final vars */
725 final String _selZoneID = selZoneID;
726 final Geozone _selZone = selZone;
727 final String _zoneList[] = zoneList;
728 final boolean _allowEdit = allowEdit;
729 final boolean _allowView = allowView;
730 final boolean _allowNew = allowNew;
731 final boolean _allowDelete = allowDelete;
732 final boolean _editZone = _allowEdit && editZone;
733 final boolean _viewZone = _editZone || viewZone;
734 final boolean _listZones = listZones || (!_editZone && !_viewZone);
735
736 /* Style */
737 HTMLOutput HTML_CSS = new HTMLOutput() {
738 public void write(PrintWriter out) throws IOException {
739 if (mapProvider != null) {
740 mapProvider.writeStyle(out, reqState);
741 }
742 String cssDir = ZoneInfo.this.getCssDirectory();
743 WebPageAdaptor.writeCssLink(out, reqState, "ZoneInfo.css", cssDir);
744 }
745 };
746
747 /* JavaScript */
748 final boolean _showFilter = showFilter; // FILTER_JS
749 HTMLOutput HTML_JS = new HTMLOutput() {
750 public void write(PrintWriter out) throws IOException {
751 MenuBar.writeJavaScript(out, pageName, reqState);
752 JavaScriptTools.writeJSInclude(out, JavaScriptTools.qualifyJSFileRef(SORTTABLE_JS), request);
753 if (!_listZones && mapSupportsGeozones) {
754
755 // MapProvider JavaScript
756 if (mapProvider != null) {
757 mapProvider.writeJavaScript(out, reqState);
758 }
759
760 /* start JavaScript */
761 JavaScriptTools.writeStartJavaScript(out);
762
763 // Geozone Javascript
764 double radiusMeters = DEFAULT_ZONE_RADIUS;
765 int zoneTypeInt = Geozone.GeozoneType.POINT_RADIUS.getIntValue(); // default
766 String zoneColor = "";
767 if (_selZone != null) {
768 zoneTypeInt = _selZone.getZoneType();
769 zoneColor = _selZone.getShapeColor();
770 double minRad = Geozone.GetMinimumRadius(zoneTypeInt);
771 double maxRad = Geozone.GetMaximumRadius(zoneTypeInt);
772 radiusMeters = _selZone.getRadiusMeters(minRad,maxRad);
773 }
774 MapDimension mapDim = (mapProvider != null)? mapProvider.getZoneDimension() : new MapDimension(-1,-1);
775 out.println("// Geozone vars");
776 out.println("jsvGeozoneMode = true;");
777 //out.println("MAP_WIDTH = " + mapDim.getWidth() + ";");
778 //out.println("MAP_HEIGHT = " + mapDim.getHeight() + ";");
779
780 JavaScriptTools.writeJSVar(out, "DEFAULT_ZONE_RADIUS", DEFAULT_ZONE_RADIUS);
781 JavaScriptTools.writeJSVar(out, "jsvZoneEditable" , _editZone);
782 JavaScriptTools.writeJSVar(out, "jsvShowVertices" , true);
783 JavaScriptTools.writeJSVar(out, "jsvZoneType" , zoneTypeInt);
784 JavaScriptTools.writeJSVar(out, "jsvZoneRadiusMeters", radiusMeters);
785 JavaScriptTools.writeJSVar(out, "jsvZoneColor" , zoneColor);
786
787 int pointCount = ZoneInfo.getGeozoneSupportedPointCount(reqState, zoneTypeInt);
788 out.write("// Geozone points\n");
789 JavaScriptTools.writeJSVar(out, "jsvZoneCount" , pointCount);
790 JavaScriptTools.writeJSVar(out, "jsvZoneIndex" , DEFAULT_POINT_INDEX);
791 out.write("var jsvZoneList = new Array(\n"); // consistent with JSMapPoint
792 for (int z = 0; z < pointCount; z++) {
793 GeoPoint gp = (_selZone != null)? _selZone.getGeoPointAt(z,null) : null;
794 if (gp == null) { gp = GeoPoint.INVALID_GEOPOINT; }
795 out.write(" { lat:" + gp.getLatitude() + ", lon:" + gp.getLongitude() + " }");
796 if ((z+1) < pointCount) { out.write(","); }
797 out.write("\n");
798 }
799 out.write(" );\n");
800
801 /* end JavaScript */
802 JavaScriptTools.writeEndJavaScript(out);
803
804 /* Geozone.js */
805 JavaScriptTools.writeJSInclude(out, JavaScriptTools.qualifyJSFileRef("Geozone.js"), request);
806
807 }
808 }
809 };
810
811 /* Content */
812 final boolean mapControlsOnLeft =
813 ListTools.containsIgnoreCase(CONTROLS_ON_LEFT,privLabel.getStringProperty(PrivateLabel.PROP_ZoneInfo_mapControlLocation,""));
814 HTMLOutput HTML_CONTENT = new HTMLOutput(CommonServlet.CSS_CONTENT_FRAME, m) {
815 public void write(PrintWriter out) throws IOException {
816 String pageName = ZoneInfo.this.getPageName();
817
818 // -- frame header
819 //String menuURL = EncodeMakeURL(reqState,RequestProperties.TRACK_BASE_URI(),PAGE_MENU_TOP);
820 String menuURL = privLabel.getWebPageURL(reqState, PAGE_MENU_TOP);
821 String editURL = ZoneInfo.this.encodePageURL(reqState);//,RequestProperties.TRACK_BASE_URI());
822 String selectURL = ZoneInfo.this.encodePageURL(reqState);//,RequestProperties.TRACK_BASE_URI());
823 String newURL = ZoneInfo.this.encodePageURL(reqState);//,RequestProperties.TRACK_BASE_URI());
824
825 // -- Geozone GlobalActive
826 boolean globalActive = Geozone.IsGlobalActive();
827
828 if (_listZones) {
829
830 // -- Geozone selection table (Select, Geozone ID, Zone Name)
831 String frameTitle = _allowEdit?
832 i18n.getString("ZoneInfo.list.viewEditZone","View/Edit Geozone Information") :
833 i18n.getString("ZoneInfo.list.viewZone","View Geozone Information");
834 out.write("<span class='"+CommonServlet.CSS_MENU_TITLE+"'>"+frameTitle+"</span><br/>\n");
835 out.write("<hr>\n");
836
837 // -- Geozone selection table (Select, Zone ID, Zone Name)
838 out.write("<span class='"+CommonServlet.CSS_ADMIN_SELECT_TITLE+"'>"+FilterText(i18n.getString("ZoneInfo.list.selectZone","Select a Geozone"))+":</span>\n");
839 out.write("<div style='margin-left:25px;'>\n");
840 out.write("<form name='"+FORM_ZONE_SELECT+"' method='post' action='"+selectURL+"' target='_self'>"); // target='_top'
841 out.write("<input type='hidden' name='"+PARM_COMMAND+"' value='"+COMMAND_INFO_SELECT+"'/>");
842 out.write("<table class='"+CommonServlet.CSS_ADMIN_SELECT_TABLE+"' id='filter-table' cellspacing=0 cellpadding=0 border=0>\n");
843 out.write(" <thead>\n");
844 out.write(" <tr class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_ROW+"'>\n");
845 out.write(" <th class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_COL_SEL+"'>"+FilterText(i18n.getString("ZoneInfo.list.select","Select"))+"</th>\n");
846 out.write(" <th class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_COL +"'>"+FilterText(i18n.getString("ZoneInfo.list.zoneID","Geozone ID"))+"</th>\n");
847 out.write(" <th class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_COL +"'>"+FilterText(i18n.getString("ZoneInfo.list.description","Description\n(Address)"))+"</th>\n");
848 if (!globalActive) {
849 out.write(" <th class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_COL +"'>"+FilterText(i18n.getString("ZoneInfo.list.active","Active"))+"</th>\n");
850 }
851 if (showOverlapPriority) {
852 out.write(" <th class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_COL +"'>"+FilterText(i18n.getString("ZoneInfo.list.overlapPriority","Overlap\nPriority"))+"</th>\n");
853 }
854 out.write(" <th class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_COL +"'>"+FilterText(i18n.getString("ZoneInfo.list.zoneType","Zone\nType"))+"</th>\n");
855 if (showRevGeocodeZone) {
856 out.write(" <th class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_COL +"'>"+FilterText(i18n.getString("ZoneInfo.list.revGeocode","Reverse\nGeocode"))+"</th>\n");
857 }
858 if (showArriveDepartZone) {
859 out.write(" <th class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_COL +"'>"+FilterText(i18n.getString("ZoneInfo.list.arriveZone","Arrival\nZone"))+"</th>\n");
860 out.write(" <th class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_COL +"'>"+FilterText(i18n.getString("ZoneInfo.list.departZone","Departure\nZone"))+"</th>\n");
861 }
862 if (showClientUploadZone == 1) {
863 out.write(" <th class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_COL +"'>"+FilterText(i18n.getString("ZoneInfo.list.clientUpload","Device\nUpload"))+"</th>\n");
864 } else
865 if (showClientUploadZone == 2) {
866 out.write(" <th class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_COL +"'>"+FilterText(i18n.getString("ZoneInfo.list.clientUploadID","Device\nUpload ID"))+"</th>\n");
867 }
868 out.write(" <th class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_COL +"'>"+FilterText(i18n.getString("ZoneInfo.list.radiusMeters","Radius\n(meters)"))+"</th>\n");
869 out.write(" <th class='"+CommonServlet.CSS_ADMIN_TABLE_HEADER_COL +"'>"+FilterText(i18n.getString("ZoneInfo.list.centerPoint","Center\nLatitude/Longitude"))+"</th>\n");
870 out.write(" </tr>\n");
871 out.write(" </thead>\n");
872
873 /* geozone list */
874 out.write(" <tbody>\n");
875 int pointRadiusType = Geozone.GeozoneType.POINT_RADIUS.getIntValue();
876 int polygonType = Geozone.GeozoneType.POLYGON.getIntValue();
877 int corridorType = Geozone.GeozoneType.SWEPT_POINT_RADIUS.getIntValue();
878 for (int z = 0, r = 0; z < _zoneList.length; z++) {
879
880 /* get Geozone */
881 Geozone zone = null;
882 try {
883 zone = Geozone.getGeozone(currAcct, _zoneList[z], DEFAULT_SORT_ID, false);
884 } catch (DBException dbe) {
885 // error
886 }
887 if (zone == null) {
888 continue; // skip
889 }
890
891 /* geozone vars */
892 int zoneTypeInt = zone.getZoneType();
893 boolean zoneIsPOI = Geozone.isPointOfInterest(zone);
894 String zoneID = FilterText(zone.getGeozoneID());
895 String zoneDesc = FilterText(zone.getDescription());
896 String zoneActive = FilterText(ComboOption.getYesNoText(locale,zone.getIsActive()));
897 String zoneTypeStr = FilterText(zone.getZoneTypeDescription(locale));
898 String zoneRevGeo = FilterText(!zoneIsPOI?ComboOption.getYesNoText(locale,zone.getReverseGeocode()):"--");
899 String zoneRadius = zone.hasRadius()? String.valueOf(zone.getRadius()) : "--";
900 GeoPoint centerPt = zone.getGeoPointAt(DEFAULT_POINT_INDEX,null); // may be null if invalid
901 if (centerPt == null) { centerPt = new GeoPoint(0.0, 0.0); }
902 String zoneCenter = centerPt.getLatitudeString(GeoPoint.SFORMAT_DEC_5,null) + " "+GeoPoint.PointSeparator+" " + centerPt.getLongitudeString(GeoPoint.SFORMAT_DEC_5,null);
903 String checked = _selZoneID.equals(zone.getGeozoneID())? "checked" : "";
904 String styleClass = ((r++ & 1) == 0)? CommonServlet.CSS_ADMIN_TABLE_BODY_ROW_ODD : CommonServlet.CSS_ADMIN_TABLE_BODY_ROW_EVEN;
905
906 int pointCount = ZoneInfo.getGeozoneSupportedPointCount(reqState, zoneTypeInt);
907 String typeColor = (pointCount > 0)? "black" : "red";
908
909 out.write(" <tr class='" + styleClass + "'>\n");
910 out.write(" <td class='"+CommonServlet.CSS_ADMIN_TABLE_BODY_COL_SEL+"' "+SORTTABLE_SORTKEY+"='"+z+"'>");
911 if (pointCount <= 0) {
912 out.write(" "); // not supported
913 } else
914 if ((zoneTypeInt == pointRadiusType) || (zoneTypeInt == polygonType) || (zoneTypeInt == corridorType)) {
915 out.write("<input type='radio' name='"+PARM_ZONE_SELECT+"' id='"+zoneID+"' value='"+zoneID+"' "+checked+">");
916 } else {
917 out.write(" "); // unrecognized type
918 }
919 out.write( "</td>\n");
920 out.write(" <td class='"+CommonServlet.CSS_ADMIN_TABLE_BODY_COL +"' nowrap><label for='"+zoneID+"'>"+zoneID+"</label></td>\n");
921 out.write(" <td class='"+CommonServlet.CSS_ADMIN_TABLE_BODY_COL +"' nowrap>"+zoneDesc+"</td>\n");
922 if (!globalActive) {
923 out.write(" <td class='"+CommonServlet.CSS_ADMIN_TABLE_BODY_COL +"' nowrap>"+zoneActive+"</td>\n");
924 }
925 if (showOverlapPriority) {
926 String zonePriority = FilterText(!zoneIsPOI?String.valueOf(zone.getPriority()):"--");
927 out.write(" <td class='"+CommonServlet.CSS_ADMIN_TABLE_BODY_COL +"' nowrap>"+zonePriority+"</td>\n");
928 }
929 out.write(" <td class='"+CommonServlet.CSS_ADMIN_TABLE_BODY_COL +"' nowrap style='color:"+typeColor+"'>"+zoneTypeStr+"</td>\n");
930 if (showRevGeocodeZone) {
931 out.write(" <td class='"+CommonServlet.CSS_ADMIN_TABLE_BODY_COL +"' nowrap>"+zoneRevGeo+"</td>\n");
932 }
933 if (showArriveDepartZone) {
934 String zoneArrNtfy = FilterText(!zoneIsPOI?ComboOption.getYesNoText(locale,zone.getArrivalZone()):"--");
935 String zoneDepNtfy = FilterText(!zoneIsPOI?ComboOption.getYesNoText(locale,zone.getDepartureZone()):"--");
936 out.write(" <td class='"+CommonServlet.CSS_ADMIN_TABLE_BODY_COL +"' nowrap>"+zoneArrNtfy+"</td>\n");
937 out.write(" <td class='"+CommonServlet.CSS_ADMIN_TABLE_BODY_COL +"' nowrap>"+zoneDepNtfy+"</td>\n");
938 }
939 if (showClientUploadZone == 1) {
940 String zoneUpload = FilterText(!zoneIsPOI?ComboOption.getYesNoText(locale,zone.getClientUpload()||(zone.getClientID() > 0)):"--");
941 out.write(" <td class='"+CommonServlet.CSS_ADMIN_TABLE_BODY_COL +"' nowrap>"+zoneUpload+"</td>\n");
942 } else
943 if (showClientUploadZone == 2) {
944 String zoneUpldID = (zone.getClientID() > 0)? String.valueOf(zone.getClientID()) : "--";
945 out.write(" <td class='"+CommonServlet.CSS_ADMIN_TABLE_BODY_COL +"' nowrap>"+zoneUpldID+"</td>\n");
946 }
947 out.write(" <td class='"+CommonServlet.CSS_ADMIN_TABLE_BODY_COL +"' nowrap>"+zoneRadius+"</td>\n");
948 out.write(" <td class='"+CommonServlet.CSS_ADMIN_TABLE_BODY_COL +"' nowrap>"+zoneCenter+"</td>\n");
949 out.write(" </tr>\n");
950
951 }
952 out.write(" </tbody>\n");
953 out.write("</table>\n");
954 out.write("<table cellpadding='0' cellspacing='0' border='0' style='width:95%; margin-top:5px; margin-left:5px; margin-bottom:5px;'>\n");
955 out.write("<tr>\n");
956 if (_allowView ) {
957 out.write("<td style='padding-left:5px;'>");
958 out.write("<input type='submit' name='"+PARM_SUBMIT_VIEW+"' value='"+i18n.getString("ZoneInfo.list.view","View")+"'>");
959 out.write("</td>\n");
960 }
961 if (_allowEdit ) {
962 out.write("<td style='padding-left:5px;'>");
963 out.write("<input type='submit' name='"+PARM_SUBMIT_EDIT+"' value='"+i18n.getString("ZoneInfo.list.edit","Edit")+"'>");
964 out.write("</td>\n");
965 }
966 out.write("<td style='width:100%; text-align:right; padding-right:10px;'>");
967 if (_allowDelete) {
968 out.write("<input type='submit' name='"+PARM_SUBMIT_DEL+"' value='"+i18n.getString("ZoneInfo.list.delete","Delete")+"' "+Onclick_ConfirmDelete(locale)+">");
969 } else {
970 out.write(" ");
971 }
972 out.write("</td>\n");
973 out.write("</tr>\n");
974 out.write("</table>\n");
975
976 out.write("</form>\n");
977 out.write("</div>\n");
978 out.write("<hr>\n");
979
980 /* new Geozone */
981 if (_allowNew) {
982 out.write("<h1 class='"+CommonServlet.CSS_ADMIN_SELECT_TITLE+"'>"+FilterText(i18n.getString("ZoneInfo.list.createNewZone","Create a new Geozone"))+":</h1>\n");
983 out.write("<div style='margin-top:5px; margin-left:5px; margin-bottom:5px;'>\n");
984 out.write("<form name='"+FORM_ZONE_NEW+"' method='post' action='"+newURL+"' target='_self'>"); // target='_top'
985 out.write(" <input type='hidden' name='"+PARM_COMMAND+"' value='"+COMMAND_INFO_NEW+"'/>");
986 out.write(FilterText(i18n.getString("ZoneInfo.list.zoneID","Geozone ID"))+": <input type='text' class='"+CommonServlet.CSS_TEXT_INPUT+"' name='"+PARM_NEW_ID+"' value='' size='32' maxlength='32'>");
987 int polyPointCount = ZoneInfo.getGeozoneSupportedPointCount(reqState,polygonType );
988 int corrPointCount = ZoneInfo.getGeozoneSupportedPointCount(reqState,corridorType);
989 if ((polyPointCount > 0) || (corrPointCount > 0)) {
990 ComboMap zoneTypeList = new ComboMap();
991 out.write(" ");
992 zoneTypeList.add(String.valueOf(pointRadiusType) , Geozone.GeozoneType.POINT_RADIUS.toString(locale));
993 if (polyPointCount > 0) {
994 zoneTypeList.add(String.valueOf(polygonType) , Geozone.GeozoneType.POLYGON.toString(locale));
995 }
996 if (corrPointCount > 0) {
997 zoneTypeList.add(String.valueOf(corridorType), Geozone.GeozoneType.SWEPT_POINT_RADIUS.toString(locale));
998 }
999 out.print(Form_ComboBox(PARM_NEW_TYPE,PARM_NEW_TYPE,true,zoneTypeList,"","", -1));
1000 } else {
1001 // only POINT_RADIUS supported
1002 }
1003 out.write("<br>\n");
1004 out.write(" <input type='submit' name='"+PARM_SUBMIT_NEW+"' value='"+i18n.getString("ZoneInfo.list.new","New")+"' style='margin-top:5px; margin-left:10px;'>\n");
1005 out.write("</form>\n");
1006 out.write("</div>\n");
1007 out.write("<hr>\n");
1008 }
1009
1010 } else {
1011
1012 // -- view/edit
1013 int selZoneType = (_selZone != null)? _selZone.getZoneType() : Geozone.GeozoneType.POINT_RADIUS.getIntValue();
1014 boolean selZoneIsPOI = Geozone.isPointOfInterest(_selZone); // false if _selZone is null
1015
1016 // -- begin form
1017 out.println("<form name='"+FORM_ZONE_EDIT+"' method='post' action='"+editURL+"' target='_self'>"); // target='_top'
1018
1019 // -- Geozone view/edit form
1020 out.write("<table cellspacing='0' cellpadding='0' border='0'><tr>\n");
1021 out.write("<td nowrap>");
1022 String frameTitle = _editZone?
1023 i18n.getString("ZoneInfo.map.editZone","Edit Geozone") :
1024 i18n.getString("ZoneInfo.map.viewZone","View Geozone");
1025 out.print ("<span style='font-size:9pt; font-weight:bold;'>"+frameTitle+" </span>");
1026 out.print (Form_TextField(PARM_ZONE_SELECT, false, _selZoneID, 16, 20));
1027 out.write("</td>");
1028 out.write("<td nowrap style=\"width:100%; text-align:right;\">");
1029 //out.println("<span style='width:100%;'> </span>"); <-- causes IE to NOT display the following description
1030 String i18nAddressTooltip = i18n.getString("ZoneInfo.map.description.tooltip", "This description is used for custom reverse-geocoding");
1031 out.print ("<span class='zoneDescription' style='width:100%;' title=\""+i18nAddressTooltip+"\">");
1032 out.print ("<b>"+i18n.getString("ZoneInfo.map.description","Description (Address)")+"</b>: ");
1033 out.print (Form_TextField(PARM_ZONE_DESC, _editZone, (_selZone!=null)?_selZone.getDescription():"", 30, 64));
1034 out.println("</span>");
1035 out.write("</td>");
1036 out.write("</tr></table>");
1037
1038 //out.println("<br/>");
1039 out.println("<input type='hidden' name='"+PARM_COMMAND+"' value='"+COMMAND_INFO_UPDATE+"'/>");
1040
1041 out.println("<table border='0' cellpadding='0' cellspacing='0' style='padding-top:3px'>"); // {
1042 out.println("<tr>");
1043
1044 /* map (controls on right) */
1045 MapDimension mapDim = (mapProvider != null)? mapProvider.getZoneDimension() : new MapDimension(-1,-1);
1046 if (!mapControlsOnLeft) {
1047 String mapWidth = (mapDim.getWidth() <= 0)? "100%" : String.valueOf(mapDim.getWidth()) +"px";
1048 String mapHeight = (mapDim.getHeight() <= 0)? "100%" : String.valueOf(mapDim.getHeight())+"px";
1049 if (mapSupportsGeozones) {
1050 out.println("<!-- Begin Map -->");
1051 out.println("<td style='width:"+mapWidth+"; height:"+mapHeight+"; padding-right:5px;'>");
1052 mapProvider.writeMapCell(out, reqState, mapDim);
1053 out.println("</td>");
1054 out.println("<!-- End Map -->");
1055 } else {
1056 out.println("<td style='width:"+mapWidth+"; height:"+mapHeight+"; padding-right:5px; border: 1px solid black;'>");
1057 out.println("<!-- Geozones not yet supported for this MapProvider -->");
1058 out.println("<center>");
1059 out.println("<span style='font-size:12pt;'>");
1060 out.println(i18n.getString("ZoneInfo.map.notSupported","Geozone map not yet supported for this MapProvider"));
1061 out.println(" </span>");
1062 out.println("</center>");
1063 out.println("</td>");
1064 }
1065 }
1066
1067 /* Geozone fields */
1068 out.println("<td valign='top' style='width:230px; min-width:230px; border-top: solid #CCCCCC 1px;'>");
1069
1070 // -- active
1071 if (!Geozone.IsGlobalActive()) {
1072 String i18nActiveTooltip = i18n.getString("ZoneInfo.map.active.tooltip", "Select to enable/activate this Geozone");
1073 out.println("<div class='zoneCheckSelect' title=\""+i18nActiveTooltip+"\">");
1074 out.println(Form_CheckBox(PARM_ZONE_ACTIVE, PARM_ZONE_ACTIVE, _editZone, ((_selZone!=null) && _selZone.getIsActive()),null,null));
1075 out.println("<b><label for='"+PARM_ZONE_ACTIVE+"'>"+i18n.getString("ZoneInfo.map.active","Active")+"</label></b>");
1076 out.println("</div>");
1077 }
1078
1079 // -- overlap priority
1080 if (showOverlapPriority && !selZoneIsPOI) {
1081 String i18nPriorityTooltip = i18n.getString("ZoneInfo.map.overlapPriority.tooltip", "Priority used when multiple Geozones overlap");
1082 out.println("<div class='zonePrioritySelect' title=\""+i18nPriorityTooltip+"\">");
1083 int pri = (_selZone != null)? _selZone.getPriority() : 0;
1084 if (pri < 0) {
1085 pri = 0;
1086 } else
1087 if (pri >= OVERLAP_PRIORITY.length) {
1088 pri = OVERLAP_PRIORITY.length - 1;
1089 }
1090 ComboMap priCombo = new ComboMap(OVERLAP_PRIORITY);
1091 String priSel = OVERLAP_PRIORITY[pri];
1092 out.println("<b><label for='"+PARM_PRIORITY+"'>"+i18n.getString("ZoneInfo.map.overlapPriority","Overlap Priority")+": </label></b>");
1093 out.println(Form_ComboBox(PARM_PRIORITY, PARM_PRIORITY, _editZone, priCombo, priSel, null, 6));
1094 out.println("</div>");
1095 }
1096
1097 // -- show assigned device group
1098 if (showAssignedDevGroup && !selZoneIsPOI) {
1099 String acctID = currAcct.getAccountID();
1100 String userID = (currUser != null)? currUser.getUserID() : User.getAdminUserID();
1101 java.util.List<String> devGrps = null;
1102 boolean limitToGroups = privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_limitToUserDeviceGroups,false);
1103 if (limitToGroups && !User.isAdminUser(userID)) {
1104 // -- specific user authorized groups
1105 try {
1106 java.util.List<String> grps = User.getExplicitlyAuthorizedDeviceGroupIDs(DBReadWriteMode.READ_WRITE,acctID,userID,-1L);
1107 if (!ListTools.isEmpty(grps)) {
1108 devGrps = new Vector<String>(grps);
1109 }
1110 } catch (DBException dbe) {
1111 devGrps = null;
1112 }
1113 } else {
1114 // -- admin user
1115 try {
1116 boolean includeAll = true;
1117 java.util.List<String> grps = DeviceGroup.getDeviceGroupsForAccount(DBReadWriteMode.READ_WRITE,acctID,includeAll);
1118 if (!ListTools.isEmpty(grps)) {
1119 devGrps = grps;
1120 }
1121 } catch (DBException dbe) {
1122 devGrps = null;
1123 }
1124 }
1125 if (!ListTools.isEmpty(devGrps)) {
1126 String i18nGroupTooltip = i18n.getString("ZoneInfo.map.deviceGroups.tooltip", "Select to Assign Group to Geozone");
1127 //for (String dg : devGrps) { Print.logInfo(" Device Group: " + dg); }
1128 ComboMap grpMap = new ComboMap(devGrps);
1129 String selGrp = (_selZone!=null)? _selZone.getGroupID() : null;
1130 if (StringTools.isBlank(selGrp)) {
1131 selGrp = DeviceGroup.DEVICE_GROUP_ALL;
1132 }
1133 out.println("<div class='zoneGroupSelect' title=\""+i18nGroupTooltip+"\">");
1134 out.println("<label for='"+PARM_GROUP_SELECT+"'><b>"+i18n.getString("ZoneInfo.assignGroup","Assign Group")+"</b></label>");
1135 out.println(Form_ComboBox(PARM_GROUP_SELECT, PARM_GROUP_SELECT, _editZone, grpMap, selGrp, null/*onchange*/));
1136 out.println("</div>");
1137 }
1138 }
1139
1140 // -- reverse-geocode zone
1141 if (showRevGeocodeZone && !selZoneIsPOI) {
1142 String i18nRevGeoTooltip = i18n.getString("ZoneInfo.map.reverseGeocode.tooltip", "Select to use this zone for custom reverse-geocoding");
1143 out.println("<div class='zoneCheckSelect' title=\""+i18nRevGeoTooltip+"\">");
1144 out.println(Form_CheckBox(PARM_REV_GEOCODE, PARM_REV_GEOCODE, _editZone, ((_selZone!=null) && _selZone.getReverseGeocode()),null,null));
1145 out.println("<b><label for='"+PARM_REV_GEOCODE+"'>"+i18n.getString("ZoneInfo.map.reverseGeocode","Reverse Geocode")+"</label></b>");
1146 out.println("</div>");
1147 }
1148
1149 // -- arrival zone
1150 if (showArriveDepartZone && !selZoneIsPOI) {
1151 String i18nArriveTooltip = i18n.getString("ZoneInfo.map.arrivalZone.tooltip", "Select to use this zone for 'Arrival' checking");
1152 boolean checked = ((_selZone!=null) && _selZone.getArrivalZone())? true : false;
1153 out.println("<div class='zoneCheckSelect' title=\""+i18nArriveTooltip+"\">");
1154 if (showArriveDepartCode) {
1155 int sc = (_selZone != null)? _selZone.getArrivalStatusCode() : StatusCodes.STATUS_GEOFENCE_ARRIVE;
1156 String sck = "0x" + StringTools.toHexString(sc,16);
1157 ComboMap scm = ZoneInfo.getArrivalCodeComboMap(privLabel);
1158 String chg = _editZone? "javascript:document."+FORM_ZONE_EDIT+"."+PARM_ARRIVE_CODE+".disabled=!document."+FORM_ZONE_EDIT+"."+PARM_ARRIVE_NOTIFY+".checked;" : null;
1159 out.println(Form_CheckBox(PARM_ARRIVE_NOTIFY, PARM_ARRIVE_NOTIFY, _editZone, checked,null,chg));
1160 out.println("<b><label for='"+PARM_ARRIVE_NOTIFY+"'>"+i18n.getString("ZoneInfo.map.arrival","Arrive")+"</label></b> ");
1161 out.println(Form_ComboBox(PARM_ARRIVE_CODE, PARM_ARRIVE_CODE, _editZone && checked, scm, sck, null, 14));
1162 } else {
1163 out.println(Form_CheckBox(PARM_ARRIVE_NOTIFY, PARM_ARRIVE_NOTIFY, _editZone, checked,null,null));
1164 out.println("<b><label for='"+PARM_ARRIVE_NOTIFY+"'>"+i18n.getString("ZoneInfo.map.arrivalZone","Arrival Zone")+"</label></b>");
1165 }
1166 out.println("</div>");
1167 }
1168
1169 // -- departure zone
1170 if (showArriveDepartZone && !selZoneIsPOI) {
1171 String i18nDepartTooltip = i18n.getString("ZoneInfo.map.departureZone.tooltip", "Select to use this zone for 'Departure' checking");
1172 boolean checked = ((_selZone!=null) && _selZone.getDepartureZone())? true : false;
1173 out.println("<div class='zoneCheckSelect' title=\""+i18nDepartTooltip+"\">");
1174 if (showArriveDepartCode) {
1175 int sc = (_selZone != null)? _selZone.getDepartureStatusCode() : StatusCodes.STATUS_GEOFENCE_DEPART;
1176 String sck = "0x" + StringTools.toHexString(sc,16);
1177 ComboMap scm = ZoneInfo.getDepartureCodeComboMap(privLabel);
1178 String chg = _editZone? "javascript:document."+FORM_ZONE_EDIT+"."+PARM_DEPART_CODE+".disabled=!document."+FORM_ZONE_EDIT+"."+PARM_DEPART_NOTIFY+".checked;" : null;
1179 out.println(Form_CheckBox(PARM_DEPART_NOTIFY, PARM_DEPART_NOTIFY, _editZone, checked,null,chg));
1180 out.println("<b><label for='"+PARM_DEPART_NOTIFY+"'>"+i18n.getString("ZoneInfo.map.departure","Depart")+"</label></b> ");
1181 out.println(Form_ComboBox(PARM_DEPART_CODE, PARM_DEPART_CODE, _editZone && checked, scm, sck, null, 14));
1182 } else {
1183 out.println(Form_CheckBox(PARM_DEPART_NOTIFY, PARM_DEPART_NOTIFY, _editZone, checked,null,null));
1184 out.println("<b><label for='"+PARM_DEPART_NOTIFY+"'>"+i18n.getString("ZoneInfo.map.departureZone","Departure Zone")+"</label></b>");
1185 }
1186 out.println("</div>");
1187 }
1188
1189 // -- auto notify
1190 if (showArriveDepartZone && showAutoNotify && !selZoneIsPOI) {
1191 String i18nAutoTooltip = i18n.getString("ZoneInfo.map.autoNotify.tooltip", "Select to automatically send notification on arrive/depart");
1192 out.println("<div class='zoneCheckSelect' title=\""+i18nAutoTooltip+"\">");
1193 out.println(Form_CheckBox(PARM_AUTO_NOTIFY, PARM_AUTO_NOTIFY, _editZone, ((_selZone!=null) && _selZone.getAutoNotify()),null,null));
1194 out.println("<b><label for='"+PARM_AUTO_NOTIFY+"'>"+i18n.getString("ZoneInfo.map.autoNotify","Auto Notify")+"</label></b>");
1195 out.println("</div>");
1196 }
1197
1198 // -- Client Upload ID
1199 if ((showClientUploadZone != 0) && !selZoneIsPOI) {
1200 String i18nUploadTooltip = i18n.getString("ZoneInfo.map.clientUpload.tooltip", "Select to use for client-side geofence");
1201 out.println("<div class='zoneCheckSelect' title=\""+i18nUploadTooltip+"\">");
1202 if (showClientUploadZone == 1) {
1203 out.println(Form_CheckBox(PARM_CLIENT_UPLOAD, PARM_CLIENT_UPLOAD, _editZone, ((_selZone!=null) && _selZone.getClientUpload()),null,null));
1204 out.println("<b><label for='"+PARM_CLIENT_UPLOAD+"'>"+i18n.getString("ZoneInfo.map.clientUpload","Device Upload")+":</label></b> ");
1205 } else
1206 if (showClientUploadZone == 2) {
1207 out.println("<b>"+i18n.getString("ZoneInfo.map.clientUploadID","Device Upload ID")+":</b> ");
1208 out.println(Form_TextField(PARM_CLIENT_ID, PARM_CLIENT_ID, _editZone, (_selZone!=null)?String.valueOf(_selZone.getClientID()):"", 5, 5));
1209 }
1210 out.println("</div>");
1211 }
1212
1213 // -- geozone points section
1214 out.println("<hr>");
1215
1216 /* notes */
1217 if (_editZone && mapSupportsGeozones) {
1218 out.println("<div class='zoneNotesBasic'>");
1219 //out.println("<i>"+i18nx.getString("ZoneInfo.map.notes.basic", "The Geozone loc/size may be changed here, click 'RESET' to update.")+"</i>");
1220 out.println("<i>"+i18n.getString("ZoneInfo.map.notes.basic", "Geozone attributes:")+"</i>");
1221 out.println("</div>");
1222 }
1223
1224 /* shape color */
1225 if (privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_showShapeColor,false) && !selZoneIsPOI) {
1226 ComboMap colorCombo = GetColorComboMap(i18n);
1227 String color = (_selZone != null)? _selZone.getShapeColor() : "";
1228 String onchange = _editZone? "javascript:jsvZoneColor=document."+FORM_ZONE_EDIT+"."+PARM_ZONE_COLOR+".value;_zoneReset();" : null;
1229 out.println("<div class='zoneColorSelect' title=\""+""+"\">");
1230 out.println("<b><label for='"+PARM_ZONE_COLOR+"'>"+i18n.getString("ZoneInfo.map.shapeColor","Zone Color")+": </label></b>");
1231 out.println(Form_ComboBox(PARM_ZONE_COLOR, PARM_ZONE_COLOR, _editZone, colorCombo, color, onchange, 10));
1232 out.println("</div>");
1233 }
1234
1235 /* pushpin (show description pushpin on maps) */
1236 if (privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_showPushpins,false) || selZoneIsPOI) {
1237 // -- TODO: this should also show the pushpin image
1238 ComboMap ppCombo = GetPushpinComboMap(i18n, reqState);
1239 String ppID = (_selZone != null)? _selZone.getIconName() : "";
1240 out.println("<div class='zonePushpinSelect' title=\""+""+"\">");
1241 out.println("<b><label for='"+PARM_ZONE_PUSHPIN+"'>"+i18n.getString("ZoneInfo.map.pushpin","Pushpin")+": </label></b>");
1242 out.println(Form_ComboBox(PARM_ZONE_PUSHPIN, PARM_ZONE_PUSHPIN, _editZone, ppCombo, ppID, null/*onchange*/, 12));
1243 out.println("</div>");
1244 }
1245
1246 /* radius */
1247 Geozone.GeozoneType gzt = Geozone.getGeozoneType(_selZone);
1248 if (gzt.hasRadius()) {
1249 double minRad = Geozone.GetMinimumRadius(gzt.getIntValue());
1250 double maxRad = Geozone.GetMaximumRadius(gzt.getIntValue());
1251 String i18nRadiusTooltip = i18n.getString("ZoneInfo.map.radius.tooltip", "Radius may be between {0} and {1} meters",
1252 String.valueOf((long)minRad), String.valueOf((long)maxRad));
1253 out.println("<div class='zoneRadius' title=\""+i18nRadiusTooltip+"\">");
1254 out.print ("<b>"+i18n.getString("ZoneInfo.map.radiusMeters","Radius (meters)")+":</b> ");
1255 out.println(Form_TextField(MapProvider.ID_ZONE_RADIUS_M, PARM_ZONE_RADIUS, _editZone, (_selZone!=null)?String.valueOf(_selZone.getRadius()):"", 7, 7));
1256 out.println("</div>");
1257 } else {
1258 out.println("<input type='hidden' id='"+MapProvider.ID_ZONE_RADIUS_M+"' name='"+PARM_ZONE_RADIUS+"' value='0'/>");
1259 }
1260
1261 out.println("<div class='zoneLatLon'>");
1262 out.println("<b>"+i18n.getString("ZoneInfo.map.latLon","Lat/Lon")+"</b>: ");
1263 if (_editZone && mapSupportsGeozones) {
1264 String i18nResetBtn = i18n.getString("ZoneInfo.map.reset","Reset Map");
1265 String i18nResetTooltip = i18n.getString("ZoneInfo.map.reset.tooltip", "Click to update the map with the specified radius/latitude/longitude");
1266 out.print("<input class='formButton' type='button' name='reset' value='"+i18nResetBtn+"' title=\""+i18nResetTooltip+"\" onclick=\"javascript:_zoneReset();\">");
1267 }
1268 out.println("<br>");
1269 out.println("<div style='height:200px; overflow-y:auto;'>"); // beginning of vertice list
1270 int pointCount = ZoneInfo.getGeozoneSupportedPointCount(reqState, selZoneType);
1271 for (int z = 0; z < pointCount; z++) {
1272 GeoPoint gp = _selZone.getGeoPointAt(z,null);
1273 double gpLat = (gp != null)? gp.getLatitude() : 0.0;
1274 double gpLon = (gp != null)? gp.getLongitude() : 0.0;
1275 String latStr = (_selZone != null)? String.valueOf(gpLat) : "";
1276 String lonStr = (_selZone != null)? String.valueOf(gpLon) : "";
1277 // -- id='"+PARM_ZONE_INDEX+"'
1278 if (pointCount > 1) {
1279 String chk = (z == 0)? " checked" : "";
1280 out.println("<input type='radio' name='"+PARM_ZONE_INDEX+"' value='" + z + "' "+chk+" onclick=\"javascript:_zonePointSelectionChanged("+z+")\"/> ");
1281 // onchange=
1282 } else {
1283 out.println("<input type='hidden' name='"+PARM_ZONE_INDEX+"' value='" + z + "'/>");
1284 }
1285 String latCSS = _editZone? "zoneLatLonText" : "zoneLatLonText_ro";
1286 String lonCSS = _editZone? "zoneLatLonText" : "zoneLatLonText_ro";
1287 out.println(Form_TextField(MapProviderAdapter.ID_ZONE_LATITUDE (z), PARM_ZONE_LATITUDE (z), _editZone, latStr, null, 7, 9, latCSS));
1288 out.println(Form_TextField(MapProviderAdapter.ID_ZONE_LONGITUDE(z), PARM_ZONE_LONGITUDE(z), _editZone, lonStr, null, 8, 10, lonCSS));
1289 if ((z+1) < pointCount) { out.println("<br>"); }
1290 }
1291 out.println("</div>"); // end of vertice list
1292 // -- Speed limit
1293 if (mapSupportsGeozones && showSpeedLimit && !selZoneIsPOI) {
1294 Account.SpeedUnits speedUnit = Account.getSpeedUnits(currAcct); // not null
1295 double kphLimit = (_selZone != null)? _selZone.getSpeedLimitKPH() : 0.0;
1296 double speedLimit = speedUnit.convertFromKPH(kphLimit);
1297 out.print("<hr>\n");
1298 out.println("<div class='zoneSpeedLimit' title=\""+""+"\">");
1299 out.println("<b>"+i18n.getString("ZoneInfo.speedLimit","Speed Limit ({0})",speedUnit.toString(locale))+":</b>");
1300 out.println(Form_TextField(PARM_SPEED_LIMIT, PARM_SPEED_LIMIT, _editZone, String.valueOf(speedLimit), 5, 5));
1301 out.println("</div>");
1302 }
1303 // Purpose
1304 if (showPurposeIDs) {
1305 String purpID = (_selZone != null)? _selZone.getZonePurposeID() : "";
1306 String Pstr = privLabel.getStringProperty(PrivateLabel.PROP_ZoneInfo_zonePurposeList,null);
1307 String P[] = !StringTools.isBlank(Pstr)? StringTools.split(Pstr,',') : null;
1308 out.print("<hr>\n");
1309 out.println("<div class='zonePurposeID' title=\""+""+"\">");
1310 out.println("<b>"+i18n.getString("ZoneInfo.purposeID","Purpose")+":</b> ");
1311 if (!ListTools.isEmpty(P)) {
1312 ComboMap purpMap = new ComboMap(P);
1313 if (!ListTools.contains(P,purpID)) { purpMap.add(purpID); }
1314 out.println(Form_ComboBox(PARM_PURPOSE_ID, PARM_PURPOSE_ID, _editZone, purpMap, purpID, null/*onchange*/));
1315 } else {
1316 out.println(Form_TextField(PARM_PURPOSE_ID, PARM_PURPOSE_ID, _editZone, purpID, 16, 30));
1317 }
1318 out.println("</div>");
1319 }
1320 // GeoCorridor
1321 if (showCorridorIDs && !selZoneIsPOI) {
1322 String corrID = (_selZone != null)? _selZone.getCorridorID() : "";
1323 out.print("<hr>\n");
1324 out.println("<div class='zoneCorridorID' title=\""+""+"\">");
1325 out.println("<b>"+i18n.getString("ZoneInfo.corridorID","Corridor ID")+":</b>");
1326 out.println("<br>");
1327 out.println(Form_TextField(PARM_CORRIDOR_ID, PARM_CORRIDOR_ID, _editZone, corrID, 24, 30));
1328 out.println("</div>");
1329 }
1330 // "Center On Zip/Address"
1331 if (_editZone && mapSupportsGeozones) {
1332 // "ZipCode" button
1333 if (privLabel.getBooleanProperty(PrivateLabel.PROP_ZoneInfo_enableGeocode,false)) {
1334 GeocodeProvider gcp = privLabel.getGeocodeProvider();
1335 String dftCountryCode = privLabel.getStringProperty(PrivateLabel.PROP_ZoneInfo_enableGeocode_country,"US");
1336 String i18nZipBtn = "";
1337 if ((gcp == null) || gcp.getName().startsWith("geonames")) {
1338 i18nZipBtn = i18n.getString("ZoneInfo.map.geocodeZip","Center On City/ZipCode");
1339 } else {
1340 i18nZipBtn = i18n.getString("ZoneInfo.map.geocodeAddress","Center On Address", gcp.getName());
1341 }
1342 String i18nZipTooltip = i18n.getString("ZoneInfo.map.geocode.tooltip", "Click to reset Geozone to spcified Address/ZipCode");
1343 String rgZipCode_text = "rgZipCode";
1344 out.print("<hr>\n");
1345 //out.print("<br>");
1346 out.print("<input class='formButton' type='button' name='tozip' value='"+i18nZipBtn+"' title=\""+i18nZipTooltip+"\" onclick=\"javascript:_zoneGotoAddr(jsmGetIDValue('"+rgZipCode_text+"'),'"+dftCountryCode+"');\">");
1347 out.print("<br>");
1348 out.println(Form_TextField(rgZipCode_text, rgZipCode_text, _editZone, "", 27, 60));
1349 }
1350 }
1351 out.println("</div>");
1352
1353 out.println("<hr>");
1354 out.println("<div class='zoneInstructions'>");
1355 out.println("<b>"+i18n.getString("ZoneInfo.map.notes.header","Geozone Notes/Instructions")+":</b><br>");
1356 if (_editZone && mapSupportsGeozones) {
1357 String instr[] = mapProvider.getGeozoneInstructions(selZoneType, locale);
1358 if ((instr != null) && (instr.length > 0)) {
1359 for (int i = 0; i < instr.length; i++) {
1360 if (!StringTools.isBlank(instr[i])) {
1361 out.println("- " + FilterText(instr[i]) + "<br>");
1362 }
1363 }
1364 }
1365 }
1366 out.println("- " + i18n.getString("ZoneInfo.map.notes.lengthInMeters", "Distances are always in meters.") + "<br>");
1367
1368 out.println("<hr>");
1369 if (mapSupportsCursorLocation || mapSupportsDistanceRuler) {
1370 if (mapSupportsCursorLocation) {
1371 out.println("<b>"+i18n.getString("ZoneInfo.map.cursorLoc","Cursor")+"</b>:");
1372 out.println("<span id='"+MapProvider.ID_LAT_LON_DISPLAY +"' style='margin-left:6px; margin-bottom:3px;'>0.0000,0.0000</span>");
1373 }
1374 if (mapSupportsDistanceRuler) {
1375 if (mapSupportsCursorLocation) { out.println("<br>"); }
1376 out.println("<b>"+i18n.getString("ZoneInfo.map.distanceRuler","Distance")+"</b>:");
1377 out.println("<span id='"+MapProvider.ID_DISTANCE_DISPLAY+"' style='margin-left:6px;'>0 "+GeoPoint.DistanceUnits.METERS.toString(locale)+"</span>");
1378 }
1379 out.println("<hr>");
1380 }
1381
1382 out.println("</div>");
1383
1384 out.write("<div width='100%'>\n");
1385 out.write("<span style='padding-left:10px'> </span>\n");
1386 if (_editZone) {
1387 out.write("<input type='submit' name='"+PARM_SUBMIT_CHG+"' value='"+i18n.getString("ZoneInfo.map.change","Change")+"'>\n");
1388 out.write("<span style='padding-left:10px'> </span>\n");
1389 out.write("<input type='button' name='"+PARM_BUTTON_CANCEL+"' value='"+i18n.getString("ZoneInfo.map.cancel","Cancel")+"' onclick=\"javascript:openURL('"+editURL+"','_self');\">\n"); // target='_top'
1390 } else {
1391 out.write("<input type='button' name='"+PARM_BUTTON_BACK+"' value='"+i18n.getString("ZoneInfo.map.back","Back")+"' onclick=\"javascript:openURL('"+editURL+"','_self');\">\n"); // target='_top'
1392 }
1393 out.write("</div>\n");
1394
1395 out.println("<div width='100%' height='100%'>");
1396 out.println(" ");
1397 out.println("</div>");
1398
1399 out.println("</td>");
1400
1401 /* map (controls on left) */
1402 if (mapControlsOnLeft) {
1403 String mapWidth = (mapDim.getWidth() <= 0)? "100%" : String.valueOf(mapDim.getWidth()) +"px";
1404 String mapHeight = (mapDim.getHeight() <= 0)? "100%" : String.valueOf(mapDim.getHeight())+"px";
1405 if (mapSupportsGeozones) {
1406 out.println("<!-- Begin Map -->");
1407 out.println("<td style='width:"+mapWidth+"; height:"+mapHeight+"; padding-left:5px;'>");
1408 mapProvider.writeMapCell(out, reqState, mapDim);
1409 out.println("</td>");
1410 out.println("<!-- End Map -->");
1411 } else {
1412 out.println("<td style='width:"+mapWidth+"; height:"+mapHeight+"; padding-left:5px; border: 1px solid black;'>");
1413 out.println("<!-- Geozones not yet supported for this MapProvider -->");
1414 out.println("<center>");
1415 out.println("<span style='font-size:12pt;'>");
1416 out.println(i18n.getString("ZoneInfo.map.notSupported","Geozone map not yet supported for this MapProvider"));
1417 out.println(" </span>");
1418 out.println("</center>");
1419 out.println("</td>");
1420 }
1421 }
1422
1423 /* end of form */
1424 out.println("</tr>");
1425 out.println("</table>"); // }
1426 out.println("</form>");
1427
1428 }
1429
1430 }
1431 };
1432
1433 /* map load? */
1434 String mapOnLoad = _listZones? "" : "javascript:_zoneMapOnLoad();";
1435 String mapOnUnload = _listZones? "" : "javascript:_zoneMapOnUnload();";
1436
1437 /* write frame */
1438 String onload = error? (mapOnLoad + JS_alert(false,m)) : mapOnLoad;
1439 CommonServlet.writePageFrame(
1440 reqState,
1441 onload,mapOnUnload, // onLoad/onUnload
1442 HTML_CSS, // Style sheets
1443 HTML_JS, // Javascript
1444 null, // Navigation
1445 HTML_CONTENT); // Content
1446
1447 }
1448
1449 // ------------------------------------------------------------------------
1450