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    }