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", e); 050 } 051 } 052 053 public void writeFile(String name) { 054 log.debug("writeFile {}", name); 055 // This is taken in large part from "Java and XML" page 368 056 File file = findFile(name); 057 if (file == null) { 058 file = new File(name); 059 } 060 061 try (CSVPrinter fileOut = new CSVPrinter( 062 new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)), 063 CSVFormat.DEFAULT)) { 064 065 // create header 066 fileOut.printRecord(Bundle.getMessage("Name"), Bundle.getMessage("Description"), Bundle.getMessage("Time"), 067 Bundle.getMessage("Route"), Bundle.getMessage("Departs"), Bundle.getMessage("Terminates"), 068 Bundle.getMessage("Status"), Bundle.getMessage("Comment"), Bundle.getMessage("LocoTypes"), 069 Bundle.getMessage("CarTypes"), Bundle.getMessage("RoadOption"), Bundle.getMessage("Roads"), 070 Bundle.getMessage("RoadOption"), Bundle.getMessage("Roads"), 071 Bundle.getMessage("LoadOption"), Bundle.getMessage("Loads"), Bundle.getMessage("OwnerOption"), 072 Bundle.getMessage("Owners"), Bundle.getMessage("Built"), 073 Bundle.getMessage("NormalModeWhenBuilding"), Bundle.getMessage("AllowCarsToReturn"), 074 Bundle.getMessage("AllowThroughCars"), Bundle.getMessage("SendCustomToStaging"), 075 Bundle.getMessage("SendToTerminal", ""), 076 Bundle.getMessage("AllowLocalMoves"), Bundle.getMessage("ServiceAllCars"), 077 Bundle.getMessage("BuildConsist")); 078 079 int count = 0; 080 081 for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByTimeList()) { 082 if (!train.isBuildEnabled()) { 083 continue; 084 } 085 count++; 086 String routeName = ""; 087 if (train.getRoute() != null) { 088 routeName = train.getRoute().getName(); 089 } 090 fileOut.printRecord(train.getName(), train.getDescription(), train.getDepartureTime(), routeName, 091 train.getTrainDepartsName(), train.getTrainTerminatesName(), train.getStatus(), 092 train.getComment(), TrainCommon.formatStringToCommaSeparated(train.getLocoTypeNames()), 093 TrainCommon.formatStringToCommaSeparated(train.getCarTypeNames()), getCarRoadOption(train), 094 getCarRoads(train), getLocoRoadOption(train), getLocoRoads(train), getLoadOption(train), 095 getLoads(train), getOwnerOption(train), getOwners(train), getBuilt(train), 096 train.isBuildTrainNormalEnabled() ? Bundle.getMessage("ButtonYes") : "", 097 train.isAllowReturnToStagingEnabled() ? Bundle.getMessage("ButtonYes") : "", 098 train.isAllowThroughCarsEnabled() ? Bundle.getMessage("ButtonYes") : "", 099 train.isSendCarsWithCustomLoadsToStagingEnabled() ? Bundle.getMessage("ButtonYes") : "", 100 train.isSendCarsToTerminalEnabled() ? Bundle.getMessage("ButtonYes") : "", 101 train.isAllowLocalMovesEnabled() ? Bundle.getMessage("ButtonYes") : "", 102 train.isServiceAllCarsWithFinalDestinationsEnabled() ? Bundle.getMessage("ButtonYes") : "", 103 train.isBuildConsistEnabled() ? Bundle.getMessage("ButtonYes") : ""); 104 } 105 106 fileOut.println(); 107 // second create header for built trains 108 fileOut.printRecord(Bundle.getMessage("Name"), Bundle.getMessage("csvParameters"), 109 Bundle.getMessage("Attributes")); 110 111 for (Train train : InstanceManager.getDefault(TrainManager.class).getTrainsByTimeList()) { 112 if (!train.isBuildEnabled()) { 113 continue; 114 } 115 116 if (train.isBuilt() && train.getRoute() != null) { 117 ArrayList<Object> line = new ArrayList<>(); 118 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("Route") })); 119 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(rl.getName())); 120 fileOut.printRecord(line); 121 122 line.clear(); 123 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvArrivalTime") })); 124 train.getRoute().getLocationsBySequenceList() 125 .forEach(rl -> line.add(train.getExpectedArrivalTime(rl))); 126 fileOut.printRecord(line); 127 128 line.clear(); 129 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvDepartureTime") })); 130 train.getRoute().getLocationsBySequenceList() 131 .forEach(rl -> line.add(train.getExpectedDepartureTime(rl))); 132 fileOut.printRecord(line); 133 134 line.clear(); 135 line.addAll( 136 Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvTrainDirection") })); 137 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(rl.getTrainDirectionString())); 138 fileOut.printRecord(line); 139 140 line.clear(); 141 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvTrainWeight") })); 142 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(train.getTrainWeight(rl))); 143 fileOut.printRecord(line); 144 145 line.clear(); 146 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvTrainLength") })); 147 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(train.getTrainLength(rl))); 148 fileOut.printRecord(line); 149 150 line.clear(); 151 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("Engine") })); 152 train.getRoute().getLocationsBySequenceList().forEach(rl -> line.add(train.getLeadEngine(rl))); 153 fileOut.printRecord(line); 154 155 line.clear(); 156 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("Cars") })); 157 train.getRoute().getLocationsBySequenceList() 158 .forEach(rl -> line.add(train.getNumberCarsInTrain(rl))); 159 fileOut.printRecord(line); 160 161 line.clear(); 162 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("csvEmpties") })); 163 train.getRoute().getLocationsBySequenceList() 164 .forEach(rl -> line.add(train.getNumberEmptyCarsInTrain(rl))); 165 fileOut.printRecord(line); 166 167 line.clear(); 168 line.addAll(Arrays.asList(new Object[] { train.getName(), Bundle.getMessage("Loads") })); 169 train.getRoute().getLocationsBySequenceList() 170 .forEach(rl -> line.add(train.getNumberLoadedCarsInTrain(rl))); 171 fileOut.printRecord(line); 172 173 fileOut.println(); 174 } 175 } 176 177 fileOut.flush(); 178 fileOut.close(); 179 log.info("Exported {} trains to file {}", count, defaultOperationsFilename()); 180 JmriJOptionPane.showMessageDialog(null, 181 Bundle.getMessage("ExportedTrainsToFile", 182 count, defaultOperationsFilename()), 183 Bundle.getMessage("ExportComplete"), JmriJOptionPane.INFORMATION_MESSAGE); 184 } catch (IOException e) { 185 log.error("Can not open export trains CSV file: {}", file.getName()); 186 JmriJOptionPane.showMessageDialog(null, 187 Bundle.getMessage("ExportedTrainsToFile", 188 0, defaultOperationsFilename()), 189 Bundle.getMessage("ExportFailed"), JmriJOptionPane.ERROR_MESSAGE); 190 } 191 } 192 193 private String getCarRoadOption(Train train) { 194 String roadOption = Bundle.getMessage("AcceptAll"); 195 if (train.getCarRoadOption().equals(Train.INCLUDE_ROADS)) { 196 roadOption = Bundle.getMessage( 197 "AcceptOnly") + " " + train.getCarRoadNames().length + " " + Bundle.getMessage("Roads"); 198 } else if (train.getCarRoadOption().equals(Train.EXCLUDE_ROADS)) { 199 roadOption = Bundle.getMessage( 200 "Exclude") + " " + train.getCarRoadNames().length + " " + Bundle.getMessage("Roads"); 201 } 202 return roadOption; 203 } 204 205 private String getCarRoads(Train train) { 206 if (train.getCarRoadOption().equals(Train.ALL_ROADS)) { 207 return ""; 208 } else { 209 return TrainCommon.formatStringToCommaSeparated(train.getCarRoadNames()); 210 } 211 } 212 213 private String getLocoRoadOption(Train train) { 214 String roadOption = Bundle.getMessage("AcceptAll"); 215 if (train.getLocoRoadOption().equals(Train.INCLUDE_ROADS)) { 216 roadOption = Bundle.getMessage( 217 "AcceptOnly") + " " + train.getLocoRoadNames().length + " " + Bundle.getMessage("Roads"); 218 } else if (train.getLocoRoadOption().equals(Train.EXCLUDE_ROADS)) { 219 roadOption = Bundle.getMessage( 220 "Exclude") + " " + train.getLocoRoadNames().length + " " + Bundle.getMessage("Roads"); 221 } 222 return roadOption; 223 } 224 225 private String getLocoRoads(Train train) { 226 if (train.getLocoRoadOption().equals(Train.ALL_ROADS)) { 227 return ""; 228 } else { 229 return TrainCommon.formatStringToCommaSeparated(train.getLocoRoadNames()); 230 } 231 } 232 233 private String getLoadOption(Train train) { 234 String loadOption = Bundle.getMessage("AcceptAll"); 235 if (train.getLoadOption().equals(Train.INCLUDE_LOADS)) { 236 loadOption = Bundle.getMessage( 237 "AcceptOnly") + " " + train.getLoadNames().length + " " + Bundle.getMessage("Loads"); 238 } else if (train.getLoadOption().equals(Train.EXCLUDE_LOADS)) { 239 loadOption = Bundle.getMessage( 240 "Exclude") + " " + train.getLoadNames().length + " " + Bundle.getMessage("Loads"); 241 } 242 return loadOption; 243 } 244 245 private String getLoads(Train train) { 246 if (train.getLoadOption().equals(Train.ALL_LOADS)) { 247 return ""; 248 } else { 249 return TrainCommon.formatStringToCommaSeparated(train.getLoadNames()); 250 } 251 } 252 253 private String getOwnerOption(Train train) { 254 String ownerOption = Bundle.getMessage("AcceptAll"); 255 if (train.getOwnerOption().equals(Train.INCLUDE_OWNERS)) { 256 ownerOption = Bundle.getMessage( 257 "AcceptOnly") + " " + train.getOwnerNames().length + " " + Bundle.getMessage("Owners"); 258 } else if (train.getOwnerOption().equals(Train.EXCLUDE_OWNERS)) { 259 ownerOption = Bundle.getMessage( 260 "Exclude") + " " + train.getOwnerNames().length + " " + Bundle.getMessage("Owners"); 261 } 262 return ownerOption; 263 } 264 265 private String getOwners(Train train) { 266 if (train.getOwnerOption().equals(Train.ALL_OWNERS)) { 267 return ""; 268 } else { 269 return TrainCommon.formatStringToCommaSeparated(train.getOwnerNames()); 270 } 271 } 272 273 private String getBuilt(Train train) { 274 if (!train.getBuiltStartYear().equals(Train.NONE) && train.getBuiltEndYear().equals(Train.NONE)) { 275 return Bundle.getMessage("After") + " " + train.getBuiltStartYear(); 276 } 277 if (train.getBuiltStartYear().equals(Train.NONE) && !train.getBuiltEndYear().equals(Train.NONE)) { 278 return Bundle.getMessage("Before") + " " + train.getBuiltEndYear(); 279 } 280 if (!train.getBuiltStartYear().equals(Train.NONE) && !train.getBuiltEndYear().equals(Train.NONE)) { 281 return Bundle.getMessage("Range") + " " + train.getBuiltStartYear() + ":" + train.getBuiltEndYear(); 282 } 283 return ""; 284 } 285 286 // Operation files always use the same directory 287 public static String defaultOperationsFilename() { 288 return OperationsSetupXml.getFileLocation() + 289 OperationsSetupXml.getOperationsDirectoryName() + 290 File.separator + 291 getOperationsFileName(); 292 } 293 294 public static void setOperationsFileName(String name) { 295 operationsFileName = name; 296 } 297 298 public static String getOperationsFileName() { 299 return operationsFileName; 300 } 301 302 private static String operationsFileName = "ExportOperationsTrainRoster.csv"; // NOI18N 303 304 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExportTrains.class); 305 306}