package hirondelle.stocks.quotes;
import hirondelle.stocks.portfolio.CurrentPortfolio;
import hirondelle.stocks.preferences.QuoteTablePreferencesEditor;
import hirondelle.stocks.table.QuoteTable;
import hirondelle.stocks.util.Args;
import hirondelle.stocks.util.Consts;
import hirondelle.stocks.util.DataAccessException;
import hirondelle.stocks.util.Util;
import hirondelle.stocks.util.ui.UiConsts;
import hirondelle.stocks.util.ui.UiUtil;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.text.MessageFormat;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.KeyStroke;
import javax.swing.SwingWorker;
public final class FetchQuotesAction extends AbstractAction implements Observer {
public FetchQuotesAction (
CurrentPortfolio aCurrentPortfolio,
QuoteTablePreferencesEditor aQuoteTablePrefEditor,
QuoteTable aQuoteTable,
SummaryView aSummaryView
) {
super("Update", UiUtil.getImageIcon("/toolbarButtonGraphics/general/Refresh"));
Args.checkForNull(aQuoteTable);
Args.checkForNull(aSummaryView);
fCurrentPortfolio = aCurrentPortfolio;
fQuoteTablePrefEditor = aQuoteTablePrefEditor;
fQuoteTable = aQuoteTable;
fSummaryView = aSummaryView;
putValue(SHORT_DESCRIPTION, "Fetch updated stock quotes from web");
putValue(
ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F5, UiConsts.NO_KEYSTROKE_MASK)
);
putValue(
LONG_DESCRIPTION,
"Retrieves fresh stock quotes and displays it to the user in a table."
);
putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_U) );
fUpdateFreq = fQuoteTablePrefEditor.getUpdateFrequency();
}
public void startTimer(){
fQuoteTablePrefEditor.addObserver(this);
fCurrentPortfolio.addObserver(this);
fTimer = new javax.swing.Timer(fUpdateFreq * CONVERSION_FACTOR, this);
fTimer.start();
}
@Override public void actionPerformed(ActionEvent e) {
fLogger.info("Fetching quotes from web.");
fSummaryView.showStatusMessage("Fetching quotes...");
SwingWorker<List<Quote>, Void> hardWorker = new HardWorker();
hardWorker.execute();
}
@Override public void update(Observable aPublisher, Object aData) {
fLogger.fine("Notified ...");
if (aPublisher == fQuoteTablePrefEditor) {
fLogger.fine("By StocksTablePrefEditor.");
boolean hasChangedFreq = (fQuoteTablePrefEditor.getUpdateFrequency()!= fUpdateFreq);
if (hasChangedFreq) {
restartTimer();
}
}
else {
fLogger.fine("By Current Portfolio.");
actionPerformed(null);
}
}
private static final Logger fLogger = Util.getLogger(FetchQuotesAction.class);
private CurrentPortfolio fCurrentPortfolio;
private QuoteTablePreferencesEditor fQuoteTablePrefEditor;
private QuoteTable fQuoteTable;
private SummaryView fSummaryView;
private javax.swing.Timer fTimer;
private int fUpdateFreq;
private static final int CONVERSION_FACTOR =
Consts.MILLISECONDS_PER_SECOND * Consts.SECONDS_PER_MINUTE
;
private final class HardWorker extends SwingWorker<java.util.List<Quote>, Void> {
@Override protected List<Quote> doInBackground() throws Exception {
List<Quote> result = null;
try {
result = fCurrentPortfolio.getPortfolio().getQuotes();
}
catch(DataAccessException ex){
ex.printStackTrace();
}
return result;
}
@Override protected void done() {
try {
List<Quote> quotes = get();
if (quotes != null){
showUpdated(quotes);
}
else {
fSummaryView.showStatusMessage("Failed - Please connect to the web.");
}
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
private void showUpdated(List<Quote> aQuotes) {
fQuoteTable.setQuoteTable(aQuotes);
fSummaryView.setQuotes(aQuotes);
StringBuilder warning = new StringBuilder();
if (hasNoZeroPrices(aQuotes, warning)){
fSummaryView.showStatusMessage("Done.");
}
else {
fSummaryView.showStatusMessage(warning.toString());
}
}
private MessageFormat fTickerWarningFormat =
new MessageFormat("Warning - no price for ticker {0} ({1})")
;
private boolean hasNoZeroPrices(List<Quote> aQuotes, StringBuilder aMessage){
for(Quote quote: aQuotes){
if ( Util.isZeroMoney(quote.getPrice()) ) {
Object[] params = {
quote.getStock().getTicker(),
quote.getStock().getExchange()
};
aMessage.append(fTickerWarningFormat.format(params));
return false;
}
}
return true;
}
private void simulateLongDelay(){
try {
Thread.sleep(20000);
}
catch (InterruptedException ex) {
System.out.println(ex);
}
}
private void restartTimer(){
fLogger.fine("Resetting initial delay and delay to: " + fUpdateFreq + " minutes.");
fUpdateFreq = fQuoteTablePrefEditor.getUpdateFrequency();
fTimer.setInitialDelay(fUpdateFreq * CONVERSION_FACTOR);
fTimer.setDelay(fUpdateFreq * CONVERSION_FACTOR);
fLogger.fine("Cancelling pending tasks, and restarting timer...");
fTimer.restart();
}
}