package hirondelle.movies.edit;
import hirondelle.movies.exception.InvalidInputException;
import hirondelle.movies.main.MainWindow;
import hirondelle.movies.util.Util;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.logging.Logger;
import java.util.regex.Pattern;
public final class MovieDAO {
public void shutdown() {
fLogger.fine("Saving all movie records to file.");
String fileContents = buildFileContents();
writeStringToFile(fileContents);
}
void add(Movie aMovie) {
String id = nextId();
aMovie.setId(id.toString());
fTable.put(id, aMovie);
}
void change(Movie aMovie) {
fTable.put(aMovie.getId(), aMovie);
}
List<Movie> list() {
List<Movie> result = new ArrayList<>(fTable.values());
Collections.sort(result);
return result;
}
void delete(String aMovieId) {
fTable.remove(aMovieId);
}
private static final Map<String, Movie> fTable = new LinkedHashMap<>();
private static int fNextId = 0;
private static final String MOVIES_FILE_NAME = "movie_list_for_";
private static final String DELIMITER = "|";
private static final String NULL = "NULL";
private static final Logger fLogger = Util.getLogger(MovieDAO.class);
private final static Charset ENCODING = StandardCharsets.UTF_8;
static {
readInMovieFileUponStartup();
fLogger.config("Number of movies read in from file: " + fTable.size());
}
private static void readInMovieFileUponStartup() {
Path moviesPath = Paths.get(getMovieFileName());
fLogger.fine("Reading movies from :" + moviesPath);
String line = "";
try (Scanner scanner = new Scanner(moviesPath, ENCODING.name())){
while (scanner.hasNextLine()) {
line = scanner.nextLine();
if (Util.textHasContent(line)) {
parseLine(line);
}
}
}
catch (FileNotFoundException ex) {
fLogger.config("Movies file not present. Will be created when the app closes.");
}
catch (InvalidInputException ex) {
fLogger.severe("Movies file: date-viewed field not in expected format: " + line);
}
catch (NoSuchElementException ex) {
fLogger.severe("Movies file: Not in expected format: " + line);
}
catch(IOException ex){
fLogger.severe("Unable to access the movies file.");
}
}
private static void parseLine(String aLine) throws InvalidInputException {
Scanner scanner = new Scanner(aLine);
scanner.useDelimiter(Pattern.quote(DELIMITER));
scanner.useLocale(Locale.US);
if (scanner.hasNext()) {
String title = scanner.next();
Date viewed = Util.parseDate(maybeNull(scanner.next()), "Date Viewed");
BigDecimal rating = Util.parseBigDecimal(maybeNull(scanner.next()), "Rating");
String comment = maybeNull(scanner.next());
Movie movie = new Movie(nextId().toString(), title, viewed, rating, comment);
fTable.put(movie.getId(), movie);
}
scanner.close();
}
private static String nextId() {
++fNextId;
return String.valueOf(fNextId);
}
private void appendTo(StringBuilder aText, Object aField, String aAppend) {
if (Util.textHasContent(Util.format(aField))) {
aText.append(Util.format(aField));
}
else {
aText.append(NULL);
}
aText.append(aAppend);
}
private static String maybeNull(String aText) {
return NULL.equals(aText) ? null : aText;
}
private static String getMovieFileName() {
return MOVIES_FILE_NAME + MainWindow.getInstance().getUserName().toLowerCase(Locale.ENGLISH) + ".txt";
}
private String buildFileContents() {
String NEW_LINE = System.getProperty("line.separator");
StringBuilder result = new StringBuilder();
for (Movie movie : fTable.values()) {
appendTo(result, movie.getTitle(), DELIMITER);
appendTo(result, movie.getDateViewed(), DELIMITER);
appendTo(result, movie.getRating(), DELIMITER);
appendTo(result, movie.getComment(), NEW_LINE);
}
return result.toString();
}
private void writeStringToFile(String aFileContents) {
Path moviesPath = Paths.get(getMovieFileName());
fLogger.fine("Writing movies to: " + moviesPath);
try (BufferedWriter writer = Files.newBufferedWriter(moviesPath, ENCODING)){
writer.write(aFileContents);
}
catch (FileNotFoundException ex) {
fLogger.severe("Cannot find movies text file.");
}
catch (IOException ex) {
fLogger.severe("Problem while saving movies text file.");
}
}
}