package util.settings; import gui.BotnakTrayIcon; import gui.forms.GUIMain; import irc.Donor; import irc.message.Message; import irc.message.MessageQueue; import lib.JSON.JSONArray; import lib.JSON.JSONObject; import util.Response; import util.Utils; import util.misc.Donation; import java.net.URL; import java.sql.Date; import java.text.NumberFormat; import java.time.Instant; import java.util.Currency; import java.util.HashSet; import java.util.concurrent.CopyOnWriteArraySet; /** * Created by Nick on 11/22/2014. */ public class DonationManager { public boolean ranFirstCheck; private Donation lastDonation; private CopyOnWriteArraySet<Donor> donors; private CopyOnWriteArraySet<Donation> donations; private static NumberFormat CURRENCY_FORMAT, DECIMAL_FORMAT; //for displaying the numbers public static NumberFormat getCurrencyFormat() { if (CURRENCY_FORMAT == null) { CURRENCY_FORMAT = NumberFormat.getCurrencyInstance(); CURRENCY_FORMAT.setMinimumFractionDigits(0); CURRENCY_FORMAT.setMaximumFractionDigits(2); } return CURRENCY_FORMAT; } //for saving the numbers public static NumberFormat getDecimalFormat() { if (DECIMAL_FORMAT == null) { DECIMAL_FORMAT = NumberFormat.getNumberInstance(); DECIMAL_FORMAT.setMinimumFractionDigits(2); DECIMAL_FORMAT.setMaximumFractionDigits(2); } return DECIMAL_FORMAT; } public DonationManager() { lastDonation = null; ranFirstCheck = false; CURRENCY_FORMAT = null; DECIMAL_FORMAT = null; donors = new CopyOnWriteArraySet<>(); donations = new CopyOnWriteArraySet<>(); } public boolean canCheck() { return !getClientID().isEmpty() && !getAccessCode().isEmpty(); } /** * Called from Settings#loadDonations() to give this class * the donations that you already know you have (saved locally). * <p> * You wouldn't want an alert for every donation you already know you have, right? * * @param d The HashSet of donations from loading through Settings. */ public void fillDonations(HashSet<Donation> d) { donations.addAll(d); } public void addDonation(JSONObject tip, boolean isLocal) { addDonation(new Donation(tip.getString("_id"), tip.getString("username"), tip.getString("note"), tip.getDouble("amount"), Date.from(Instant.parse(tip.getString("date")))), isLocal); } public void addDonation(Donation d, boolean isLocal) { if (!donationsContains(d.getDonationID()) || isLocal) { if (donations.add(d)) { Donor don = getDonor(d.getFromWho()); if (don == null) { don = new Donor(d.getFromWho(), d.getAmount()); addDonor(don); } else { don.addDonated(d.getAmount()); } if (!isLocal) { Settings.DONATIONS.save(); Settings.DONORS.save(); setLastDonation(d); if (BotnakTrayIcon.shouldDisplayDonations()) { GUIMain.getSystemTrayIcon().displayDonation(d); } MessageQueue.addMessage(new Message() .setChannel(Settings.accountManager.getUserAccount().getName()) .setType(Message.MessageType.DONATION_NOTIFY) .setContent(String.format("%s has just donated %s! Lifetime total: %s ", d.getFromWho(), getCurrencyFormat().format(d.getAmount()), getCurrencyFormat().format(don.getDonated()))) .setExtra(d)); } } } } public Response parseDonation(String[] lines) { Response toReturn = new Response(); if (lines.length > 2) { String name = lines[1]; try { Double amount = Double.parseDouble(lines[2]); if (amount > 0.0) { addDonation(new Donation("LOCAL", name, "Added manually.", amount, java.util.Date.from(Instant.now())), true); toReturn.setResponseText("Successfully added local donation for " + name + " !"); toReturn.wasSuccessful(); } else { toReturn.setResponseText("Failed to add donation, the amount must be greater than 0!"); } } catch (Exception ignored) { toReturn.setResponseText("Failed to add donation, the amount must have a decimal point!"); } } else { toReturn.setResponseText("Failed to add donation, usage: !adddonation (user) (amount)"); } return toReturn; } public void addDonor(Donor d) { donors.add(d); } public Donor getDonor(String name) { if (!donors.isEmpty()) { for (Donor d : donors) { if (d.getName().equalsIgnoreCase(name)) { return d; } } } return null; } public boolean donationsContains(String tipID) { for (Donation d : donations) { if (d.getDonationID().equals(tipID)) return true; } return false; } public String getClientID() { return Settings.donationClientID.getValue(); } public String getAccessCode() { return Settings.donationAuthCode.getValue(); } public CopyOnWriteArraySet<Donor> getDonors() { return donors; } public CopyOnWriteArraySet<Donation> getDonations() { return donations; } public Donation getLastDonation() { return lastDonation; } public void setLastDonation(Donation d) { lastDonation = d; } public void checkDonations(boolean single) { int limit = (single ? 5 : 100); String url = "https://streamtip.com/api/tips?client_id=" + getClientID() + "&access_token=" + getAccessCode() + "&limit=" + limit; try { String line = Utils.createAndParseBufferedReader(new URL(url).openStream()); if (!line.isEmpty()) { JSONObject outerShell = new JSONObject(line); int status = outerShell.getInt("status"); int count = outerShell.getInt("_count"); if (status == 200) { //ensure there's no problem with the site JSONArray tipsArray = outerShell.getJSONArray("tips"); for (int i = (single ? tipsArray.length() - 1 : count - 1); i > -1; i--) { JSONObject tip = tipsArray.getJSONObject(i); try { Currency c = Currency.getInstance(tip.getString("currencyCode")); getCurrencyFormat().setCurrency(c); } catch (Exception e) { GUIMain.log("Unknown currency code: " + tip.getString("currencyCode")); getCurrencyFormat().setCurrency(Currency.getInstance("USD")); } if (lastDonation != null) { if (lastDonation.getDonationID().equals(tip.getString("_id"))) { continue; } } addDonation(tip, false); } } } } catch (Exception e) { GUIMain.log(e); } } public void scanInitialDonations(int passesCompleted) { String url = "https://streamtip.com/api/tips?client_id=" + getClientID() + "&access_token=" + getAccessCode() + "&limit=100&direction=asc"; try { String offset = "&offset=" + String.valueOf(100 * passesCompleted); String line = Utils.createAndParseBufferedReader(new URL(url + offset).openStream()); if (!line.isEmpty()) { JSONObject outerShell = new JSONObject(line); int status = outerShell.getInt("status"); int count = outerShell.getInt("_count"); if (count > 0) { if (status == 200) { //ensure there's no problem with the site JSONArray tipsArray = outerShell.getJSONArray("tips"); for (int i = 0; i < tipsArray.length(); i++) { JSONObject tip = tipsArray.getJSONObject(i); if (lastDonation != null) { if (lastDonation.getDonationID().equals(tip.getString("_id"))) { continue; } } addDonation(tip, true); //we're simulating a local donation here to not spam the chat with all the donations } scanInitialDonations(passesCompleted + 1); } else { GUIMain.log("Failed to scan initial donations due to an error on Streamtip!"); } } else { //finished! GUIMain.log("Successfully scanned initial donations!"); } } } catch (Exception e) { GUIMain.log(e); } } }