001package com.studentgui.apppages;
002
003import java.awt.BorderLayout;
004import java.awt.Font;
005import java.awt.GridBagConstraints;
006import java.awt.GridBagLayout;
007import java.awt.Insets;
008import java.awt.event.ActionEvent;
009import java.awt.event.KeyEvent;
010import java.sql.SQLException;
011import java.time.LocalDate;
012
013import javax.swing.JButton;
014import javax.swing.JLabel;
015import javax.swing.JPanel;
016import javax.swing.JScrollPane;
017import javax.swing.JTextArea;
018import javax.swing.SwingUtilities;
019
020import org.slf4j.Logger;
021import org.slf4j.LoggerFactory;
022
023/**
024 * Freeform session notes editor for general observations and reflections.
025 *
026 * <p>Provides a simple multi-line text area for educators to record unstructured notes
027 * about a student session. This complements the structured assessment pages (Braille, Abacus, etc.)
028 * by allowing qualitative observations, anecdotal records, and contextual details that don't
029 * fit into numeric scoring fields.</p>
030 *
031 * <p><b>Typical Use Cases:</b></p>
032 * <ul>
033 *   <li>Recording behavioral observations (e.g., "Student showed increased frustration with Nemeth fractions today")</li>
034 *   <li>Documenting environmental factors affecting performance (e.g., "Noisy classroom due to construction")</li>
035 *   <li>Noting equipment issues or accommodations used (e.g., "Switched to Braille Sense due to BrailleNote malfunction")</li>
036 *   <li>General reflections or instructional notes for future reference</li>
037 * </ul>
038 *
039 * <p><b>Data Storage:</b></p>
040 * <ul>
041 *   <li>Notes persisted via {@link com.studentgui.apphelpers.Database#saveSessionNotes} to {@code ProgressSession.notes} column</li>
042 *   <li>Associated with a SessionNotes progress type and session ID for consistent querying</li>
043 *   <li>JSON export: {@code StudentDataFiles/<student>/Sessions/SessionNotes/SessionNotes-<sessionId>-<timestamp>.json}</li>
044 *   <li>No plots or reports generated (text-only data)</li>
045 * </ul>
046 *
047 * <p>The shared {@link JLineGraph} component is present for UI layout consistency but remains
048 * empty (session notes are not quantitative data). This page does not implement listener interfaces
049 * as it operates on static student/date parameters provided at construction time.</p>
050 *
051 * @see com.studentgui.apphelpers.Database#saveSessionNotes
052 * @see com.studentgui.apphelpers.dto.NotesPayload
053 */
054public class SessionNotes extends JPanel {
055    private static final Logger LOG = LoggerFactory.getLogger(SessionNotes.class);
056    /** Text area containing session notes entered by the user. */
057    private final JTextArea notesArea;
058
059    /** Selected student's display name used when saving session notes (may be null). */
060    private final String studentNameParam;
061
062    /** Date associated with these session notes. */
063    private final LocalDate dateParam;
064
065    /**
066     * Create a SessionNotes page for the provided student and date.
067     * The supplied JLineGraph is displayed below the notes editor.
068     *
069     * @param studentName student display name (may be null when no student selected)
070     * @param date        the date this session pertains to
071     * @param graph       the chart component shown beneath the notes
072     */
073    public SessionNotes(String studentName, LocalDate date, JLineGraph graph) {
074    this.studentNameParam = (studentName == null || studentName.trim().isEmpty()) ? com.studentgui.apphelpers.Helpers.defaultStudent() : studentName;
075        this.dateParam = date;
076        setLayout(new BorderLayout());
077
078    JPanel p = new JPanel(new GridBagLayout());
079    JPanel view = new JPanel(new BorderLayout());
080    view.add(p, BorderLayout.NORTH);
081    view.setBorder(javax.swing.BorderFactory.createEmptyBorder(20,20,20,20));
082    JScrollPane scroll = new JScrollPane(view);
083    scroll.getAccessibleContext().setAccessibleName("Session Notes data entry scroll pane");
084        GridBagConstraints gbc = new GridBagConstraints(); gbc.insets=new Insets(2,2,2,2); gbc.fill = GridBagConstraints.BOTH; gbc.anchor = GridBagConstraints.NORTHWEST;
085    JLabel title = new JLabel("Session Notes", JLabel.LEFT);
086    title.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 28));
087    title.getAccessibleContext().setAccessibleName("Session Notes Title");
088    gbc.gridx=0; gbc.gridy=0; gbc.gridwidth=1; p.add(title, gbc);
089
090    int globalLabel = com.studentgui.uicomp.PhaseScoreField.getGlobalLabelWidth();
091    gbc.gridy=1; gbc.gridx=0; JLabel notesLabel = new JLabel("Notes:"); notesLabel.setPreferredSize(new java.awt.Dimension(globalLabel, notesLabel.getPreferredSize().height)); p.add(notesLabel, gbc);
092    gbc.gridy=2; gbc.gridx=0; notesArea = new JTextArea(8,40); notesArea.setLineWrap(true); notesArea.setWrapStyleWord(true); notesArea.setToolTipText("Enter session notes for the student"); notesArea.getAccessibleContext().setAccessibleName("Session notes"); p.add(notesArea, gbc);
093    notesLabel.setLabelFor(notesArea);
094
095    gbc.gridy=3; JButton submit = new JButton("Save Session Notes");
096    submit.addActionListener((ActionEvent e)-> saveNotes());
097    submit.setMnemonic(KeyEvent.VK_S);
098    submit.setToolTipText("Save session notes (Alt+S)");
099    submit.getAccessibleContext().setAccessibleName("Save Session Notes");
100    p.add(submit, gbc);
101
102        add(scroll, BorderLayout.CENTER);
103
104        SwingUtilities.invokeLater(()->{ p.setPreferredSize(p.getPreferredSize()); revalidate(); });
105
106        com.studentgui.apphelpers.Helpers.createFolderHierarchy();
107    }
108
109    /**
110     * Persist the contents of the session notes into the database. Ensures
111     * required student and progress session records exist and writes the notes
112     * to the ProgressSession.notes column.
113     */
114    private void saveNotes() {
115        if (this.studentNameParam == null || this.studentNameParam.trim().isEmpty()) {
116            javax.swing.JOptionPane.showMessageDialog(this, "Please select a student before saving session notes.", "Missing student", javax.swing.JOptionPane.WARNING_MESSAGE);
117            return;
118        }
119
120        try {
121            int studentId = com.studentgui.apphelpers.Database.getOrCreateStudent(this.studentNameParam);
122            int ptId = com.studentgui.apphelpers.Database.getOrCreateProgressType("SessionNotes");
123            int sessionId = com.studentgui.apphelpers.Database.createProgressSession(studentId, ptId, this.dateParam);
124            String notes = notesArea.getText();
125            com.studentgui.apphelpers.Database.saveSessionNotes(sessionId, notes);
126            LOG.info("Saved session notes for {}", studentNameParam);
127            com.studentgui.apphelpers.UiNotifier.show("Session notes saved.");
128            com.studentgui.apphelpers.dto.NotesPayload payload = new com.studentgui.apphelpers.dto.NotesPayload(sessionId, notes);
129            java.nio.file.Path jsonOut = com.studentgui.apphelpers.SessionJsonWriter.writeSessionJson(this.studentNameParam, "SessionNotes", payload, sessionId);
130            if (jsonOut == null) {
131                LOG.warn("Unable to save SessionNotes session JSON for sessionId={}", sessionId);
132            }
133        } catch (SQLException ex) {
134            LOG.error("Error saving session notes", ex);
135            javax.swing.JOptionPane.showMessageDialog(this, "Database error saving session notes: " + ex.getMessage(), "Database error", javax.swing.JOptionPane.ERROR_MESSAGE);
136        }
137    }
138}