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