001package jmri.jmrit.operations.trains.tools; 002 003import java.io.*; 004import java.nio.charset.StandardCharsets; 005import java.util.ArrayList; 006import java.util.Arrays; 007 008import org.apache.commons.csv.CSVFormat; 009import org.apache.commons.csv.CSVPrinter; 010 011import jmri.InstanceManager; 012import jmri.jmrit.XmlFile; 013import jmri.jmrit.operations.setup.OperationsSetupXml; 014import jmri.jmrit.operations.trains.Train; 015import jmri.jmrit.operations.trains.TrainManager; 016import jmri.jmrit.operations.trains.trainbuilder.TrainCommon; 017import jmri.util.swing.JmriJOptionPane; 018 019/** 020 * Exports the train roster into a comma delimited file (CSV). Only trains that 021 * have the "Build" checkbox selected are exported. If a train is built, a 022 * summary of the train's route and work is provided. 023 * 024 * @author Daniel Boudreau Copyright (C) 2010, 2011, 2019 025 * 026 */ 027public class ExportTrains extends XmlFile { 028 029 public ExportTrains(){ 030 // nothing to do 031 } 032 033 public void writeOperationsTrainsFile() { 034 makeBackupFile(defaultOperationsFilename()); 035 try { 036 if (!checkFile(defaultOperationsFilename())) { 037 // The file does not exist, create it before writing 038 java.io.File file = new java.io.File(defaultOperationsFilename()); 039 java.io.File parentDir = file.getParentFile(); 040 if (!parentDir.exists()) { 041 if (!parentDir.mkdir()) { 042 log.error("Directory wasn't created"); 043 } 044 } 045 if (file.createNewFile()) { 046 log.debug("File created"); 047 } 048 } 049 writeFile(defaultOperationsFilename()); 050 } catch (IOException e) { 051 log.error("Exception while writing the new CSV operations file, may not be complete: {}", 052 e.getLocalizedMessage()); 053 } 054 } 055 056 public void writeFile(String name) { 057 log.debug("writeFile {}", name); 058 // This is taken in large part from "Java and XML" page 368 059 File file = findFile(name); 060 if (file == null) { 061 file = new File(name); 062 } 063 064 try (CSVPrinter fileOut = new CSVPrinter( 065 new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)), 066 CSVFormat.DEFAULT)) { 067 068 // create header 069 fileOut.printRecord(Bundle.getMessage("Name"), Bundle.getMessage("Description"), Bundle.getMessage("Time"), 070 Bundle.getMessage("Route"), Bundle.getMessage("Departs"), Bundle.getMessage("Terminates"), 071 Bundle.getMessage("Status"), Bundle.getMessage("Comment"), Bundle.getMessage("LocoTypes"), 072 Bundle.getMessage("CarTypes"), Bundle.getMessage("RoadOption"), Bundle.getMessage("RoadsCar"), 073 Bundle.getMessage("RoadOption"), Bundle.getMessage("RoadsCaboose"), Bundle.getMessage("RoadOption"), 074 Bundle.getMessage("RoadsLoco"), 075 Bundle.getMessage("LoadOption"), Bundle.getMessage("Loads"), Bundle.getMessage("OwnerOption"), 076 Bundle.getMessage("Owners"), Bundle.getMessage("Built"), 077 Bundle.getMessage("NormalModeWhenBuilding"), Bundle.getMessage("AllowCarsToReturn"), 078 Bundle.getMessage("AllowThroughCars"), Bundle.getMessage("SendCustomToStaging"), 079 Bundle.getMessage("SendToTerminal", ""), 080 Bundle.getMessage("AllowLocalMoves"), Bundle.getMessage("ServiceAllCars"), 081 Bundle.getMessage("BuildConsist")); 082 083 int count = 0; 084 085 for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByTimeList()) { 086 if (!train.isBuildEnabled()) { 087 continue; 088 } 089 count++; 090 String routeName = ""; 091 if (train.getRoute() != null) { 092 routeName = train.getRoute().getName(); 093 } 094 fileOut.printRecord(train.getName(), train.getDescription(), train.getDepartureTime(), routeName, 095 train.getTrainDepartsName(), train.getTrainTerminatesName(), train.getStatus(), 096 train.getComment(), TrainCommon.formatStringToCommaSeparated(train.getLocoTypeNames()), 097 TrainCommon.formatStringToCommaSeparated(train.getCarTypeNames()), getCarRoadOption(train), 098 getCarRoads(train), getCabooseRoadOption(train), getCabooseRoads(train), 099 getLocoRoadOption(train), getLocoRoads(train), getLoadOption(train), 100 getLoads(train), getOwnerOption(train), getOwners(train), getBuilt(train), 101 train.isBuildTrainNormalEnabled() ? Bundle.getMessage("ButtonYes") : "", 102 train.isAllowReturnToStagingEnabled() ? Bundle.getMessage("ButtonYes") : "", 103 train.isAllowThroughCarsEnabled() ? Bundle.getMessage("ButtonYes") : "", 104 train.isSendCarsWithCustomLoadsToStagingEnabled() ? Bundle.getMessage("ButtonYes") : "", 105 train.isSendCarsToTerminalEnabled() ? Bundle.getMessage("ButtonYes") : "", 106 train.isAllowLocalMovesEnabled() ? Bundle.getMessage("ButtonYes") : "", 107 train.isServiceAllCarsWithFinalDestinationsEnabled() ? Bundle.getMessage("ButtonYes") : "", 108 train.isBuildConsistEnabled() ? Bundle.getMessage("ButtonYes") : ""); 109 } 110 111 fileOut.println(); 112 // second create header for built trains 113 fileOut.printRecord(Bundle.getMessage("Name"), Bundle.getMessage("csvParameters"), 114 Bundle.getMessage("Attributes")); 115 116 for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByTimeList()) { 117 if (!train.isBuildEnabled()) { 118 continue; 119 } 120 121 if (train.isBuilt() && train.getRoute() != null) { 122 ArrayList<Object> line = new ArrayList<>(); 123 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("Route") })); 124 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(rl.getName())); 125 fileOut.printRecord(line); 126 127 line.clear(); 128 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvArrivalTime") })); 129 train.getRoute().getLocationsBySequenceList() 130 .forEach(rl -> line.add(train.getExpectedArrivalTime(rl))); 131 fileOut.printRecord(line); 132 133 line.clear(); 134 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvDepartureTime") })); 135 train.getRoute().getLocationsBySequenceList() 136 .forEach(rl -> line.add(train.getExpectedDepartureTime(rl))); 137 fileOut.printRecord(line); 138 139 line.clear(); 140 line.addAll( 141 Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvTrainDirection") })); 142 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(rl.getTrainDirectionString())); 143 fileOut.printRecord(line); 144 145 line.clear(); 146 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvTrainWeight") })); 147 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(train.getTrainWeight(rl))); 148 fileOut.printRecord(line); 149 150 line.clear(); 151 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvTrainLength") })); 152 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(train.getTrainLength(rl))); 153 fileOut.printRecord(line); 154 155 line.clear(); 156 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("Engine") })); 157 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(train.getLeadEngine(rl))); 158 fileOut.printRecord(line); 159 160 line.clear(); 161 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("Cars") })); 162 train.getRoute().getLocationsBySequenceList() 163 .forEach(rl -> line.add(train.getNumberCarsInTrain(rl))); 164 fileOut.printRecord(line); 165 166 line.clear(); 167 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvEmpties") })); 168 train.getRoute().getLocationsBySequenceList() 169 .forEach(rl -> line.add(train.getNumberEmptyCarsInTrain(rl))); 170 fileOut.printRecord(line); 171 172 line.clear(); 173 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("Loads") })); 174 train.getRoute().getLocationsBySequenceList() 175 .forEach(rl -> line.add(train.getNumberLoadedCarsInTrain(rl))); 176 fileOut.printRecord(line); 177 178 fileOut.println(); 179 } 180 } 181 182 log.info("Exported {} trains to file {}", count, defaultOperationsFilename()); 183 JmriJOptionPane.showMessageDialog(null, 184 Bundle.getMessage("ExportedTrainsToFile", 185 count, defaultOperationsFilename()), 186 Bundle.getMessage("ExportComplete"), JmriJOptionPane.INFORMATION_MESSAGE); 187 } catch (IOException e) { 188 log.error("Can not open export trains CSV file: {}", e.getLocalizedMessage()); 189 JmriJOptionPane.showMessageDialog(null, 190 Bundle.getMessage("ExportedTrainsToFile", 191 0, defaultOperationsFilename()), 192 Bundle.getMessage("ExportFailed"), JmriJOptionPane.ERROR_MESSAGE); 193 } 194 } 195 196 private String getCarRoadOption(Train train) { 197 String roadOption = Bundle.getMessage("AcceptAll"); 198 if (train.getCarRoadOption().equals(Train.INCLUDE_ROADS)) { 199 roadOption = Bundle.getMessage( 200 "AcceptOnly") + " " + train.getCarRoadNames().length + " " + Bundle.getMessage("Roads"); 201 } else if (train.getCarRoadOption().equals(Train.EXCLUDE_ROADS)) { 202 roadOption = Bundle.getMessage( 203 "Exclude") + " " + train.getCarRoadNames().length + " " + Bundle.getMessage("Roads"); 204 } 205 return roadOption; 206 } 207 208 private String getCarRoads(Train train) { 209 if (train.getCarRoadOption().equals(Train.ALL_ROADS)) { 210 return ""; 211 } else { 212 return TrainCommon.formatStringToCommaSeparated(train.getCarRoadNames()); 213 } 214 } 215 216 private String getCabooseRoadOption(Train train) { 217 String roadOption = Bundle.getMessage("AcceptAll"); 218 if (train.getCabooseRoadOption().equals(Train.INCLUDE_ROADS)) { 219 roadOption = Bundle.getMessage( 220 "AcceptOnly") + " " + train.getCabooseRoadNames().length + " " + Bundle.getMessage("Roads"); 221 } else if (train.getCabooseRoadOption().equals(Train.EXCLUDE_ROADS)) { 222 roadOption = Bundle.getMessage( 223 "Exclude") + " " + train.getCabooseRoadNames().length + " " + Bundle.getMessage("Roads"); 224 } 225 return roadOption; 226 } 227 228 private String getCabooseRoads(Train train) { 229 if (train.getCabooseRoadOption().equals(Train.ALL_ROADS)) { 230 return ""; 231 } else { 232 return TrainCommon.formatStringToCommaSeparated(train.getCabooseRoadNames()); 233 } 234 } 235 236 private String getLocoRoadOption(Train train) { 237 String roadOption = Bundle.getMessage("AcceptAll"); 238 if (train.getLocoRoadOption().equals(Train.INCLUDE_ROADS)) { 239 roadOption = Bundle.getMessage( 240 "AcceptOnly") + " " + train.getLocoRoadNames().length + " " + Bundle.getMessage("Roads"); 241 } else if (train.getLocoRoadOption().equals(Train.EXCLUDE_ROADS)) { 242 roadOption = Bundle.getMessage( 243 "Exclude") + " " + train.getLocoRoadNames().length + " " + Bundle.getMessage("Roads"); 244 } 245 return roadOption; 246 } 247 248 private String getLocoRoads(Train train) { 249 if (train.getLocoRoadOption().equals(Train.ALL_ROADS)) { 250 return ""; 251 } else { 252 return TrainCommon.formatStringToCommaSeparated(train.getLocoRoadNames()); 253 } 254 } 255 256 private String getLoadOption(Train train) { 257 String loadOption = Bundle.getMessage("AcceptAll"); 258 if (train.getLoadOption().equals(Train.INCLUDE_LOADS)) { 259 loadOption = Bundle.getMessage( 260 "AcceptOnly") + " " + train.getLoadNames().length + " " + Bundle.getMessage("Loads"); 261 } else if (train.getLoadOption().equals(Train.EXCLUDE_LOADS)) { 262 loadOption = Bundle.getMessage( 263 "Exclude") + " " + train.getLoadNames().length + " " + Bundle.getMessage("Loads"); 264 } 265 return loadOption; 266 } 267 268 private String getLoads(Train train) { 269 if (train.getLoadOption().equals(Train.ALL_LOADS)) { 270 return ""; 271 } else { 272 return TrainCommon.formatStringToCommaSeparated(train.getLoadNames()); 273 } 274 } 275 276 private String getOwnerOption(Train train) { 277 String ownerOption = Bundle.getMessage("AcceptAll"); 278 if (train.getOwnerOption().equals(Train.INCLUDE_OWNERS)) { 279 ownerOption = Bundle.getMessage( 280 "AcceptOnly") + " " + train.getOwnerNames().length + " " + Bundle.getMessage("Owners"); 281 } else if (train.getOwnerOption().equals(Train.EXCLUDE_OWNERS)) { 282 ownerOption = Bundle.getMessage( 283 "Exclude") + " " + train.getOwnerNames().length + " " + Bundle.getMessage("Owners"); 284 } 285 return ownerOption; 286 } 287 288 private String getOwners(Train train) { 289 if (train.getOwnerOption().equals(Train.ALL_OWNERS)) { 290 return ""; 291 } else { 292 return TrainCommon.formatStringToCommaSeparated(train.getOwnerNames()); 293 } 294 } 295 296 private String getBuilt(Train train) { 297 if (!train.getBuiltStartYear().equals(Train.NONE) && train.getBuiltEndYear().equals(Train.NONE)) { 298 return Bundle.getMessage("After") + " " + train.getBuiltStartYear(); 299 } 300 if (train.getBuiltStartYear().equals(Train.NONE) && !train.getBuiltEndYear().equals(Train.NONE)) { 301 return Bundle.getMessage("Before") + " " + train.getBuiltEndYear(); 302 } 303 if (!train.getBuiltStartYear().equals(Train.NONE) && !train.getBuiltEndYear().equals(Train.NONE)) { 304 return Bundle.getMessage("Range") + " " + train.getBuiltStartYear() + ":" + train.getBuiltEndYear(); 305 } 306 return ""; 307 } 308 309 // Operation files always use the same directory 310 public static String defaultOperationsFilename() { 311 return OperationsSetupXml.getFileLocation() + 312 OperationsSetupXml.getOperationsDirectoryName() + 313 File.separator + 314 getOperationsFileName(); 315 } 316 317 public static void setOperationsFileName(String name) { 318 operationsFileName = name; 319 } 320 321 public static String getOperationsFileName() { 322 return operationsFileName; 323 } 324 325 private static String operationsFileName = "ExportOperationsTrainRoster.csv"; // NOI18N 326 327 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExportTrains.class); 328 329}