package unify;
import java.util.ArrayList;
import java.util.Collections;
import java.util.logging.Logger;
import unify.data.Episode;
import unify.data.Feed;
import unify.data.Season;
import unify.data.Settings;
import unify.data.Show;
import unify.fileio.Database;
import unify.fileio.RSSParser;
import unify.gui.GUI;
import unify.gui.SysTrayIcon;
public class ShowLibrary {
/*
* Change arraylists to lists and make private.
* Still instantiated as arraylists.
* Getters should be unmodifiable, setters shouldn't exist, instead do individual operations (add/remove/has).
*/
public ArrayList<Show> shows = new ArrayList<Show>();
public ArrayList<Show> newShows = new ArrayList<Show>();
public ArrayList<Show> onToday = new ArrayList<Show>();
public ArrayList<Show> onTomorrow = new ArrayList<Show>();
private ArrayList<Show> ignoredShows = new ArrayList<Show>();
private static ShowLibrary _instance = null;
private boolean pendingUpdates;
private ArrayList<String> pendingNotifications;
private Thread thread;
private final static Logger LOGGER = Logger.getLogger(ShowLibrary.class.getName());
private ShowLibrary() {
super();
this.pendingNotifications = new ArrayList<String>();
this.pendingUpdates = false;
}
public static synchronized ShowLibrary getInstance() {
if (_instance == null) {
_instance = new ShowLibrary();
}
return _instance;
}
public Show getShow(String myTitle) {
return getShow(this.shows, myTitle);
}
public Show getShow(ArrayList<Show> shows, String myTitle) {
for (int i = 0; i < shows.size(); i++) {
Show show = shows.get(i);
if (show.isThisMyTitle(myTitle)) {
return show;
}
}
return null;
}
public Show addShow(Show show) {
return addShow(show.getTitle(), show.getCurSeason(), show.getLastEpisode());
}
public Show addShow(String myTitle, int mySeason, int myEpisode) {
Show show = new Show(myTitle);
show.setCurSeason(mySeason);
show.setLastEpisode(myEpisode);
shows.add(show);
return show;
}
public void doDelay() {
LOGGER.info("Checking feeds.");
parseFeeds();
LOGGER.info("Done checking feeds. Checking again in " + Settings.getInstance().getDelay() + " minutes.");
try {
this.thread = Thread.currentThread();
Thread.sleep(Settings.getInstance().getDelay()*60000);
} catch (InterruptedException ie) {
LOGGER.fine("Sleeping thread was interrupted, probably intentional.");
}
}
public void parseFeeds() {
LOGGER.fine("Initiating feed parsing...");
if(Settings.getInstance().getFeeds().size()==0) {
LOGGER.warning("There are no rss feeds! Add a new feed in the settings.");
}
populateList(onToday, Settings.getInstance().getToday());
populateList(onTomorrow, Settings.getInstance().getTomorrow());
for(Feed myFeed : Settings.getInstance().getFeeds()) {
RSSParser parser = new RSSParser(myFeed);
ArrayList<Show> rssShows = parser.parseFeed();
checkShows(rssShows);
if(Settings.getInstance().isFindNewShows()) {
checkNewShows(rssShows);
}
LOGGER.fine("Done checking feed: " + myFeed.getLabel() + ". Feed had " + rssShows.size() + " episodes.");
}
if(this.pendingUpdates) {
doUpdates();
}
}
private void populateList(ArrayList<Show> showList, Feed feed) {
showList.clear();
RSSParser parser = new RSSParser(feed);
ArrayList<Show> rssShows = parser.parseFeed();
for(int i=0;i<rssShows.size();i++) {
Show show = rssShows.get(i);
if(getShow(show.getTitle())!=null) {
showList.add(show);
this.pendingUpdates = true;
}
}
}
private void checkShows(ArrayList<Show> rssShows) {
for(int i=0;i<rssShows.size();i++) {
Show rssShow = rssShows.get(i);
Show show = getShow(rssShow.getTitle());
if(show!=null) {
for(Season rssSeason : rssShow.seasons) {
int seasonInt = rssSeason.getNumber();
Season season = show.findSeason(seasonInt);
if(show.getCurSeason()<=seasonInt) {
if(show.getCurSeason()<seasonInt) {
season = show.addSeason(seasonInt);
show.setLastEpisode(0);
LOGGER.info("Found new season (" + seasonInt + ") of " + show.getTitle());
show.setCurSeason(seasonInt);
}
for(Episode rssEpisode : rssSeason.getEpisodes()) {
int episodeInt = rssEpisode.getNumber();
Episode episode = null;
if(season!=null) {
episode = season.findEpisode(episodeInt);
}
if(show.getLastEpisode()<episodeInt && episode==null) {
if(season==null) {
season = show.addSeason(seasonInt);
}
for(int m=show.getLastEpisode()+1;m<episodeInt;m++) {
LOGGER.info("Found new episode (" + m + ") of " + show.getTitle() + " in season " + seasonInt);
season.addEpisode(m, " ", " ");
pendingNotice(show.getTitle() + " (" + seasonInt + "x" + m + ") is now available.");
}
LOGGER.info("Found new episode (" + episodeInt + ") of " + show.getTitle() + " in season " + seasonInt);
season.addEpisode(episodeInt, rssEpisode.getLink(), rssEpisode.getLinkLabel());
pendingNotice(show.getTitle() + " (" + seasonInt + "x" + episodeInt + ") is now available.");
show.setLastEpisode(episodeInt);
}
if(episode!=null) {
int newPriority = Settings.getInstance().getFeedPriority(rssEpisode.getLinkLabel());
int oldPriority = Settings.getInstance().getFeedPriority(episode.getLinkLabel());
if (newPriority>oldPriority) {
LOGGER.info("Found higher priority link for " + show.getTitle() + " (" + seasonInt + "x" + episodeInt + "), updating from " + episode.getLinkLabel() + " to " + rssEpisode.getLinkLabel());
episode.setLink(rssEpisode.getLink());
episode.setLinkLabel(rssEpisode.getLinkLabel());
pendingNotice(show.getTitle() + " (" + seasonInt + "x" + episode.getNumber() + ") is now available on " + rssEpisode.getLinkLabel() + ".");
}
}
}
}
}
}
}
}
private void checkNewShows(ArrayList<Show> rssShows) {
for(int i=0;i<rssShows.size();i++) {
Show rssShow = rssShows.get(i);
if(getShow(this.shows, rssShow.getTitle())==null && getShow(this.newShows, rssShow.getTitle())==null && getShow(this.ignoredShows, rssShow.getTitle())==null) {
Season season = rssShow.getSeason();
Episode episode = season.getEpisode();
if(season.getNumber()==1 && episode.getNumber() == 1) {
Show show = new Show(rssShow.getTitle());
Season newSeason = show.addSeason(1);
newSeason.addEpisode(1, episode.getLink(), episode.getLinkLabel());
show.setCurSeason(1);
show.setLastEpisode(1);
this.newShows.add(show);
this.ignoredShows.add(show);
LOGGER.info("Found new show: " + show.getTitle());
pendingNotice("Found new show: " + show.getTitle());
}
}
}
}
public void doUpdates() {
LOGGER.info("Performing updates.");
Collections.sort(shows);
SysTrayIcon.getInstance().generatePopup();
if(!this.pendingNotifications.isEmpty()) {
SysTrayIcon.getInstance().showMessages(this.pendingNotifications);
this.pendingNotifications.clear();
LOGGER.fine("Sending notification messages to trayicon popup.");
}
GUI.getInstance().refresh();
Database.saveData();
this.pendingUpdates = false;
}
private void pendingNotice(String string) {
this.pendingUpdates = true;
this.pendingNotifications.add(string);
}
public void checkFeedsNow() {
this.thread.interrupt();
}
public void removeNewShow(Show show) {
this.newShows.remove(show);
LOGGER.fine("Removed " + show.getTitle() + " from new shows.");
}
}