001package com.fs.starfarer.api.impl.campaign.shared;
002
003import java.util.HashMap;
004import java.util.List;
005import java.util.Map;
006
007import com.fs.starfarer.api.Global;
008import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI;
009import com.fs.starfarer.api.campaign.econ.EconomyAPI;
010import com.fs.starfarer.api.campaign.econ.MarketAPI;
011import com.fs.starfarer.api.util.IntervalUtil;
012import com.fs.starfarer.api.util.Misc;
013import com.fs.starfarer.api.util.SaveableIterator;
014
015public class CommodityStatTracker {
016
017        public static class CommodityStats {
018                private float minSupplyPrice;
019                private float maxDemandPrice;
020                private float averageSupplyPrice;
021                private float averageDemandPrice;
022                private float totalDemand;
023                private float totalSupply;
024                private float totalStockpiles;
025                private final String commodityId;
026
027                public CommodityStats(String commodityId) {
028                        this.commodityId = commodityId;
029                }
030                
031//              public MarketAPI getMarket() {
032//                      return Global.getSector().getEconomy().getMarket(marketId);
033//              }
034//              public CommodityOnMarketAPI getCommodity() {
035//                      MarketAPI market = getMarket();
036//                      if (market == null) return null;
037//                      return market.getCommodityData(commodityId);
038//              }
039                
040                public float getMinSupplyPrice() {
041                        return minSupplyPrice;
042                }
043                public float getMaxDemandPrice() {
044                        return maxDemandPrice;
045                }
046                public float getAverageSupplyPrice() {
047                        return averageSupplyPrice;
048                }
049                public float getAverageDemandPrice() {
050                        return averageDemandPrice;
051                }
052                public String getCommodityId() {
053                        return commodityId;
054                }
055                public void setMinSupplyPrice(float min) {
056                        this.minSupplyPrice = min;
057                }
058                public void setMaxDemandPrice(float max) {
059                        this.maxDemandPrice = max;
060                }
061                public void setAverageSupplyPrice(float average) {
062                        this.averageSupplyPrice = average;
063                }
064                public float getTotalDemand() {
065                        return totalDemand;
066                }
067                public void setTotalDemand(float totalDemand) {
068                        this.totalDemand = totalDemand;
069                }
070                public float getTotalSupply() {
071                        return totalSupply;
072                }
073                public void setTotalSupply(float totalSupply) {
074                        this.totalSupply = totalSupply;
075                }
076                public float getTotalStockpiles() {
077                        return totalStockpiles;
078                }
079                public void setTotalStockpiles(float totalStockpiles) {
080                        this.totalStockpiles = totalStockpiles;
081                }
082                public void setAverageDemandPrice(float weightedAveragePrice) {
083                        this.averageDemandPrice = weightedAveragePrice;
084                }
085        }
086        
087        private IntervalUtil timer = new IntervalUtil(0.25f, 0.75f);
088        
089        private Map<String, CommodityStats> priceData = new HashMap<String, CommodityStats>();
090        private boolean firstFrame = true;
091        
092        public void advance(float days) {
093
094                if (firstFrame) {
095                        firstFrame = false;
096                        EconomyAPI economy = Global.getSector().getEconomy();
097                        for (String id : economy.getAllCommodityIds()) {
098                                updateCommodityStats(id);
099                        }
100                }
101                
102                timer.advance(days);
103                if (timer.intervalElapsed()) {
104                        updateStatsNextStep();
105                }
106                
107//              compute prices stuff here? min/max
108//              add an "is price change significant" method; "is price significant" method
109        }
110        
111        
112        public boolean isSupplyPriceSignificant(CommodityOnMarketAPI com) {
113                return isSupplyPriceWithMultSignificant(com, 1f);
114        }
115        public boolean isDemandPriceSignificant(CommodityOnMarketAPI com) {
116                return isDemandPriceWithMultSignificant(com, 1f);
117        }
118        
119        public boolean isSupplyPriceWithMultSignificant(CommodityOnMarketAPI com, float mult) {
120                float supplyPrice = Math.round(com.getMarket().getSupplyPrice(com.getId(), 1, true));
121                supplyPrice *= mult;
122                return isSupplyPriceSignificant(com, supplyPrice);
123        }
124        
125        public boolean isDemandPriceWithMultSignificant(CommodityOnMarketAPI com, float mult) {
126                float demandPrice = Math.round(com.getMarket().getDemandPrice(com.getId(), 1, true));
127                demandPrice *= mult;
128                return isSupplyPriceSignificant(com, demandPrice);
129        }
130        
131        public boolean isSupplyPriceSignificant(CommodityOnMarketAPI com, float price) {
132                //if (com.getAverageStockpileAfterDemand() < 100) return false;
133                CommodityStats stats = getStats(com.getId());
134                float average = stats.getAverageSupplyPrice();
135                //return price <= average * .5f || average - price > com.getCommodity().getBasePrice() * 0.5f;
136                //return price <= average * .5f || average - price > 100f;
137                //return price <= average * .5f || average - price > Math.max(100, com.getCommodity().getBasePrice() * 0.5f);
138                
139//              float margin = Misc.getProfitMargin();
140//              margin = Math.min(margin * 0.5f, average * 0.75f);
141                float flat = Misc.getProfitMarginFlat();
142                float mult = Misc.getProfitMarginMult();
143                
144                return price <= average - flat || price <= average / mult;
145                
146//              if (margin < Misc.getProfitMargin() * 0.25f) {
147//                      margin = Misc.getProfitMargin() * 0.25f;
148//              }
149//              return price <= average - margin;
150        }
151        
152        public boolean isDemandPriceSignificant(CommodityOnMarketAPI com, float price) {
153                //if (com.getDemand().getDemandValue() < 100) return false;
154                CommodityStats stats = getStats(com.getId());
155                float average = stats.getAverageDemandPrice();
156                //return price >= average * 1.75f || price - average > com.getCommodity().getBasePrice() * 1f;
157                //return price >= average * 1.75f || price - average > 100f;
158                //return price >= average * 1.75f || price - average > Math.max(100, com.getCommodity().getBasePrice() * 1f);
159                
160                float flat = Misc.getProfitMarginFlat();
161                float mult = Misc.getProfitMarginMult();
162                
163                return price >= average + flat || price >= average * mult;
164                
165//              float margin = Misc.getProfitMargin();
166//              margin = margin - Math.min(margin * 0.5f, average * 0.5f);
167//              
168//              return price >= average + margin;
169        }
170
171        
172//      public boolean isCommodityPriceSpreadInteresting(String commodityId) {
173//              CommodityStats stats = getStats(commodityId);
174//
175//              float diff = Math.abs(stats.getMaxDemandPrice() - stats.getMinSupplyPrice());
176//              return isCommodityPriceSpreadInteresting(commodityId, diff);
177//      }
178//      
179//      public boolean isCommodityPriceSpreadInteresting(String commodityId, float diff) {
180//              CommodityStats stats = getStats(commodityId);
181//              if (diff > 100) return true;
182//              if (diff > stats.getMinSupplyPrice() * .75f) return true;
183//              return false;
184//      }
185        
186        
187        
188        private SaveableIterator<String> commodityIterator = null;
189        private void updateStatsNextStep() {
190                EconomyAPI economy = Global.getSector().getEconomy();
191                
192                if (commodityIterator == null || !commodityIterator.hasNext()) {
193                        commodityIterator = new SaveableIterator<String>(economy.getAllCommodityIds());
194                }
195                if (!commodityIterator.hasNext()) return; // no commodities exist, yyeah.
196                
197                String commodityId = commodityIterator.next();
198                
199                updateCommodityStats(commodityId);
200        }
201        
202        public void updateCommodityStats(String commodityId) {
203                EconomyAPI economy = Global.getSector().getEconomy();
204                List<MarketAPI> markets = economy.getMarketsCopy();
205
206                float totalSupply = 0;
207                float totalDemand = 0;
208                float totalStockpiles = 0;
209                float minSupplyPrice = Float.MAX_VALUE;
210                float maxDemandPrice = 0;
211                
212                float totalSupplyPrice = 0;
213                float totalDemandPrice = 0;
214                
215                for (MarketAPI market : markets) {
216                        CommodityOnMarketAPI com = market.getCommodityData(commodityId);
217                        
218                        //float supply = com.getSupplyValue();
219                        float demand = com.getDemand().getDemandValue();
220                        float supply = demand;
221                        float stockpile = com.getStockpile();
222                        
223                        if (supply < 10 && demand < 10 && stockpile < 10) continue;
224                        
225                        float supplyPrice = Math.round(market.getSupplyPrice(com.getId(), 1, true));
226                        float demandPrice = Math.round(market.getDemandPrice(com.getId(), 1, true)); 
227                
228                        if (supplyPrice < minSupplyPrice) {
229                                minSupplyPrice = supplyPrice;
230                        }
231                        if (demandPrice > maxDemandPrice) {
232                                maxDemandPrice = demandPrice;
233                        }
234                        
235                        totalSupply += supply;
236                        totalDemand += demand;
237                        totalStockpiles += stockpile;
238                        
239                        totalSupplyPrice += stockpile * supplyPrice;
240                        totalDemandPrice += demand * demandPrice;
241                }
242                
243                CommodityStats stats = getStats(commodityId);
244                
245                stats.setTotalSupply(totalSupply);
246                stats.setTotalDemand(totalDemand);
247                stats.setTotalStockpiles(totalStockpiles);
248                stats.setMaxDemandPrice(maxDemandPrice);
249                stats.setMinSupplyPrice(minSupplyPrice);
250                
251                if (totalStockpiles > 0) {
252                        stats.setAverageSupplyPrice(totalSupplyPrice / totalStockpiles);
253                } else {
254                        stats.setAverageSupplyPrice(0);
255                }
256                
257                if (totalDemand > 0) {
258                        stats.setAverageDemandPrice(totalDemandPrice / totalDemand);
259                } else {
260                        stats.setAverageDemandPrice(0);
261                }
262        }
263        
264        
265        public CommodityStats getStats(String commodityId) {
266                CommodityStats data = priceData.get(commodityId);
267                if (data == null) {
268                        data = new CommodityStats(commodityId);
269                        priceData.put(commodityId, data);
270                }
271                return data;
272        }
273}
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297