001package com.studentgui.tools; 002 003import java.nio.file.Path; 004import java.sql.Connection; 005import java.sql.DriverManager; 006import java.sql.PreparedStatement; 007import java.sql.ResultSet; 008import java.time.LocalDate; 009import java.time.format.DateTimeFormatter; 010import java.util.ArrayList; 011import java.util.List; 012 013import com.studentgui.apphelpers.Database; 014import com.studentgui.apphelpers.Helpers; 015import com.studentgui.apppages.JLineGraph; 016 017/** 018 * Command-line utility for offline student progress chart rendering and export. 019 * 020 * <p>This standalone tool generates PNG charts for a specific student and progress type 021 * without launching the full GUI application. Useful for:</p> 022 * <ul> 023 * <li>Batch chart generation for multiple students/progress types</li> 024 * <li>Debugging chart rendering issues outside the GUI context</li> 025 * <li>Automated report generation in CI/CD pipelines</li> 026 * <li>Creating historical chart snapshots for archival purposes</li> 027 * </ul> 028 * 029 * <p><b>Usage:</b></p> 030 * <pre>{@code 031 * java -cp StudentDataGUI.jar com.studentgui.tools.RenderStudentProgress "Aaron A Aaronsson" "Braille" 032 * }</pre> 033 * 034 * <p><b>Workflow:</b></p> 035 * <ol> 036 * <li>Ensures app folder hierarchy exists via {@link Helpers#createFolderHierarchy()}</li> 037 * <li>Queries database for canonical assessment part codes for the specified progress type</li> 038 * <li>Fetches up to 5 most recent assessment sessions via {@link Database#fetchLatestAssessmentResults}</li> 039 * <li>Renders grouped chart using {@link JLineGraph#updateWithGroupedData}</li> 040 * <li>Exports PNG to {@code StudentDataFiles/<student>/plots/<ProgressType>-render-<date>.png}</li> 041 * </ol> 042 * 043 * <p><b>Output:</b> PNG file written to student's plots directory with filename format: 044 * {@code <ProgressType>-render-<ISO_DATE>.png}</p> 045 * 046 * @see com.studentgui.apphelpers.Database#fetchLatestAssessmentResults 047 * @see com.studentgui.apppages.JLineGraph 048 * @see com.studentgui.apphelpers.Helpers#createFolderHierarchy() 049 */ 050public class RenderStudentProgress { 051 /** 052 * Render and write a progress chart for the provided student and progress type. 053 * 054 * @param args first arg: student display name, second arg: progress type name 055 * @throws Exception on I/O or database access errors 056 */ 057 public static void main(final String[] args) throws Exception { 058 if (args.length < 2) { 059 System.out.println("Usage: RenderStudentProgress <Student Name> <ProgressTypeName>"); 060 return; 061 } 062 String student = args[0]; 063 String pt = args[1]; 064 Helpers.createFolderHierarchy(); 065 System.out.println("Rendering " + pt + " for " + student); 066 067 // fetch canonical part codes for progress type 068 List<String> codes = new ArrayList<>(); 069 try (Connection c = DriverManager.getConnection("jdbc:sqlite:" + Helpers.DATABASE_PATH.toString())) { 070 try (PreparedStatement ps = c.prepareStatement("SELECT code FROM AssessmentPart ap JOIN ProgressType pt ON ap.progress_type_id = pt.id WHERE pt.name = ? ORDER BY ap.id ASC")) { 071 ps.setString(1, pt); 072 try (ResultSet rs = ps.executeQuery()) { 073 while (rs.next()) codes.add(rs.getString(1)); 074 } 075 } 076 } 077 if (codes.isEmpty()) { 078 System.out.println("No parts found for progress type: " + pt); 079 return; 080 } 081 String[] codeArr = codes.toArray(new String[0]); 082 List<List<Integer>> rows = Database.fetchLatestAssessmentResults(student, pt, 5); 083 if (rows == null || rows.isEmpty()) { 084 System.out.println("No session rows for student/progress: " + student + "/" + pt); 085 return; 086 } 087 JLineGraph g = new JLineGraph(); 088 g.updateWithGroupedData(rows, codeArr); 089 Path out = Helpers.APP_HOME.resolve("StudentDataFiles").resolve(Helpers.safeName(student)).resolve("plots"); 090 java.nio.file.Files.createDirectories(out); 091 DateTimeFormatter df = DateTimeFormatter.ISO_DATE; 092 Path file = out.resolve(pt + "-render-" + LocalDate.now().format(df) + ".png"); 093 g.saveChart(file, 1000, 800); 094 System.out.println("Wrote: " + file.toAbsolutePath()); 095 } 096 /** 097 * Explicit no-arg constructor with documentation to avoid default-constructor javadoc warnings. 098 */ 099 public RenderStudentProgress() { 100 // utility 101 } 102}