001 package market.statistics; 002 003 import java.util.Calendar; 004 import java.util.Iterator; 005 006 import market.MarketCalendar; 007 import market.SMarket; 008 import market.UCustomer; 009 import market.UMUserBase; 010 011 /** 012 * Helper class that handles the filtering and creating of analyzable statistics. 013 */ 014 public abstract class Statistics { 015 016 public static Object[] MONTHS = new Object[] {"Januar", "Februar", "März", "April", "Mai", "Juni", 017 "Juli", "August", "September", "Oktober", "November", "Dezember"}; 018 019 /** 020 * Creates an array of all years from which statistics are available. 021 * This array is used by the {@link market.swing.JCTimeRangeBoxes JCTimeRangeBoxes} that let the user 022 * select a time range for statistics to be displayed. 023 * 024 * @return the created array. 025 */ 026 public static Object[] createArticleStatisticsYears() { 027 int firstYear = getFirstArticleStatisticsYear(); 028 int lastYear = SMarket.getYear(); 029 int nrOfYears = lastYear - firstYear + 1; 030 Object[] returnObject = new Object[nrOfYears]; 031 for (int i = 0; i < nrOfYears; i++) { 032 returnObject[i] = new Integer(firstYear + i).toString(); 033 } 034 return returnObject; 035 } 036 037 /** 038 * Creates an array of all months of a given year from which statistics are available. 039 * This array is used by the {@link market.swing.JCTimeRangeBoxes JCTimeRangeBoxes} that let the user 040 * only select a time ranges for which statistics are available. 041 * 042 * @see market.swing.JCTimeRangeBoxes.FromItemListener 043 * @see market.swing.JCTimeRangeBoxes.ToItemListener 044 * @return the created array. 045 */ 046 public static Object[] createArticleStatisticsMonths(Object yearString) { 047 int year = new Integer((String)yearString).intValue(); 048 int firstMonth = 0; 049 int lastMonth = 11; 050 int firstYear = getFirstArticleStatisticsYear(); 051 int lastYear = getLastArticleStatisticsYear(); 052 if (getLastArticleStatisticsMonth() == 11) { //prevents returnObject from being initialized with a 053 lastYear++; //negative number (happens if date set to Janary => 054 } //firstMonth > lastMonth because firstYear equals 055 //lastYear and both firstMonth and lastMonth get new 056 //values) 057 if (year == firstYear || year == lastYear) { 058 if (year == firstYear) { 059 firstMonth = getFirstArticleStatisticsMonth(); 060 } 061 if (year == lastYear) { 062 lastMonth = SMarket.getMonth(); 063 } 064 Object[] returnObject = new Object[lastMonth - firstMonth + 1]; 065 System.arraycopy(MONTHS, firstMonth, returnObject, 0, returnObject.length); 066 return returnObject; 067 } else { 068 return MONTHS; 069 } 070 } 071 072 /** 073 * Sums up a CIalesStats for the desired range of time. 074 * 075 * @param id the ID of the article for which statistics are asked for. 076 * @param mFrom the first month of the statistics interval. 077 * @param yFrom the first year of the statistics interval. 078 * @param mTo the last month of the statistics interval. 079 * @param yTo the last year of the statistics interval. 080 * 081 * @return the summed up CISalesStats. 082 */ 083 public static CISalesStats getArticleStats(String id, int mFrom, int yFrom, int mTo, int yTo) { 084 CISalesStats thisMonthsItem = SMarket.getMonthlySalesStats().get(id); 085 CISalesStats returnStats = new CISalesStats(id, 0, 0); 086 CCompleteStats ccs = SMarket.getCompleteSalesStats(); 087 Iterator it = ccs.keySet(null).iterator(); 088 //initialize m and y (don't init with -1 as this might wrongly cause directlyBefore() to be true if 089 //the parameters are unfavorable 090 int m = -2; 091 int y = -2; 092 //if there are already saved statistics, initialize m and y with the month directly before 093 //the first statistics entry 094 //this is necessary to prevent the iterator from iterating over ALL elements, if the first 095 //statistics element to be evaluated is also the first one ever saved (the directlyBefore() 096 //test would say true the first time, then m and y equal mFrom and yFrom or are greater 097 //and the loop would only stop if the iterator reached the last element) 098 if (it.hasNext()) { 099 CSalesStats css = ccs.get((String)ccs.keySet(null).iterator().next()); //use new iterator! 100 m = css.getMonth() - 1; 101 y = css.getYear(); 102 } 103 //iterate over statistics catalog, until the element directly before (mFrom, yFrom) is reached 104 while (it.hasNext() && !directlyBefore(m, y, mFrom, yFrom)) { 105 CSalesStats css = ccs.get((String)it.next()); 106 y = css.getYear(); 107 m = css.getMonth(); 108 } 109 //iterate until (mTo, yTo) is reached, sum up all stats 110 while (it.hasNext() && !(y == yTo && m == mTo)) { 111 CSalesStats css = ccs.get((String)it.next()); 112 y = css.getYear(); 113 m = css.getMonth(); 114 CISalesStats ciss = css.get(id); 115 returnStats.addAmount(ciss.getAmount()); 116 returnStats.addRevenue(ciss.getRevenue()); 117 returnStats.appendOrderHistory(ciss.getOrderHistory()); 118 returnStats.appendPriceHistory(ciss.getPriceHistory()); 119 } 120 //if queried time range ends with current month, add current month's stats to returnStats, 121 if (mTo == SMarket.getMonth() && yTo == SMarket.getYear()) { 122 returnStats.addAmount(thisMonthsItem.getAmount()); 123 returnStats.addRevenue(thisMonthsItem.getRevenue()); 124 returnStats.appendOrderHistory(thisMonthsItem.getOrderHistory()); 125 returnStats.appendPriceHistory(thisMonthsItem.getPriceHistory()); 126 } 127 return returnStats; 128 } 129 130 131 /** 132 * @return {@link CCompleteStats CCompleteStats'} first entry. 133 */ 134 public static CSalesStats getFirstArticleStatisticsEntry() { 135 CCompleteStats ccs = SMarket.getCompleteSalesStats(); 136 Iterator it = ccs.keySet(null).iterator(); 137 CSalesStats css = null; 138 if (it.hasNext()) { 139 css = ccs.get((String)it.next()); 140 } 141 return css; 142 } 143 144 /** 145 * @return the year of CCompleteStats' first entry. If there is no first entry, 146 * the current year is returned. 147 */ 148 public static int getFirstArticleStatisticsYear() { 149 CSalesStats css = getFirstArticleStatisticsEntry(); 150 return css == null ? SMarket.getYear() : css.getYear(); 151 } 152 153 /** 154 * @return the month of CCompleteStats' first entry. If there is no first entry, 155 * the current month is returned. 156 */ 157 public static int getFirstArticleStatisticsMonth() { 158 CSalesStats css = getFirstArticleStatisticsEntry(); 159 return css == null ? SMarket.getMonth() : css.getMonth(); 160 } 161 162 /** 163 * @return CCompleteStats' last entry. 164 */ 165 public static CSalesStats getLastArticleStatisticsEntry() { 166 CCompleteStats ccs = SMarket.getCompleteSalesStats(); 167 Iterator it = ccs.keySet(null).iterator(); 168 CSalesStats css = null; 169 while (it.hasNext()) { 170 css = ccs.get((String)it.next()); 171 } 172 return css; 173 } 174 175 176 /** 177 * @return the year of CCompleteStats' last entry. If there is no entry, 178 * the current year is returned. 179 */ 180 public static int getLastArticleStatisticsYear() { 181 CSalesStats css = getLastArticleStatisticsEntry(); 182 return css == null ? SMarket.getYear() : css.getYear(); 183 } 184 185 /** 186 * @return the month of CCompleteStats' last entry. If there is no entry, 187 * the current month is returned. 188 */ 189 public static int getLastArticleStatisticsMonth() { 190 CSalesStats css = getLastArticleStatisticsEntry(); 191 return css == null ? SMarket.getMonth() : css.getMonth(); 192 } 193 194 /** 195 * Checks if a month is immediately before another one (e.g. March 2003 is directlyBefore April 2003). 196 * 197 * @param month the month that is checked 198 * @param year the year in that is checked 199 * @param limitMonth the month with which the checked month is compared. 200 * @param limitYear the year with which the checked year is compared. 201 * 202 * @return <code>true</code> if the checked month is directly before the other one, otherwise 203 * <code>false</code>. 204 */ 205 private static boolean directlyBefore(int month, int year, int limitMonth, int limitYear) { 206 return (month + 1 == limitMonth && year == limitYear) || 207 (month == 11 && limitMonth == 0 && year + 1 == limitYear); 208 } 209 210 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 211 // Customer stats 212 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 213 214 /** 215 * @param uc the customer whose statistics are of interest. 216 * @return the summed value of all purchases the customer has made so far. 217 */ 218 public static int getCompleteCustomerRevenue(UCustomer uc) { 219 int sum = 0; 220 Iterator it = SMarket.getCustomerStats().get(uc.getName()).getHistory().iterator(); 221 while (it.hasNext()) { 222 sum += ((HistoryEntry)it.next()).getValue(); 223 } 224 return sum; 225 } 226 227 /** 228 * @param uc the customer whose allowable revenue is of interest. 229 * @return the summed value of all purchases that affect the discount. 230 */ 231 public static int getAllowableCustomerRevenue(UCustomer uc) { 232 Calendar now = SMarket.getTime(); 233 //compute the first date, which is taken into account when calculating the discount 234 Calendar firstDate = new MarketCalendar(now.get(Calendar.YEAR), 235 now.get(Calendar.MONTH) - SMarket.getOptions().getDiscountRange(), 236 now.get(Calendar.DATE)); 237 int sum = 0; 238 Iterator it = SMarket.getCustomerStats().get(uc.getName()).getHistory().iterator(); 239 while (it.hasNext()) { 240 HistoryEntry he = (HistoryEntry)it.next(); 241 if (!he.getDate().before(firstDate)) { 242 sum += he.getValue(); 243 } 244 } 245 return sum; 246 } 247 248 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 249 // Overall stats 250 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 251 252 /** 253 * Sums up the CSalesStats for the desired range of time. 254 * 255 * @param mFrom the first month of the statistics interval. 256 * @param yFrom the first year of the statistics interval. 257 * @param mTo the last month of the statistics interval. 258 * @param yTo the last year of the statistics interval. 259 * 260 * @return the summed up CSalesStats. 261 */ 262 public static CSalesStats getOverallStats(int mFrom, int yFrom, int mTo, int yTo) { 263 CCompleteStats ccs = SMarket.getCompleteSalesStats(); 264 CSalesStats returnStats = new CSalesStats(0, 0); 265 Iterator it = ccs.keySet(null).iterator(); 266 //initialize m and y (don't init with -1 as this might cause directlyBefore() to be true if 267 //the parameters are unfavorable 268 int m = -2; 269 int y = -2; 270 //if there are already saved statistics, initialize m and y with the month directly before 271 //the first statistics entry 272 //this is necessary to prevent the iterator from iterating over ALL elements. This would 273 //happen if the first statistics element to be evaluated is also the first one ever saved. 274 //(the directlyBefore() test would say true the first time, then m and y equal mFrom and yFrom 275 //or are greater and the loop would only stop if the iterator reached the last element) 276 if (it.hasNext()) { 277 CSalesStats css = ccs.get((String)ccs.keySet(null).iterator().next()); //use new iterator! 278 m = css.getMonth() - 1; 279 y = css.getYear(); 280 } 281 //iterate over statistics catalog, until the element directly before (mFrom, yFrom) is reached 282 while (it.hasNext() && !directlyBefore(m, y, mFrom, yFrom)) { 283 CSalesStats css = ccs.get((String)it.next()); 284 y = css.getYear(); 285 m = css.getMonth(); 286 } 287 //iterate until (mTo, yTo) is reached, sum up all stats 288 int marketPurchases = 0; 289 while (it.hasNext() && !(y == yTo && m == mTo)) { 290 CSalesStats css = ccs.get((String)it.next()); 291 y = css.getYear(); 292 m = css.getMonth(); 293 returnStats.setCosts(returnStats.getCosts() + css.getCosts()); 294 returnStats.setWages(returnStats.getWages() + css.getWages()); 295 returnStats.addRevenue(css.getRevenue()); 296 returnStats.addOrders(css); 297 } 298 //if queried time range ends with current month, add current month's stats to returnStats, 299 if (mTo == SMarket.getMonth() && yTo == SMarket.getYear()) { 300 CSalesStats now = SMarket.getMonthlySalesStats(); 301 returnStats.setCosts(returnStats.getCosts() + now.getCosts()); 302 returnStats.setWages(returnStats.getWages() + UMUserBase.getGlobalBase().getCurrentWages()); 303 returnStats.addRevenue(now.getRevenue()); 304 returnStats.addOrders(now); 305 } 306 return returnStats; 307 } 308 309 }