package main.java.model; import java.util.ArrayList; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.time.LocalDate; import main.java.Global; import main.java.view.MatrixonatorIOException; /** * MatrixIO -------- Provides static methods to deal with load and saving of matrices * * Author: Ewan McCartney */ public class MatrixIO { /** * Called from startup check to stop IO operations if no directory structure */ public static void setSaveFlag() { Global.DONT_SAVE = true; } /** * RESET METHOD FOR JUNIT TESTS. DO NOT USE IN APPLICATION */ public static void resetSaveFlag() { Global.DONT_SAVE = false; } /** * Performs the load operation on a matrix file * * @param matrixFile File object to load * @return the loaded matrix is sucsessful * @throws Exception */ private static Matrix load(File matrixFile) throws Exception { // Properties from file String name = ""; LocalDate date = null; int Rows = 0; int Cols = 0; double[][] matrixData = null; try { // Attempting to read in file given FileReader fr = new FileReader(matrixFile); BufferedReader br = new BufferedReader(fr); name = br.readLine(); date = LocalDate.parse(br.readLine()); String[] NumRowsCols = br.readLine().split(","); Rows = Integer.parseInt(NumRowsCols[0]); Cols = Integer.parseInt(NumRowsCols[1]); matrixData = new double[Rows][Cols]; for (int i = 0; i < Rows; ++i) { String row = br.readLine(); String[] Values = row.split(","); int Col = 0; for (String val : Values) { matrixData[i][Col] = Double.parseDouble(val); ++Col; } } br.close(); } catch (Exception e) { throw e; } return new Matrix(name, matrixData, date); } /** * Deletes stored matrix data if the file exists * * @param filename * @return True on success (or if no data was found). False if something went wrong */ public static boolean deleteFile(String filename) { File oldData = new File(getWorkingDir() + MATRIXDIR + Global.PATH_SEP + filename); if (oldData.exists()) { return oldData.delete(); } else { return true; } } /** * Check to see if the given Matrix has its data stored to file * * @param filename * @return True if exists */ public static boolean isMatrixSaved(String filename) { File toCheck = new File(getWorkingDir() + MATRIXDIR + Global.PATH_SEP + filename); return toCheck.exists(); } /** * Load Matrix from File * * @param filename of Matrix to load. To load RREF, use different call * @return Loaded Matrix * @throws FileNotFoundException, IOException, MatrixonatorIOException */ public static Matrix loadMatrix(String filename) throws Exception { if (Global.DONT_SAVE) { throw new MatrixonatorIOException( "Save is currently disabled due to Matrixonator not having working directories. Please contact system administor for directory create rights."); } // Checking incase the working directories haven't worked properly filename = getWorkingDir() + MATRIXDIR + Global.PATH_SEP + filename; File matrixFile = new File(filename); if (!matrixFile.exists()) { throw new FileNotFoundException(); } // Load Matrix and return it try { return load(matrixFile); } catch (Exception e) { throw e; } } /** * Save Matrix to file * * @param matrix * @return True on success, false otherwise */ /* * Saves Matrix as plain text (for now) * * File Format: - Matrix Name - Matrix Date - Matrix NumRows/Cols - Matrix Data (Row per line, * Cols split with ,) */ public static boolean save(Matrix matrix) { if (Global.DONT_SAVE) { return false; } // Checking for Save flag on startup // Size required for data String[] buffer = new String[(matrix.getNumRows() + 3)]; // Adds title information buffer[0] = matrix.getName(); buffer[1] = matrix.getCreatedDate().toString(); buffer[2] = matrix.getNumRows() + "," + matrix.getNumCols(); for (int i = 3; i < (matrix.getNumRows() + 3); ++i) { // For each row, we add a new line and put each value in a string // seperated by , StringBuilder line = new StringBuilder(); double[] row = matrix.getRow(i - 3); for (double val : row) { line.append(val); line.append(","); } buffer[i] = line.toString(); } // Actual IO Operation in try try { File matrixFile = new File(getWorkingDir() + MATRIXDIR + Global.PATH_SEP + buffer[0] + ".matrix"); if (!matrixFile.exists()) { matrixFile.createNewFile(); } FileWriter fw = new FileWriter(matrixFile.getAbsoluteFile()); BufferedWriter bw = new BufferedWriter(fw); for (String line : buffer) { bw.append(line + "\n"); } bw.close(); return true; } catch (IOException e) { e.printStackTrace(); return false; } } /** * Gets all the saved Matrices saved previously * * @return List of loaded Matrices */ public static ArrayList<Matrix> loadAll() { File searchDir = new File(getWorkingDir() + MATRIXDIR); String[] matrixNames = searchDir.list(); ArrayList<Matrix> loadedMatrices = new ArrayList<Matrix>(); if (matrixNames != null) { for (String name : matrixNames) { try { String filename = getWorkingDir() + MATRIXDIR + Global.PATH_SEP + name; File m = new File(filename); loadedMatrices.add(load(m)); } catch (Exception e) { System.out.println("Error loading a saved matrix into the application: " + name); } } } return loadedMatrices; } /* * IO Helper Methods */ private static String MATRIXDIR = null; private static String LOCALDIR = null; /** * @return The path to application working directory */ private static String getWorkingDir() { return System.getProperty("user.dir"); } /** * Performs IO startup checks and defines path separators for running OS If an error occurs, will * save a noSave flag where any IO operation is blocked. Application can still perform * calculations * * @throws MatrixonatorIOException */ public static void checkDirectories() throws MatrixonatorIOException { // Additional check to create proper path seperators per OS // WE MUST DO THIS FIRST. WONDER WHY THE HELL THIS EVEN WORKED ON LINUX BEFORE?! String tempLDir = "%Matrixonator"; String tempMDir = "%Matrixonator%Matrix"; String osName = System.getProperty("os.name"); // Update Path Sep if (osName.startsWith("Windows")) { Global.PATH_SEP = '\\'; } LOCALDIR = tempLDir.replace('%', Global.PATH_SEP); MATRIXDIR = tempMDir.replace('%', Global.PATH_SEP); // Checking for a working directory File BaseDirectory = new File(getWorkingDir() + LOCALDIR); if (!BaseDirectory.exists()) { try { if (!BaseDirectory.mkdir()) { throw new MatrixonatorIOException( "Unable to create working directories. Please contact system administrator for directory create rights.\n\nMatrixonator will still work, however you will be unable to save matrices or preferences"); } } catch (SecurityException e) { e.printStackTrace(); throw new MatrixonatorIOException( "Unable to create working directories due to secuirty issues. Please contact system administrator for directory create rights."); } } // Check for a directory to save matrix files to File MatrixDirectory = new File(getWorkingDir() + MATRIXDIR); if (!MatrixDirectory.exists()) { try { if (!MatrixDirectory.mkdir()) { throw new MatrixonatorIOException( "Unable to create working directories. Please contact system administrator for directory create rights.\n\nMatrixonator will still work, however you will be unable to save matrices or preferences"); } } catch (SecurityException e) { e.printStackTrace(); throw new MatrixonatorIOException( "Unable to create working directories due to secuirty issues. Please contact system administrator for directory create rights."); } } } }