package com.llamacorp.equate.unit;
import android.content.Context;
import android.os.AsyncTask;
import com.llamacorp.equate.R;
import com.llamacorp.equate.view.ViewUtils;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
/**
* Helper class is used to update dynamic unit types such as currency by
* calling all the necessary async tasks and such
* Created by Evan on 10/2/2015.
*/
public class UnitTypeUpdater {
public static int UPDATE_TIMEOUT_MIN = 90;
private Context mContext;
private ArrayList<Integer> mUnitsToUpdate;
public UnitTypeUpdater(Context mContext) {
this.mContext = mContext;
mUnitsToUpdate = new ArrayList<>();
}
public void update(UnitType ut, boolean forced) {
if (!ut.containsDynamicUnits()) return;
//only do update if timeout period has passed
if (isTimeoutReached(ut) || forced){
//add "Updating" text
ut.setUpdating(true);
new UpdateYahooXMLAsyncTask(ut, forced).execute();
} else {
ViewUtils.toast(mContext.getText(R.string.words_units_up_to_date)
.toString(), mContext);
}
}
private boolean isTimeoutReached(UnitType ut) {
Date now = new Date();
if (ut.getLastUpdateTime() != null && (now.getTime() -
ut.getLastUpdateTime().getTime())
< (60 * 1000 * UPDATE_TIMEOUT_MIN)){
return false;
} else
return true;
}
/**
* This class is used to create a background task that handles
* the actual retrieval of the Yahoo XML file that contains the current rates
*/
private class UpdateYahooXMLAsyncTask extends AsyncTask<Void, Void, Boolean> {
private UnitType mUnitType;
private Boolean mForced;
public UpdateYahooXMLAsyncTask(UnitType unitType, Boolean forced) {
mUnitType = unitType;
mForced = forced;
}
//This method is called first
@Override
protected Boolean doInBackground(Void... voids) {
return updateRatesWithXML(mUnitType);
}
// This method is called after doInBackground completes
@Override
protected void onPostExecute(Boolean successful) {
if (successful){
mUnitType.setLastUpdateTime(new Date());
String text = "Updated at ";
if (mForced) text = "FORCED update at ";
ViewUtils.toastLong(text + mUnitType.getLastUpdateTime().toString(),
mContext);
}
//update the remaining units that got missed by yahoo xml
if (mUnitsToUpdate != null){
for (int i = 0; i < mUnitsToUpdate.size(); i++) {
UnitCurrency u = (UnitCurrency) mUnitType.getUnitPosInUnitArray(mUnitsToUpdate.get(i));
if (u.isTimeoutReached(mContext))
u.asyncRefresh(mContext);
}
}
//remove text "Updating"
mUnitType.setUpdating(false);
}
}
private boolean updateRatesWithXML(UnitType ut) {
//only try to update currencies if we have XML currency URL to work with
if (ut.getXMLCurrencyURL() == null) return false;
HashMap<String, YahooXmlParser.Entry> currRates = null;
//grab the array of yahoo currency units
try {
currRates = getCurrRates(ut.getXMLCurrencyURL());
} catch (XmlPullParserException | IOException e) {
e.printStackTrace();
}
//leave if we have not updated rates
if (currRates == null) return false;
//update each existing curr with new rates
for (int i = 0; i < ut.size(); i++) {
//skip unit support that don't support updating (not hist)
if (!ut.getUnitPosInUnitArray(i).isDynamic()) continue;
UnitCurrency u = ((UnitCurrency) ut.getUnitPosInUnitArray(i));
YahooXmlParser.Entry entry = currRates.get(u.getAbbreviation());
if (entry != null){
u.setValue(entry.price);
u.setUpdateTime(entry.date);
} else {
//this is for BTC and other units that don't get updated by yahoo
mUnitsToUpdate.add(i);
}
}
return true;
}
/**
* Downloads XML file of current Yahoo finance currency rates
*
* @param urlString URL of XML string
* @return Array of currencies with updated values
* @throws XmlPullParserException
* @throws IOException
*/
private HashMap<String, YahooXmlParser.Entry> getCurrRates(String urlString)
throws XmlPullParserException, IOException {
InputStream stream = null;
YahooXmlParser yahooXmlParser = new YahooXmlParser();
HashMap<String, YahooXmlParser.Entry> currRates = null;
try {
stream = downloadUrl(urlString);
currRates = yahooXmlParser.parse(stream);
// Makes sure that the InputStream is closed after the app is
// finished using it.
} finally {
if (stream != null){
stream.close();
}
}
return currRates;
}
/**
* Given a string representation of a URL, sets up a connection and gets
* an input stream.
*/
private InputStream downloadUrl(String urlString) throws IOException {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
return conn.getInputStream();
}
}