001package edu.pdx.cs410J.grader;
002
003import com.google.common.io.Files;
004import edu.pdx.cs410J.ParserException;
005import edu.pdx.cs410J.grader.gradebook.GradeBook;
006import edu.pdx.cs410J.grader.gradebook.Student;
007import edu.pdx.cs410J.grader.gradebook.XmlGradeBookParser;
008import jakarta.mail.MessagingException;
009import jakarta.mail.Session;
010import jakarta.mail.Transport;
011import jakarta.mail.internet.InternetAddress;
012import jakarta.mail.internet.MimeMessage;
013import org.slf4j.Logger;
014import org.slf4j.LoggerFactory;
015
016import java.io.File;
017import java.io.IOException;
018import java.io.PrintStream;
019import java.nio.charset.Charset;
020import java.util.*;
021
022public class StudentFileMailer extends EmailSender {
023  private static Logger logger = LoggerFactory.getLogger(StudentFileMailer.class.getPackage().getName());
024
025  private final String subject;
026  private final Session session;
027
028  public StudentFileMailer(String subject, Session session) {
029    this.subject = subject;
030    this.session = session;
031  }
032
033  public static void main(String[] args) {
034    String gradeBookFileName = null;
035    String subject = null;
036    List<String> fileNames = new ArrayList<>();
037
038    for (String arg : args) {
039      if (gradeBookFileName == null) {
040        gradeBookFileName = arg;
041
042      } else if (subject == null) {
043        subject = arg;
044
045      } else {
046        fileNames.add(arg);
047      }
048    }
049
050    usageIfNull(gradeBookFileName, "Missing grade book file name");
051    usageIfNull(subject, "Missing email subject");
052    usageIfEmpty(fileNames, "Missing file names");
053    List<File> files = getFiles(fileNames);
054    GradeBook gradeBook = getGradeBook(gradeBookFileName);
055    Map<Student, File> filesToSendToStudents = getFilesToSendToStudents(files, gradeBook);
056
057    StudentFileMailer mailer = new StudentFileMailer(subject, newEmailSession(false));
058    filesToSendToStudents.forEach((student, file) -> {
059      try {
060        mailer.mailFileToStudent(file, student);
061
062      } catch (MessagingException | IOException ex) {
063        logger.error("While mailing \"" + file + "\" to " + student, ex);
064      }
065    });
066  }
067
068  private void mailFileToStudent(File file, Student student) throws MessagingException, IOException {
069    InternetAddress studentEmail = getEmailAddress(student);
070
071    logger.info("Mailing \"" + file + "\" to \"" + studentEmail + "\"");
072
073    MimeMessage message =
074      newEmailTo(this.session, studentEmail)
075        .from(TA_EMAIL)
076        .replyTo(DAVE_EMAIL)
077        .withSubject(this.subject)
078        .createMessage();
079    message.setText(readTextFromFile(file));
080
081    sendEmailMessage(message);
082  }
083
084  private String readTextFromFile(File file) throws IOException {
085    StringBuilder sb = new StringBuilder();
086    Files.copy(file, Charset.defaultCharset(), sb);
087    return sb.toString();
088  }
089
090  private void sendEmailMessage(MimeMessage message) throws MessagingException {
091    Transport.send(message);
092  }
093
094  private InternetAddress getEmailAddress(Student student) {
095    StringBuilder name = new StringBuilder();
096    name.append(student.getFirstName());
097    name.append(" ");
098    if (student.getNickName() != null) {
099      name.append("\"");
100      name.append(student.getNickName());
101      name.append("\" ");
102    }
103    name.append(student.getLastName());
104
105    return newInternetAddress(student.getEmail(), name.toString());
106  }
107
108  private static Map<Student, File> getFilesToSendToStudents(List<File> files, GradeBook gradeBook) {
109    Map<Student, File> filesToSendToStudents = new HashMap<>();
110    for (File file : files) {
111      String studentId = getStudentIdFromFileName(file);
112      Optional<Student> maybeStudent = gradeBook.getStudent(studentId);
113      if (maybeStudent.isEmpty()) {
114        cannotFindStudent(studentId);
115      } else {
116        filesToSendToStudents.put(maybeStudent.get(), file);
117      }
118    }
119
120    return filesToSendToStudents;
121  }
122
123  private static void cannotFindStudent(String studentId) {
124    logger.warn("Cannot find student with id \"" + studentId + "\" in grade book");
125  }
126
127  private static String getStudentIdFromFileName(File file) {
128    String studentId;
129    String fileName = file.getName();
130    int index = fileName.lastIndexOf('.');
131    if (index < 0) {
132      studentId = fileName;
133
134    } else {
135      studentId = fileName.substring(0, index);
136    }
137    return studentId;
138  }
139
140  private static List<File> getFiles(List<String> fileNames) {
141    List<File> files = new ArrayList<>(fileNames.size());
142    for (String fileName : fileNames) {
143      File file = new File(fileName);
144      if (!file.exists()) {
145        throw new IllegalStateException("File \"" + fileName + "\" does not exist");
146
147      } else if (!file.isFile()) {
148        throw new IllegalStateException("File \"" + fileName + "\" is not a file");
149      }
150
151      files.add(file);
152    }
153
154    return files;
155  }
156
157  private static GradeBook getGradeBook(String gradeBookFileName) {
158    try {
159      XmlGradeBookParser parser = new XmlGradeBookParser(gradeBookFileName);
160      return parser.parse();
161
162    } catch (IOException ex) {
163      return usage("Couldn't read grade book file \"" + gradeBookFileName + "\"");
164
165    } catch (ParserException ex) {
166      return usage("Couldn't parse grade book file \"" + gradeBookFileName + "\"");
167    }
168  }
169
170
171  private static void usageIfEmpty(List<String> list, String message) {
172    if (list.isEmpty()) {
173      usage(message);
174    }
175  }
176
177  private static void usageIfNull(String arg, String message) {
178    if (arg == null) {
179      usage(message);
180    }
181  }
182
183  private static <T> T usage(String message) {
184    PrintStream err = System.err;
185
186    err.println("** " + message);
187    err.println();
188    err.println("usage: java StudentFileMailer gradeBookFileName subject fileName+");
189    err.println();
190    err.println("Emails a file to a student in a grade book.  The name of the file must");
191    err.println("begin with the student's id.");
192    err.println();
193    err.println("  gradeBookFileName    Name of the grade book file");
194    err.println("  subject              The subject of the email");
195    err.println("  fileName             A file to send to the student");
196    err.println();
197
198    System.exit(1);
199
200    throw new UnsupportedOperationException("Should never get here");
201  }
202}