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 org.apache.commons.text.StringEscapeUtils; 013import org.slf4j.Logger; 014import org.slf4j.LoggerFactory; 015 016import jmri.InstanceManager; 017import jmri.jmrit.operations.locations.Track; 018import jmri.jmrit.operations.rollingstock.RollingStock; 019import jmri.jmrit.operations.rollingstock.cars.Car; 020import jmri.jmrit.operations.rollingstock.engines.Engine; 021import jmri.jmrit.operations.routes.RouteLocation; 022import jmri.jmrit.operations.setup.Setup; 023import jmri.jmrit.operations.trains.Train; 024import jmri.jmrit.operations.trains.TrainCommon; 025import jmri.jmrit.operations.trains.schedules.TrainScheduleManager; 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 static private 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 // count the number of utility cars 104 if (count != 0) { 105 builder.append(count); 106 } 107 for (String attribute : format) { 108 builder.append( 109 String.format(locale, strings.getProperty("Attribute"), getCarAttribute(car, attribute, PICKUP, 110 !LOCAL), attribute.toLowerCase())).append(" "); // NOI18N 111 } 112 log.debug("Picking up car {}", builder); 113 return String.format(locale, strings.getProperty(this.resourcePrefix + "PickUpCar"), builder.toString()); // NOI18N 114 } 115 116 protected String dropCar(Car car, String[] format, boolean isLocal) { 117 return dropCar(car, 0, format, isLocal); 118 } 119 120 protected String dropCar(Car car, int count, String[] format, boolean isLocal) { 121 StringBuilder builder = new StringBuilder(); 122 // count the number of utility cars 123 if (count != 0) { 124 builder.append(count); 125 } 126 for (String attribute : format) { 127 builder.append( 128 String.format(locale, strings.getProperty("Attribute"), getCarAttribute(car, attribute, !PICKUP, 129 isLocal), attribute.toLowerCase())).append(" "); // NOI18N 130 } 131 log.debug("Dropping {}car {}", (isLocal) ? "local " : "", builder); 132 if (!isLocal) { 133 return String.format(locale, strings.getProperty(this.resourcePrefix + "DropCar"), builder.toString()); // NOI18N 134 } else { 135 return String.format(locale, strings.getProperty(this.resourcePrefix + "LocalCar"), builder.toString()); // NOI18N 136 } 137 } 138 139 protected String engineChange(RouteLocation rl, int legOptions) { 140 if ((legOptions & Train.HELPER_ENGINES) == Train.HELPER_ENGINES) { 141 return String.format(strings.getProperty("AddHelpersAt"), rl.getSplitName()); // NOI18N 142 } else if ((legOptions & Train.CHANGE_ENGINES) == Train.CHANGE_ENGINES 143 && ((legOptions & Train.REMOVE_CABOOSE) == Train.REMOVE_CABOOSE || (legOptions & Train.ADD_CABOOSE) == Train.ADD_CABOOSE)) { 144 return String.format(strings.getProperty("LocoAndCabooseChangeAt"), rl.getSplitName()); // NOI18N 145 } else if ((legOptions & Train.CHANGE_ENGINES) == Train.CHANGE_ENGINES) { 146 return String.format(strings.getProperty("LocoChangeAt"), rl.getSplitName()); // NOI18N 147 } else if ((legOptions & Train.REMOVE_CABOOSE) == Train.REMOVE_CABOOSE 148 || (legOptions & Train.ADD_CABOOSE) == Train.ADD_CABOOSE) { 149 return String.format(strings.getProperty("CabooseChangeAt"), rl.getSplitName()); // NOI18N 150 } 151 return ""; 152 } 153 154 protected String dropEngines(List<Engine> engines, RouteLocation location) { 155 StringBuilder builder = new StringBuilder(); 156 for (Engine engine : engines) { 157 if (engine.getRouteDestination().equals(location)) { 158 builder.append(dropEngine(engine)); 159 } 160 } 161 return String.format(strings.getProperty("EnginesList"), builder.toString()); 162 } 163 164 @Override 165 public String dropEngine(Engine engine) { 166 StringBuilder builder = new StringBuilder(); 167 builder.append(Setup.getDropEnginePrefix()).append(" "); 168 for (String attribute : Setup.getDropEngineMessageFormat()) { 169 builder.append( 170 String.format(locale, strings.getProperty("Attribute"), 171 getEngineAttribute(engine, attribute, false), attribute.toLowerCase())).append(" "); 172 } 173 log.debug("Drop engine: {}", builder); 174 return String.format(locale, strings.getProperty(this.resourcePrefix + "DropEngine"), builder.toString()); 175 } 176 177 protected String pickupEngines(List<Engine> engines, RouteLocation location) { 178 StringBuilder builder = new StringBuilder(); 179 for (Engine engine : engines) { 180 if (engine.getRouteLocation().equals(location) && !engine.getTrackName().isEmpty()) { 181 builder.append(pickupEngine(engine)); 182 } 183 } 184 return String.format(locale, strings.getProperty("EnginesList"), builder.toString()); 185 } 186 187 @Override 188 public String pickupEngine(Engine engine) { 189 StringBuilder builder = new StringBuilder(); 190 builder.append(Setup.getPickupEnginePrefix()).append(" "); 191 for (String attribute : Setup.getPickupEngineMessageFormat()) { 192 builder.append( 193 String.format(locale, strings.getProperty("Attribute"), 194 getEngineAttribute(engine, attribute, true), attribute.toLowerCase())).append(" "); 195 } 196 log.debug("Picking up engine: {}", builder); 197 return String.format(locale, strings.getProperty(this.resourcePrefix + "PickUpEngine"), builder.toString()); 198 } 199 200 protected String getCarAttribute(Car car, String attribute, boolean isPickup, boolean isLocal) { 201 if (attribute.equals(Setup.LOAD)) { 202 return (car.isCaboose() || car.isPassenger()) ? "" : StringEscapeUtils.escapeHtml4(car.getLoadName()); // NOI18N 203 } else if (attribute.equals(Setup.HAZARDOUS)) { 204 return car.isHazardous() ? Setup.getHazardousMsg() : ""; // NOI18N 205 } else if (attribute.equals(Setup.DROP_COMMENT)) { 206 return car.getDropComment(); 207 } else if (attribute.equals(Setup.PICKUP_COMMENT)) { 208 return car.getPickupComment(); 209 } else if (attribute.equals(Setup.KERNEL)) { 210 return car.getKernelName(); 211 } else if (attribute.equals(Setup.RWE)) { 212 if (!car.getReturnWhenEmptyDestinationName().isEmpty()) { 213 return String.format(locale, strings.getProperty("RWELocationAndTrack"), StringEscapeUtils 214 .escapeHtml4(car.getSplitReturnWhenEmptyDestinationName()), StringEscapeUtils 215 .escapeHtml4(car.getSplitReturnWhenEmptyDestinationTrackName())); 216 } 217 return ""; // NOI18N 218 } else if (attribute.equals(Setup.FINAL_DEST)) { 219 if (!car.getFinalDestinationName().isEmpty()) { 220 return String.format(locale, strings.getProperty("FinalDestinationLocation"), StringEscapeUtils 221 .escapeHtml4(car.getSplitFinalDestinationName())); 222 } 223 return ""; 224 } else if (attribute.equals(Setup.FINAL_DEST_TRACK)) { 225 if (!car.getFinalDestinationName().isEmpty()) { 226 return String.format(locale, strings.getProperty("FinalDestinationLocationAndTrack"), StringEscapeUtils 227 .escapeHtml4(car.getSplitFinalDestinationName()), StringEscapeUtils 228 .escapeHtml4(car.getSplitFinalDestinationTrackName())); 229 } 230 return ""; 231 } 232 return getRollingStockAttribute(car, attribute, isPickup, isLocal); 233 } 234 235 protected String getEngineAttribute(Engine engine, String attribute, boolean isPickup) { 236 if (attribute.equals(Setup.MODEL)) { 237 return engine.getModel(); 238 } 239 if (attribute.equals(Setup.CONSIST)) { 240 return engine.getConsistName(); 241 } 242 if (attribute.equals(Setup.DCC_ADDRESS)) { 243 return engine.getDccAddress(); 244 } 245 return getRollingStockAttribute(engine, attribute, isPickup, false); 246 } 247 248 protected String getRollingStockAttribute(RollingStock rs, String attribute, boolean isPickup, boolean isLocal) { 249 if (attribute.equals(Setup.NUMBER)) { 250 return splitString(rs.getNumber()); 251 } else if (attribute.equals(Setup.ROAD)) { 252 return StringEscapeUtils.escapeHtml4(rs.getRoadName().split(TrainCommon.HYPHEN)[0]); 253 } else if (attribute.equals(Setup.TYPE)) { 254 return rs.getTypeName().split(TrainCommon.HYPHEN)[0]; 255 } else if (attribute.equals(Setup.LENGTH)) { 256 return rs.getLength(); 257 } else if (attribute.equals(Setup.COLOR)) { 258 return rs.getColor(); 259 } else if (attribute.equals(Setup.LOCATION) && (isPickup || isLocal) 260 || (attribute.equals(Setup.TRACK) && isPickup)) { 261 if (rs.getTrack() != null) { 262 return String.format(locale, strings.getProperty("FromTrack"), StringEscapeUtils.escapeHtml4(rs 263 .getSplitTrackName())); 264 } 265 return ""; 266 } else if (attribute.equals(Setup.LOCATION) && !isPickup && !isLocal) { 267 return ""; // we don't have the car's origin, so nothing to return 268 // Note that the JSON database does have the car's origin, so this could be fixed. 269// return String.format(locale, strings.getProperty("FromLocation"), StringEscapeUtils.escapeHtml4(rs 270// .getLocationName())); 271 } else if (attribute.equals(Setup.DESTINATION) && isPickup) { 272 return String.format(locale, strings.getProperty("ToLocation"), StringEscapeUtils 273 .escapeHtml4(rs.getSplitDestinationName())); 274 } else if ((attribute.equals(Setup.DESTINATION) || attribute.equals(Setup.TRACK)) && !isPickup) { 275 return String.format(locale, strings.getProperty("ToTrack"), StringEscapeUtils.escapeHtml4(rs 276 .getSplitDestinationTrackName())); 277 } else if (attribute.equals(Setup.DEST_TRACK)) { 278 return String.format(locale, strings.getProperty("ToLocationAndTrack"), StringEscapeUtils 279 .escapeHtml4(rs.getSplitDestinationName()), StringEscapeUtils.escapeHtml4(rs 280 .getSplitDestinationTrackName())); 281 } else if (attribute.equals(Setup.OWNER)) { 282 return StringEscapeUtils.escapeHtml4(rs.getOwnerName()); 283 } else if (attribute.equals(Setup.COMMENT)) { 284 return StringEscapeUtils.escapeHtml4(rs.getComment()); 285 } else if (attribute.equals(Setup.BLANK) || attribute.equals(Setup.NO_NUMBER) 286 || attribute.equals(Setup.NO_ROAD) || attribute.equals(Setup.NO_COLOR) 287 || attribute.equals(Setup.NO_DESTINATION) || attribute.equals(Setup.NO_DEST_TRACK) 288 || attribute.equals(Setup.NO_LOCATION) || attribute.equals(Setup.NO_TRACK) 289 || attribute.equals(Setup.TAB) || attribute.equals(Setup.TAB2) || attribute.equals(Setup.TAB3)) { 290 // attributes that don't print 291 return ""; 292 } 293 return String.format(Bundle.getMessage(locale, "ErrorPrintOptions"), attribute); // something is isn't right! 294 } 295 296 protected String getTrackComments(RouteLocation location, List<Car> cars) { 297 StringBuilder builder = new StringBuilder(); 298 if (location.getLocation() != null) { 299 List<Track> tracks = location.getLocation().getTracksByNameList(null); 300 for (Track track : tracks) { 301 // any pick ups or set outs to this track? 302 boolean pickup = false; 303 boolean setout = false; 304 for (Car car : cars) { 305 if (car.getRouteLocation() == location && car.getTrack() != null && car.getTrack() == track) { 306 pickup = true; 307 } 308 if (car.getRouteDestination() == location && car.getDestinationTrack() != null 309 && car.getDestinationTrack() == track) { 310 setout = true; 311 } 312 } 313 // print the appropriate comment if there's one 314 if (pickup && setout && !track.getCommentBoth().isEmpty()) { 315 builder.append(String.format(locale, strings.getProperty("TrackComments"), StringEscapeUtils 316 .escapeHtml4(track.getCommentBoth()))); 317 } else if (pickup && !setout && !track.getCommentPickup().isEmpty()) { 318 builder.append(String.format(locale, strings.getProperty("TrackComments"), StringEscapeUtils 319 .escapeHtml4(track.getCommentPickup()))); 320 } else if (!pickup && setout && !track.getCommentSetout().isEmpty()) { 321 builder.append(String.format(locale, strings.getProperty("TrackComments"), StringEscapeUtils 322 .escapeHtml4(track.getCommentSetout()))); 323 } 324 } 325 } 326 return builder.toString(); 327 } 328 329 public String getValidity() { 330 if (Setup.isPrintTrainScheduleNameEnabled()) { 331 return String.format(locale, strings.getProperty("ManifestValidityWithSchedule"), getDate(true), 332 InstanceManager.getDefault(TrainScheduleManager.class).getScheduleById(train.getId())); 333 } else { 334 return String.format(locale, strings.getProperty("ManifestValidity"), getDate(true)); 335 } 336 } 337 338}