001/* 002 * To change this license header, choose License Headers in Project Properties. 003 * To change this template file, choose Tools | Templates 004 * and open the template in the editor. 005 */ 006package jmri.web.servlet.operations; 007 008import java.io.FileInputStream; 009import java.io.IOException; 010import java.util.*; 011 012import jmri.InstanceManager; 013import jmri.jmrit.operations.locations.Track; 014import jmri.jmrit.operations.rollingstock.RollingStock; 015import jmri.jmrit.operations.rollingstock.cars.Car; 016import jmri.jmrit.operations.rollingstock.engines.Engine; 017import jmri.jmrit.operations.routes.RouteLocation; 018import jmri.jmrit.operations.setup.Setup; 019import jmri.jmrit.operations.trains.Train; 020import jmri.jmrit.operations.trains.schedules.TrainScheduleManager; 021import jmri.jmrit.operations.trains.trainbuilder.TrainCommon; 022 023import org.apache.commons.text.StringEscapeUtils; 024import org.slf4j.Logger; 025import org.slf4j.LoggerFactory; 026 027/** 028 * 029 * @author Randall Wood 030 */ 031public class HtmlTrainCommon extends TrainCommon { 032 033 protected final Properties strings = new Properties(); 034 protected final Locale locale; 035 protected final Train train; 036 protected String resourcePrefix; 037 038 protected enum ShowLocation { 039 040 location, track, both; 041 } 042 043 private static final Logger log = LoggerFactory.getLogger(HtmlTrainCommon.class); 044 045 public HtmlTrainCommon(Locale locale, Train train) throws IOException { 046 this.locale = locale; 047 this.train = train; 048 FileInputStream is = null; 049 try { 050 is = new FileInputStream(Bundle.getMessage(locale, "ManifestStrings.properties")); 051 strings.load(is); 052 is.close(); 053 } 054 catch (IOException ex) { 055 if (is != null) { 056 is.close(); 057 } 058 throw ex; 059 } 060 } 061 062 public String pickupUtilityCars(List<Car> cars, Car car, boolean isManifest) { 063 // list utility cars by type, track, length, and load 064 String[] messageFormat; 065 if (isManifest) { 066 messageFormat = Setup.getPickupUtilityManifestMessageFormat(); 067 } else { 068 messageFormat = Setup.getPickupUtilitySwitchListMessageFormat(); 069 } 070 int count = countUtilityCars(messageFormat, cars, car, PICKUP); 071 if (count == 0) { 072 return ""; // already printed out this car type 073 } 074 return pickUpCar(car, count, messageFormat); 075 } 076 077 protected String setoutUtilityCars(List<Car> cars, Car car, boolean isManifest) { 078 boolean isLocal = car.isLocalMove(); 079 if (Setup.isSwitchListFormatSameAsManifest()) { 080 isManifest = true; 081 } 082 String[] messageFormat = Setup.getDropUtilityManifestMessageFormat(); 083 if (isLocal && isManifest) { 084 messageFormat = Setup.getLocalUtilityManifestMessageFormat(); 085 } else if (isLocal && !isManifest) { 086 messageFormat = Setup.getLocalUtilitySwitchListMessageFormat(); 087 } else if (!isLocal && !isManifest) { 088 messageFormat = Setup.getDropUtilitySwitchListMessageFormat(); 089 } 090 int count = countUtilityCars(messageFormat, cars, car, !PICKUP); 091 if (count == 0) { 092 return ""; // already printed out this car type 093 } 094 return dropCar(car, count, messageFormat, isLocal); 095 } 096 097 protected String pickUpCar(Car car, String[] format) { 098 return pickUpCar(car, 0, format); 099 } 100 101 protected String pickUpCar(Car car, int count, String[] format) { 102 StringBuilder builder = new StringBuilder(); 103 builder.append("<span style=\"color: " + Setup.getPickupTextColor() + ";\">"); 104 builder.append(Setup.getPickupCarPrefix()).append(" "); 105 // count the number of utility cars 106 if (count != 0) { 107 builder.append(count); 108 } 109 for (String attribute : format) { 110 builder.append( 111 String.format(locale, strings.getProperty("Attribute"), getCarAttribute(car, attribute, PICKUP, 112 !LOCAL), attribute.toLowerCase())).append(" "); // NOI18N 113 } 114 log.debug("Picking up car {}", builder); 115 return String.format(locale, strings.getProperty(this.resourcePrefix + "PickUpCar"), builder.toString()); // NOI18N 116 } 117 118 protected String dropCar(Car car, String[] format, boolean isLocal) { 119 return dropCar(car, 0, format, isLocal); 120 } 121 122 protected String dropCar(Car car, int count, String[] format, boolean isLocal) { 123 StringBuilder builder = new StringBuilder(); 124 if (!isLocal) { 125 builder.append("<span style=\"color: " + Setup.getDropTextColor() + ";\">"); 126 builder.append(Setup.getDropCarPrefix()).append(" "); 127 } else { 128 builder.append("<span style=\"color: " + Setup.getLocalTextColor() + ";\">"); 129 builder.append(Setup.getLocalPrefix()).append(" "); 130 } 131 // count the number of utility cars 132 if (count != 0) { 133 builder.append(count); 134 } 135 for (String attribute : format) { 136 builder.append( 137 String.format(locale, strings.getProperty("Attribute"), getCarAttribute(car, attribute, !PICKUP, 138 isLocal), attribute.toLowerCase())).append(" "); // NOI18N 139 } 140 log.debug("Dropping {}car {}", (isLocal) ? "local " : "", builder); 141 if (!isLocal) { 142 return String.format(locale, strings.getProperty(this.resourcePrefix + "DropCar"), builder.toString()); // NOI18N 143 } else { 144 return String.format(locale, strings.getProperty(this.resourcePrefix + "LocalCar"), builder.toString()); // NOI18N 145 } 146 } 147 148 protected String engineChange(RouteLocation rl, int legOptions) { 149 if ((legOptions & Train.HELPER_ENGINES) == Train.HELPER_ENGINES) { 150 return String.format(strings.getProperty("AddHelpersAt"), rl.getSplitName()); // NOI18N 151 } else if ((legOptions & Train.CHANGE_ENGINES) == Train.CHANGE_ENGINES 152 && ((legOptions & Train.REMOVE_CABOOSE) == Train.REMOVE_CABOOSE || (legOptions & Train.ADD_CABOOSE) == Train.ADD_CABOOSE)) { 153 return String.format(strings.getProperty("LocoAndCabooseChangeAt"), rl.getSplitName()); // NOI18N 154 } else if ((legOptions & Train.CHANGE_ENGINES) == Train.CHANGE_ENGINES) { 155 return String.format(strings.getProperty("LocoChangeAt"), rl.getSplitName()); // NOI18N 156 } else if ((legOptions & Train.REMOVE_CABOOSE) == Train.REMOVE_CABOOSE 157 || (legOptions & Train.ADD_CABOOSE) == Train.ADD_CABOOSE) { 158 return String.format(strings.getProperty("CabooseChangeAt"), rl.getSplitName()); // NOI18N 159 } 160 return ""; 161 } 162 163 protected String dropEngines(List<Engine> engines, RouteLocation location) { 164 StringBuilder builder = new StringBuilder(); 165 for (Engine engine : engines) { 166 if (engine.getRouteDestination().equals(location)) { 167 builder.append(dropEngine(engine)); 168 } 169 } 170 return String.format(strings.getProperty("EnginesList"), builder.toString()); 171 } 172 173 public String dropEngine(Engine engine) { 174 StringBuilder builder = new StringBuilder(); 175 builder.append("<span style=\"color: " + Setup.getDropEngineTextColor() + ";\">"); 176 builder.append(Setup.getDropEnginePrefix()).append(" "); 177 for (String attribute : Setup.getDropEngineMessageFormat()) { 178 builder.append( 179 String.format(locale, strings.getProperty("Attribute"), 180 getEngineAttribute(engine, attribute, false), attribute.toLowerCase())).append(" "); 181 } 182 log.debug("Drop engine: {}", builder); 183 return String.format(locale, strings.getProperty(this.resourcePrefix + "DropEngine"), builder.toString()); 184 } 185 186 protected String pickupEngines(List<Engine> engines, RouteLocation location) { 187 StringBuilder builder = new StringBuilder(); 188 for (Engine engine : engines) { 189 if (engine.getRouteLocation() == location && !engine.getTrackName().isEmpty()) { 190 builder.append(pickupEngine(engine)); 191 } 192 } 193 return String.format(locale, strings.getProperty("EnginesList"), builder.toString()); 194 } 195 196 public String pickupEngine(Engine engine) { 197 StringBuilder builder = new StringBuilder(); 198 builder.append("<span style=\"color: " + Setup.getPickupEngineTextColor() + ";\">"); 199 builder.append(Setup.getPickupEnginePrefix()).append(" "); 200 for (String attribute : Setup.getPickupEngineMessageFormat()) { 201 builder.append( 202 String.format(locale, strings.getProperty("Attribute"), 203 getEngineAttribute(engine, attribute, true), attribute.toLowerCase())).append(" "); 204 } 205 log.debug("Picking up engine: {}", builder); 206 return String.format(locale, strings.getProperty(this.resourcePrefix + "PickUpEngine"), builder.toString()); 207 } 208 209 protected String getCarAttribute(Car car, String attribute, boolean isPickup, boolean isLocal) { 210 if (attribute.equals(Setup.LOAD)) { 211 return (car.isCaboose() || car.isPassenger()) ? "" 212 : StringEscapeUtils.escapeHtml4(car.getLoadName().split(TrainCommon.HYPHEN)[0]); // NOI18N 213 } else if (attribute.equals(Setup.LOAD_TYPE)) { 214 return car.getLoadType(); 215 } else if (attribute.equals(Setup.HAZARDOUS)) { 216 return car.isHazardous() ? Setup.getHazardousMsg() : ""; // NOI18N 217 } else if (attribute.equals(Setup.DROP_COMMENT)) { 218 return car.getDropComment(); 219 } else if (attribute.equals(Setup.PICKUP_COMMENT)) { 220 return car.getPickupComment(); 221 } else if (attribute.equals(Setup.KERNEL)) { 222 return car.getKernelName(); 223 } else if (attribute.equals(Setup.KERNEL_SIZE)) { 224 if (car.getKernel() != null) { 225 return Integer.toString(car.getKernel().getSize()); 226 } else { 227 return ""; 228 } 229 } else if (attribute.equals(Setup.RWE)) { 230 if (!car.getReturnWhenEmptyDestinationName().isEmpty()) { 231 return String.format(locale, strings.getProperty("RWELocationAndTrack"), StringEscapeUtils 232 .escapeHtml4(car.getSplitReturnWhenEmptyDestinationName()), StringEscapeUtils 233 .escapeHtml4(car.getSplitReturnWhenEmptyDestinationTrackName())); 234 } 235 return ""; // NOI18N 236 } else if (attribute.equals(Setup.FINAL_DEST)) { 237 if (!car.getFinalDestinationName().isEmpty()) { 238 return String.format(locale, strings.getProperty("FinalDestinationLocation"), StringEscapeUtils 239 .escapeHtml4(car.getSplitFinalDestinationName())); 240 } 241 return ""; 242 } else if (attribute.equals(Setup.FINAL_DEST_TRACK)) { 243 if (!car.getFinalDestinationName().isEmpty()) { 244 return String.format(locale, strings.getProperty("FinalDestinationLocationAndTrack"), StringEscapeUtils 245 .escapeHtml4(car.getSplitFinalDestinationName()), StringEscapeUtils 246 .escapeHtml4(car.getSplitFinalDestinationTrackName())); 247 } 248 return ""; 249 } else if (attribute.equals(Setup.DIVISION)) { 250 return car.getDivisionName(); 251 } else if (attribute.equals(Setup.BLOCKING_ORDER)) { 252 if (car.isPassenger()) { 253 return Integer.toString(car.getBlocking()); 254 } 255 return ""; 256 } 257 return getRollingStockAttribute(car, attribute, isPickup, isLocal); 258 } 259 260 protected String getEngineAttribute(Engine engine, String attribute, boolean isPickup) { 261 if (attribute.equals(Setup.MODEL)) { 262 return engine.getModel(); 263 } 264 if (attribute.equals(Setup.HP)) { 265 return engine.getHp(); 266 } 267 if (attribute.equals(Setup.CONSIST)) { 268 return engine.getConsistName(); 269 } 270 if (attribute.equals(Setup.DCC_ADDRESS)) { 271 return engine.getDccAddress(); 272 } 273 return getRollingStockAttribute(engine, attribute, isPickup, false); 274 } 275 276 protected String getRollingStockAttribute(RollingStock rs, String attribute, boolean isPickup, boolean isLocal) { 277 if (attribute.equals(Setup.ORDER)) { 278 return rs.getOrder(); 279 } else if (attribute.equals(Setup.NUMBER)) { 280 return splitString(rs.getNumber()); 281 } else if (attribute.equals(Setup.ROAD)) { 282 return StringEscapeUtils.escapeHtml4(rs.getRoadName().split(TrainCommon.HYPHEN)[0]); 283 } else if (attribute.equals(Setup.TYPE)) { 284 return rs.getTypeName().split(TrainCommon.HYPHEN)[0]; 285 } else if (attribute.equals(Setup.LENGTH)) { 286 return rs.getLength(); 287 } else if (attribute.equals(Setup.WEIGHT)) { 288 return Integer.toString(rs.getAdjustedWeightTons()); 289 } else if (attribute.equals(Setup.COLOR)) { 290 return rs.getColor(); 291 } else if (attribute.equals(Setup.LOCATION) && (isPickup || isLocal) || 292 (attribute.equals(Setup.TRACK) && isPickup)) { 293 if (rs.getTrack() != null) { 294 return String.format(locale, strings.getProperty("FromTrack"), StringEscapeUtils.escapeHtml4(rs 295 .getSplitTrackName())); 296 } 297 return ""; 298 } else if (attribute.equals(Setup.LOCATION) && !isPickup && !isLocal) { 299 return ""; // we don't have the car's origin, so nothing to return 300 // Note that the JSON database does have the car's origin, so this could be fixed. 301 // return String.format(locale, strings.getProperty("FromLocation"), StringEscapeUtils.escapeHtml4(rs 302 // .getLocationName())); 303 } else if (attribute.equals(Setup.DESTINATION) && isPickup) { 304 return String.format(locale, strings.getProperty("ToLocation"), StringEscapeUtils 305 .escapeHtml4(rs.getSplitDestinationName())); 306 } else if ((attribute.equals(Setup.DESTINATION) || attribute.equals(Setup.TRACK)) && !isPickup) { 307 return String.format(locale, strings.getProperty("ToTrack"), StringEscapeUtils.escapeHtml4(rs 308 .getSplitDestinationTrackName())); 309 } else if (attribute.equals(Setup.DEST_TRACK)) { 310 return String.format(locale, strings.getProperty("ToLocationAndTrack"), StringEscapeUtils 311 .escapeHtml4(rs.getSplitDestinationName()), StringEscapeUtils.escapeHtml4(rs 312 .getSplitDestinationTrackName())); 313 } else if (attribute.equals(Setup.OWNER)) { 314 return StringEscapeUtils.escapeHtml4(rs.getOwnerName()); 315 } else if (attribute.equals(Setup.COMMENT)) { 316 return StringEscapeUtils.escapeHtml4(rs.getComment()); 317 } else if (attribute.equals(Setup.LAST_TRAIN)) { 318 return String.format(locale, strings.getProperty("LastTrain"), 319 StringEscapeUtils.escapeHtml4(rs.getLastTrainName())); 320 } else if (attribute.equals(Setup.LAST_MOVED)) { 321 return String.format(locale, strings.getProperty("LastMoved"), 322 StringEscapeUtils.escapeHtml4(rs.getLastDate())); 323 } else if (attribute.equals(Setup.LAST_LOCATION)) { 324 return String.format(locale, strings.getProperty("LastLocation"), 325 StringEscapeUtils.escapeHtml4(rs.getLastLocationName())); 326 } else if (attribute.equals(Setup.BLANK) || attribute.equals(Setup.NO_NUMBER) 327 || attribute.equals(Setup.NO_ROAD) || attribute.equals(Setup.NO_COLOR) 328 || attribute.equals(Setup.NO_DESTINATION) || attribute.equals(Setup.NO_DEST_TRACK) 329 || attribute.equals(Setup.NO_LOCATION) || attribute.equals(Setup.NO_TRACK) 330 || attribute.equals(Setup.TAB) || attribute.equals(Setup.TAB2) || attribute.equals(Setup.TAB3)) { 331 // attributes that don't print 332 return ""; 333 } 334 return String.format(Bundle.getMessage(locale, "ErrorPrintOptions"), attribute); // something is isn't right! 335 } 336 337 protected String getTrackComments(RouteLocation location, List<Car> cars) { 338 StringBuilder builder = new StringBuilder(); 339 if (location.getLocation() != null) { 340 List<Track> tracks = location.getLocation().getTracksByNameList(null); 341 for (Track track : tracks) { 342 // any pick ups or set outs to this track? 343 boolean pickup = false; 344 boolean setout = false; 345 for (Car car : cars) { 346 if (car.getRouteLocation() == location && car.getTrack() != null && car.getTrack() == track) { 347 pickup = true; 348 } 349 if (car.getRouteDestination() == location && car.getDestinationTrack() != null 350 && car.getDestinationTrack() == track) { 351 setout = true; 352 } 353 } 354 // print the appropriate comment if there's one 355 if (pickup && setout && !track.getCommentBoth().isEmpty()) { 356 builder.append(String.format(locale, strings.getProperty("TrackComments"), StringEscapeUtils 357 .escapeHtml4(track.getCommentBothWithColor()))); 358 } else if (pickup && !setout && !track.getCommentPickup().isEmpty()) { 359 builder.append(String.format(locale, strings.getProperty("TrackComments"), StringEscapeUtils 360 .escapeHtml4(track.getCommentPickupWithColor()))); 361 } else if (!pickup && setout && !track.getCommentSetout().isEmpty()) { 362 builder.append(String.format(locale, strings.getProperty("TrackComments"), StringEscapeUtils 363 .escapeHtml4(track.getCommentSetoutWithColor()))); 364 } 365 } 366 } 367 return builder.toString(); 368 } 369 370 public String getValidity() { 371 if (Setup.isPrintTrainScheduleNameEnabled()) { 372 return String.format(locale, strings.getProperty("ManifestValidityWithSchedule"), getDate(true), 373 InstanceManager.getDefault(TrainScheduleManager.class).getActiveSchedule().getName()); 374 } else { 375 return String.format(locale, strings.getProperty("ManifestValidity"), getDate(true)); 376 } 377 } 378 379 /** 380 * @param text Text with color tags needing conversion. See 381 * TrainCommon.formatColorString(String text, Color color) Also 382 * converts line feeds to HTLM 383 * @return HTML text with style color option 384 */ 385 public static String convertToHTMLColor(String text) { 386 // convert line feeds 387 text = text.replace("\n", "<br>"); 388 // color 389 text = text.replace("<FONT color="", "<p style=\"color: "); 390 text = text.replace("">", "\">"); 391 text = text.replace("</FONT>", ""); 392 // bold 393 text = text.replace("<b>", "<b>"); 394 text = text.replace("</b>", "</b>"); 395 // italic 396 text = text.replace("<i>", "<i>"); 397 text = text.replace("</i>", "</i>"); 398 return text; 399 } 400}