package regalowl.hyperconomy; import java.util.ArrayList; import java.util.HashMap; import regalowl.databukkit.CommonFunctions; import regalowl.databukkit.QueryResult; import regalowl.databukkit.SQLRead; import regalowl.databukkit.SQLWrite; /** * * * This class stores item price history in history.yml (Value/Purchase price.) * */ public class History { private HyperConomy hc; private EconomyManager em; private InfoSignHandler isign; private SQLWrite sw; private SQLRead sr; private int historylogtaskid; private int daysToSaveHistory; private long lastTime; private long timeCounter; private boolean useHistory; private final int millisecondsInHour = 3600000; History() { hc = HyperConomy.hc; useHistory = hc.gYH().gFC("config").getBoolean("config.store-price-history"); if (!useHistory) {return;} em = hc.getEconomyManager(); isign = hc.getInfoSignHandler(); sw = hc.getSQLWrite(); sr = hc.getSQLRead(); daysToSaveHistory = hc.gYH().gFC("config").getInt("config.daystosavehistory"); lastTime = System.currentTimeMillis(); timeCounter = getTimeCounter(); startTimer(); } public boolean useHistory() { return useHistory; } public Long getTimeCounter() { Long value = 0L; QueryResult result = sr.aSyncSelect("SELECT VALUE FROM hyperconomy_settings WHERE SETTING = 'history_time_counter'"); if (result.next()) { try { value = Long.parseLong(result.getString("VALUE")); } catch (Exception e) { value = 0L; } } else { addSetting("history_time_counter", "0"); } result.close(); return value; } public void addSetting(String setting, String value) { sw.convertAddToQueue("INSERT INTO hyperconomy_settings (SETTING, VALUE, TIME) VALUES ('" + setting + "', '" + value + "', NOW() )"); } public void updateSetting(String setting, String value) { sw.addToQueue("UPDATE hyperconomy_settings SET VALUE='" + value + "' WHERE SETTING = '" + setting + "'"); } private void startTimer() { historylogtaskid = hc.getServer().getScheduler().scheduleSyncRepeatingTask(hc, new Runnable() { public void run() { long currentTime = System.currentTimeMillis(); timeCounter += (currentTime - lastTime); lastTime = currentTime; if (timeCounter >= millisecondsInHour) { // if (timeCounter >= 600) { timeCounter = 0; writeHistoryThread(); hc.getServer().getScheduler().scheduleSyncDelayedTask(hc, new Runnable() { public void run() { if (isign != null) { isign.updateSigns(); } } }, 1200L); } updateSetting("history_time_counter", timeCounter + ""); } }, 600, 600); } private void writeHistoryThread() { ArrayList<HyperObject> objects = em.getHyperObjects(); ArrayList<String> statements = new ArrayList<String>(); for (HyperObject object : objects) { if (object instanceof HyperEnchant) { HyperEnchant he = (HyperEnchant)object; statements.add(getWriteStatement(object.getName(), object.getEconomy(), he.getValue(EnchantmentClass.DIAMOND))); } else if (object instanceof HyperItem) { HyperItem hi = (HyperItem)object; statements.add(getWriteStatement(object.getName(), object.getEconomy(), hi.getValue(1))); } else if (object instanceof BasicObject) { BasicObject bo = (BasicObject)object; statements.add(getWriteStatement(object.getName(), object.getEconomy(), bo.getValue(1))); } } if (hc.getDataBukkit().useMySQL()) { statements.add("DELETE FROM hyperconomy_history WHERE TIME < DATE_SUB(NOW(), INTERVAL " + daysToSaveHistory + " DAY)"); } else { statements.add("DELETE FROM hyperconomy_history WHERE TIME < date('now','" + formatSQLiteTime(daysToSaveHistory * -1) + " day')"); } sw.addToQueue(statements); } private String getWriteStatement(String object, String economy, double price) { return sw.convertSQL("INSERT INTO hyperconomy_history (OBJECT, ECONOMY, TIME, PRICE) VALUES ('" + object + "','" + economy + "', NOW() ,'" + price + "')"); } public void stopHistoryLog() { hc.getServer().getScheduler().cancelTask(historylogtaskid); } public void clearHistory() { String statement = "DELETE FROM hyperconomy_history"; hc.getSQLWrite().addToQueue(statement); } public double getHistoricValue(String name, String economy, int count) { try { count -= 1; QueryResult result = sr.aSyncSelect("SELECT PRICE FROM hyperconomy_history WHERE OBJECT = '" + name + "' AND ECONOMY = '" + economy + "' ORDER BY TIME DESC"); int c = 0; while (result.next()) { if (c == count) { return Double.parseDouble(result.getString("PRICE")); } c++; } result.close(); return -1.0; } catch (Exception e) { hc.gDB().writeError(e, "getHistoricValue() passed arguments: name = '" + name + "', economy = '" + economy + "', count = '" + count + "'"); return -1.0; } } /** * This function must be called from an asynchronous thread! * @param object * @param timevalue * @param economy * @return The percentage change in theoretical price for the given object and timevalue in hours */ public synchronized String getPercentChange(HyperObject ho, int timevalue) { if (ho == null || sr == null) { hc.gDB().writeError("getPercentChange passed null HyperObject or SQLRead"); return "?"; } CommonFunctions cf = hc.getCommonFunctions(); double percentChange = 0.0; double historicvalue = getHistoricValue(ho.getName(), ho.getEconomy(), timevalue); if (historicvalue == -1.0) { return "?"; } if (historicvalue == 0.0) { return "?"; } double currentvalue = 0.0; if (ho instanceof HyperEnchant) { HyperEnchant he = (HyperEnchant)ho; currentvalue = he.getValue(EnchantmentClass.DIAMOND); } else if (ho instanceof HyperItem) { HyperItem hi = (HyperItem)ho; currentvalue = hi.getValue(1); } else if (ho instanceof BasicObject) { BasicObject bo = (BasicObject)ho; currentvalue = bo.getValue(1); } percentChange = ((currentvalue - historicvalue) / historicvalue) * 100.0; percentChange = cf.round(percentChange, 3); return percentChange + ""; } /** * This function must be called from an asynchronous thread! * @param object * @param timevalue * @param economy * @return The percentage change in theoretical price for the given object and timevalue in hours */ public synchronized HashMap<HyperObject, String> getPercentChange(String economy, int timevalue) { if (sr == null) { return null; } HashMap<HyperObject, ArrayList<Double>> allValues = new HashMap<HyperObject, ArrayList<Double>>(); QueryResult result = sr.aSyncSelect("SELECT OBJECT, PRICE FROM hyperconomy_history WHERE ECONOMY = '" + economy + "' ORDER BY TIME DESC"); while (result.next()) { HyperObject ho = em.getEconomy(economy).getHyperObject(result.getString("OBJECT")); double price = result.getDouble("PRICE"); if (!allValues.containsKey(ho)) { ArrayList<Double> values = new ArrayList<Double>(); values.add(price); allValues.put(ho, values); } else { ArrayList<Double> values = allValues.get(ho); values.add(price); allValues.put(ho, values); } } result.close(); ArrayList<HyperObject> hobjects = em.getEconomy(economy).getHyperObjects(); HashMap<HyperObject, String> relevantValues = new HashMap<HyperObject, String>(); for (HyperObject ho:hobjects) { if (allValues.containsKey(ho)) { ArrayList<Double> historicValues = allValues.get(ho); if (historicValues.size() >= timevalue) { double historicValue = historicValues.get(timevalue - 1); double currentvalue = 0.0; if (ho instanceof HyperEnchant) { HyperEnchant he = (HyperEnchant)ho; currentvalue = he.getValue(EnchantmentClass.DIAMOND); } else if (ho instanceof HyperItem) { HyperItem hi = (HyperItem)ho; currentvalue = hi.getValue(1); } else if (ho instanceof HyperXP) { HyperXP bo = (HyperXP)ho; currentvalue = bo.getValue(1); } if (historicValue == 0.0) { relevantValues.put(ho, "?"); continue; } double percentChange = ((currentvalue - historicValue) / historicValue) * 100.0; percentChange = hc.getCommonFunctions().round(percentChange, 3); String stringValue = percentChange + ""; relevantValues.put(ho, stringValue); } else { relevantValues.put(ho, "?"); } } else { relevantValues.put(ho, "?"); hc.gDB().writeError("getPercentChange HyperObject missing: " + ho.getName() + ", economy: " + ho.getEconomy()); } } return relevantValues; } public String formatSQLiteTime(int time) { if (time < 0) { return "-" + Math.abs(time); } else if (time > 0) { return "+" + time; } else { return "0"; } } }