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.util.swing.JmriJOptionPane; 016 017/** 018 * Exports the train roster into a comma delimited file (CSV). Only trains that 019 * have the "Build" checkbox selected are exported. If a train is built, a 020 * summary of the train's route and work is provided. 021 * 022 * @author Daniel Boudreau Copyright (C) 2010, 2011, 2019 023 * 024 */ 025public class ExportTrains extends XmlFile { 026 027 public ExportTrains(){ 028 // nothing to do 029 } 030 031 public void writeOperationsTrainsFile() { 032 makeBackupFile(defaultOperationsFilename()); 033 try { 034 if (!checkFile(defaultOperationsFilename())) { 035 // The file does not exist, create it before writing 036 java.io.File file = new java.io.File(defaultOperationsFilename()); 037 java.io.File parentDir = file.getParentFile(); 038 if (!parentDir.exists()) { 039 if (!parentDir.mkdir()) { 040 log.error("Directory wasn't created"); 041 } 042 } 043 if (file.createNewFile()) { 044 log.debug("File created"); 045 } 046 } 047 writeFile(defaultOperationsFilename()); 048 } catch (IOException e) { 049 log.error("Exception while writing the new CSV operations file, may not be complete: {}", 050 e.getLocalizedMessage()); 051 } 052 } 053 054 public void writeFile(String name) { 055 log.debug("writeFile {}", name); 056 // This is taken in large part from "Java and XML" page 368 057 File file = findFile(name); 058 if (file == null) { 059 file = new File(name); 060 } 061 062 try (CSVPrinter fileOut = new CSVPrinter( 063 new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)), 064 CSVFormat.DEFAULT)) { 065 066 // create header 067 fileOut.printRecord(Bundle.getMessage("Name"), Bundle.getMessage("Description"), Bundle.getMessage("Time"), 068 Bundle.getMessage("Route"), Bundle.getMessage("Departs"), Bundle.getMessage("Terminates"), 069 Bundle.getMessage("Status"), Bundle.getMessage("Comment"), Bundle.getMessage("LocoTypes"), 070 Bundle.getMessage("CarTypes"), Bundle.getMessage("RoadOption"), Bundle.getMessage("RoadsCar"), 071 Bundle.getMessage("RoadOption"), Bundle.getMessage("RoadsCaboose"), Bundle.getMessage("RoadOption"), 072 Bundle.getMessage("RoadsLoco"), 073 Bundle.getMessage("LoadOption"), Bundle.getMessage("Loads"), Bundle.getMessage("OwnerOption"), 074 Bundle.getMessage("Owners"), Bundle.getMessage("Built"), 075 Bundle.getMessage("NormalModeWhenBuilding"), Bundle.getMessage("AllowCarsToReturn"), 076 Bundle.getMessage("AllowThroughCars"), Bundle.getMessage("SendCustomToStaging"), 077 Bundle.getMessage("SendToTerminal", ""), 078 Bundle.getMessage("AllowLocalMoves"), Bundle.getMessage("ServiceAllCars"), 079 Bundle.getMessage("BuildConsist")); 080 081 int count = 0; 082 083 for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByTimeList()) { 084 if (!train.isBuildEnabled()) { 085 continue; 086 } 087 count++; 088 String routeName = ""; 089 if (train.getRoute() != null) { 090 routeName = train.getRoute().getName(); 091 } 092 fileOut.printRecord(train.getName(), train.getDescription(), train.getDepartureTime(), routeName, 093 train.getTrainDepartsName(), train.getTrainTerminatesName(), train.getStatus(), 094 train.getComment(), TrainCommon.formatStringToCommaSeparated(train.getLocoTypeNames()), 095 TrainCommon.formatStringToCommaSeparated(train.getCarTypeNames()), getCarRoadOption(train), 096 getCarRoads(train), getCabooseRoadOption(train), getCabooseRoads(train), 097 getLocoRoadOption(train), getLocoRoads(train), getLoadOption(train), 098 getLoads(train), getOwnerOption(train), getOwners(train), getBuilt(train), 099 train.isBuildTrainNormalEnabled() ? Bundle.getMessage("ButtonYes") : "", 100 train.isAllowReturnToStagingEnabled() ? Bundle.getMessage("ButtonYes") : "", 101 train.isAllowThroughCarsEnabled() ? Bundle.getMessage("ButtonYes") : "", 102 train.isSendCarsWithCustomLoadsToStagingEnabled() ? Bundle.getMessage("ButtonYes") : "", 103 train.isSendCarsToTerminalEnabled() ? Bundle.getMessage("ButtonYes") : "", 104 train.isAllowLocalMovesEnabled() ? Bundle.getMessage("ButtonYes") : "", 105 train.isServiceAllCarsWithFinalDestinationsEnabled() ? Bundle.getMessage("ButtonYes") : "", 106 train.isBuildConsistEnabled() ? Bundle.getMessage("ButtonYes") : ""); 107 } 108 109 fileOut.println(); 110 // second create header for built trains 111 fileOut.printRecord(Bundle.getMessage("Name"), Bundle.getMessage("csvParameters"), 112 Bundle.getMessage("Attributes")); 113 114 for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByTimeList()) { 115 if (!train.isBuildEnabled()) { 116 continue; 117 } 118 119 if (train.isBuilt() && train.getRoute() != null) { 120 ArrayList<Object> line = new ArrayList<>(); 121 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("Route") })); 122 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(rl.getName())); 123 fileOut.printRecord(line); 124 125 line.clear(); 126 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvArrivalTime") })); 127 train.getRoute().getLocationsBySequenceList() 128 .forEach(rl -> line.add(train.getExpectedArrivalTime(rl))); 129 fileOut.printRecord(line); 130 131 line.clear(); 132 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvDepartureTime") })); 133 train.getRoute().getLocationsBySequenceList() 134 .forEach(rl -> line.add(train.getExpectedDepartureTime(rl))); 135 fileOut.printRecord(line); 136 137 line.clear(); 138 line.addAll( 139 Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvTrainDirection") })); 140 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(rl.getTrainDirectionString())); 141 fileOut.printRecord(line); 142 143 line.clear(); 144 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvTrainWeight") })); 145 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(train.getTrainWeight(rl))); 146 fileOut.printRecord(line); 147 148 line.clear(); 149 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvTrainLength") })); 150 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(train.getTrainLength(rl))); 151 fileOut.printRecord(line); 152 153 line.clear(); 154 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("Engine") })); 155 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(train.getLeadEngine(rl))); 156 fileOut.printRecord(line); 157 158 line.clear(); 159 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("Cars") })); 160 train.getRoute().getLocationsBySequenceList() 161 .forEach(rl -> line.add(train.getNumberCarsInTrain(rl))); 162 fileOut.printRecord(line); 163 164 line.clear(); 165 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvEmpties") })); 166 train.getRoute().getLocationsBySequenceList() 167 .forEach(rl -> line.add(train.getNumberEmptyCarsInTrain(rl))); 168 fileOut.printRecord(line); 169 170 line.clear(); 171 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("Loads") })); 172 train.getRoute().getLocationsBySequenceList() 173 .forEach(rl -> line.add(train.getNumberLoadedCarsInTrain(rl))); 174 fileOut.printRecord(line); 175 176 fileOut.println(); 177 } 178 } 179 180 fileOut.flush(); 181 fileOut.close(); 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}