001package edu.pdx.cs.joy.grader;
002
003import com.google.common.annotations.VisibleForTesting;
004import edu.pdx.cs.joy.ParserException;
005import edu.pdx.cs.joy.grader.gradebook.GradeBook;
006import edu.pdx.cs.joy.grader.gradebook.Student;
007import edu.pdx.cs.joy.grader.gradebook.XmlGradeBookParser;
008
009import java.io.File;
010import java.io.IOException;
011import java.util.ArrayList;
012import java.util.List;
013import java.util.function.Supplier;
014import java.util.stream.Stream;
015
016import static java.util.stream.Collectors.toCollection;
017
018public class GenerateStudentInitialsFile {
019
020  public static List<String> generateInitials(Stream<Student> students) {
021    return students
022      .map(StudentInitials::new)
023      .sorted()
024      .map(StudentInitials::getInitials)
025      .collect(toCollection(ArrayList::new));
026  }
027
028  @VisibleForTesting
029  static class StudentInitials implements Comparable<StudentInitials> {
030    private final Student student;
031    int uniqueCharsOfFirstname = 1;
032    int uniqueCharsOfLastname = 1;
033
034    public StudentInitials(Student student) {
035      this.student = student;
036    }
037
038    public String getInitials() {
039      return getFirstNameInitials() + getLastNameInitials();
040    }
041
042    private String getLastNameInitials() {
043      return getNameInitials(student::getLastName, uniqueCharsOfLastname);
044    }
045
046    private static String getNameInitials(Supplier<String> nameAccessor, int uniqueChars) {
047      return uppercaseFirstLetter(nameAccessor.get().substring(0, uniqueChars));
048    }
049
050    private static String uppercaseFirstLetter(String substring) {
051      if (substring.isEmpty()) {
052        return "";
053      }
054
055      StringBuilder sb = new StringBuilder();
056      sb.append(Character.toUpperCase(substring.charAt(0)));
057      if (substring.length() > 1) {
058        sb.append(substring.substring(1).toLowerCase());
059      }
060      return sb.toString();
061    }
062
063    private String getFirstNameInitials() {
064      return getNameInitials(student::getFirstName, uniqueCharsOfFirstname);
065    }
066
067    @Override
068    public int compareTo(StudentInitials other) {
069      int lastInitialsComparison = this.getLastNameInitials().compareToIgnoreCase(other.getLastNameInitials());
070      if (lastInitialsComparison != 0) {
071        return lastInitialsComparison;
072      }
073      int firstInitialsComparison = this.getFirstNameInitials().compareToIgnoreCase(other.getFirstNameInitials());
074      if (firstInitialsComparison != 0) {
075        return firstInitialsComparison;
076      }
077
078      if (this.uniqueCharsOfLastname > this.uniqueCharsOfFirstname) {
079        this.incrementUniqueCharsOfFirstName();
080        other.incrementUniqueCharsOfFirstName();
081
082      } else {
083        this.incrementUniqueCharsOfLastName();
084        other.incrementUniqueCharsOfLastName();
085      }
086      return this.compareTo(other);
087    }
088
089    @VisibleForTesting
090    void incrementUniqueCharsOfLastName() {
091      if (this.uniqueCharsOfLastname < student.getLastName().length()) {
092        this.uniqueCharsOfLastname++;
093      }
094    }
095
096    @VisibleForTesting
097    void incrementUniqueCharsOfFirstName() {
098      if (this.uniqueCharsOfFirstname < student.getFirstName().length()) {
099        this.uniqueCharsOfFirstname++;
100      }
101    }
102  }
103
104  public static void main(String[] args) {
105    if (args.length < 1) {
106      usage("Usage: GenerateStudentInitialsFile gradeBookFile");
107    }
108
109    String gradeBookFileName = args[0];
110    GradeBook book = loadGradeBookFromFile(gradeBookFileName);
111    List<String> initials = generateInitials(book.studentsStream());
112
113    System.out.println("""
114      Replace your initials in this file with the word "HERE" to demonstrate that you can push to this repository.
115      
116      """);
117    for (int i = 0; i < initials.size(); i++) {
118      String initial = initials.get(i);
119      System.out.format("%2d. %s%n", (i + 1), initial);
120    }
121  }
122
123  private static GradeBook loadGradeBookFromFile(String gradeBookFileName) {
124    File gradeBookFile = getExistingGradeBookFile(gradeBookFileName);
125    return parseGradeBookFile(gradeBookFile);
126  }
127
128  private static GradeBook parseGradeBookFile(File file) {
129    try {
130      return new XmlGradeBookParser(file).parse();
131
132    } catch (ParserException | IOException e) {
133      usage("While parsing " + file + ": " + e);
134      return null;
135    }
136  }
137
138  private static File getExistingGradeBookFile(String gradeBookFileName) {
139    File file = new File(gradeBookFileName);
140    if (!file.exists()) {
141      usage("Grade book file does not exist: " + gradeBookFileName);
142    }
143    return file;
144  }
145
146  private static void usage(String message) {
147    System.err.println(message);
148    System.exit(1);
149  }
150}