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 }