MovieStatistics.java

package org.xandercat.pmdb.dto;

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.util.StringUtils;
import org.xandercat.pmdb.util.DoubleStatistics;
import org.xandercat.pmdb.util.LongStatistics;
import org.xandercat.pmdb.util.WordStatistics;
import org.xandercat.pmdb.util.format.FormatUtil;

/**
 * Class for providing generic statistics about a collection of movies.
 * 
 * @author Scott Arnold
 */
public class MovieStatistics {

	private Collection<Movie> movies;
	
	public MovieStatistics(Collection<Movie> movies) {
		this.movies = movies;
	}
	
	private Double getDoubleAttribute(Movie movie, String attributeKey) {
		String value = movie.getAttribute(attributeKey);
		if (StringUtils.hasText(value)) {
			try {
				return Double.valueOf(value);
			} catch (Exception e) {
			}
		}
		return null;
	}
	
	private Long getLongAttribute(Movie movie, String attributeKey) {
		String value = movie.getAttribute(attributeKey);
		if (StringUtils.hasText(value)) {
			try {
				return Long.valueOf(value);
			} catch (Exception e) {
			}
		}
		return null;
	}
	
	private Long getLenientLongAttribute(Movie movie, String attributeKey) {
		String value = movie.getAttribute(attributeKey);
		if (StringUtils.hasText(value)) {
			try {
				return Long.valueOf(FormatUtil.formatAsNumber(value));
			} catch (Exception e) {
			}
		}
		return null;		
	}
	
	/**
	 * Returns statistics for a movie attribute that should contain double values.
	 * Statistics will only be present if there is at least 1 value to calculate statistics on.
	 * 
	 * @param attributeKey  key for movie attribute to run statistics on
	 * 
	 * @return statistics for the attribute
	 */
	public Optional<DoubleStatistics> getDoubleStatistics(String attributeKey) {
		List<Double> doubles = movies.stream()
				.map(movie -> getDoubleAttribute(movie, attributeKey))
				.filter(value -> value != null)
				.collect(Collectors.toList());
		return (doubles.size() > 0)? Optional.of(new DoubleStatistics(doubles)) : Optional.empty();
	}
	
	/**
	 * Returns statistics for a movie attribute that should contain long values.
	 * Statistics will only be present if there is at least 1 value to calculate statistics on.
	 * 
	 * @param attributeKey  key for movie attribute to run statistics on
	 * 
	 * @return statistics for the attribute
	 */
	public Optional<LongStatistics> getLongStatistics(String attributeKey) {
		List<Long> longs = movies.stream()
				.map(movie -> getLongAttribute(movie, attributeKey))
				.filter(value -> value != null)
				.collect(Collectors.toList());
		return (longs.size() > 0)? Optional.of(new LongStatistics(longs)) : Optional.empty();
	}
	
	/**
	 * Returns statistics for a movie attribute that should contain long values with lenient parsing.
	 * Lenient parsing throws away extraneous commas, currency symbols, or other non-numeric clutter in 
	 * the attribute value.  Statistics will only be present if there is at least 1 value to calculate statistics on.
	 * 
	 * @param attributeKey  key for movie attribute to run statistics on
	 * 
	 * @return statistics for the attribute
	 */
	public Optional<LongStatistics> getLenientLongStatistics(String attributeKey) {
		List<Long> longs = movies.stream()
				.map(movie -> getLenientLongAttribute(movie, attributeKey))
				.filter(value -> value != null)
				.collect(Collectors.toList());
		return (longs.size() > 0)? Optional.of(new LongStatistics(longs)) : Optional.empty();
	}
	
	/**
	 * Returns word statistics for a movie attribute.
	 * 
	 * @param attributeKey  key for movie attribute to run statistics on
	 * 
	 * @return statistics for the attribute
	 */
	public Optional<WordStatistics> getWordStatistics(String attributeKey) {
		List<String> wordStrings = movies.stream()
				.map(movie -> movie.getAttribute(attributeKey))
				.filter(value -> value != null)
				.collect(Collectors.toList());
		if (wordStrings.size() == 0) {
			return Optional.empty();
		}
		final WordStatistics wordStatistics = new WordStatistics();
		wordStrings.forEach(wordStatistics::addWords);
		return Optional.of(wordStatistics);
	}
}