001    package market;
002    
003    import java.awt.Rectangle;
004    import java.io.IOException;
005    import java.util.ArrayList;
006    import java.util.Calendar;
007    import java.util.Iterator;
008    import java.util.List;
009    
010    import javax.swing.JFrame;
011    
012    import log.Log;
013    import market.event.MarketEventListener;
014    import market.resource.IconSetter;
015    import market.statistics.CCompleteStats;
016    import market.statistics.CCustomerStats;
017    import market.statistics.CISalesStats;
018    import market.statistics.CSalesStats;
019    import market.statistics.Statistics;
020    import sale.Action;
021    import sale.MenuSheet;
022    import sale.MenuSheetItem;
023    import sale.SaleProcess;
024    import sale.SalesPoint;
025    import sale.Shop;
026    import sale.StepTimer;
027    import sale.Time;
028    import data.Catalog;
029    import data.CountingStock;
030    import data.IntegerValue;
031    import data.Value;
032    import data.ooimpl.CatalogImpl;
033    import data.ooimpl.StoringStockImpl;
034    
035    /**
036     * The Shop of this sale-application.
037     */
038    public class SMarket extends Shop {
039    
040        /**
041             * ID for serialization.
042             */
043            private static final long serialVersionUID = 8972722234332831551L;
044            
045            public static final String CAT_ARTICLECATALOG = "Produktkatalog";
046        public static final String CAT_OPENPURCHASE = "Erwartete Lieferungen";
047        public static final String CAT_CUSTOMER = "Kunden";
048        public static final String CAT_COMPLETE_SALESSTATS = "Komplette Statistik";
049        public static final String STK_OFFER = "Angebot";
050        public static final String STK_TILLQUEUE = "Kunden-Warteschlange";
051        public static final String STK_WAREHOUSEQUEUE = "Auftrags-Warteschlange";
052        public static final String MARKET_CLOSES_SHORT = "ACHTUNG: Der Markt schließt jetzt.";
053        public static final String MARKET_CLOSES_LONG = "Der Markt schließt gleich. Beehren sie uns doch " +
054                "morgen wieder.";
055        public static final String MARKET_CLOSES_NOT = "Der Markt hat doch noch eine Weile geöffnet.";
056        public static final String MARKET_CLOSED = "Der Markt hat geschlossen.";
057        public static final String MARKET_OPENED = "Der Markt hat geöffnet.";
058        private static final String SHOP_CAPTION = "Großmarkt Sohn & Sohn";
059    
060        private MenuSheetItem msiNewCustomer;
061        private MenuSheetItem msiCustomer;
062        private MenuSheetItem msiSeller;
063        private MenuSheetItem msiWorker;
064        private MenuSheetItem msiManager;
065        private Calendar dateOfOpening;
066    
067    
068        /**
069         * The {@link Options options}, which affect the computation of the discount and the
070         * dismissal compensation.
071         */
072        private Options options = new Options();
073    
074        /**
075         * The listeners listening to market events.
076         */
077        private MarketEventListener[] evl = new MarketEventListener [0];
078    
079        /**
080         * Indicates if market ist open, soon to close, or closed.
081         */
082        private int open;
083    
084        /**
085         * Indicates if the market's time has advanced.
086         * This variable is set to true when the day changes. As soon as the market opens,
087         * timeAdvanced will be false.<br>
088         * That makes it possible to distinguish between the two possibilities
089         * <ol><li>time has advanced and market can be opened</li>
090         * <li>market has just closed and day has not been changed yet</li></ol>
091         */
092        private boolean timeAdvanced;
093    
094        /**
095         * Catalog which contains all {@link CIArticle CIArticles}
096         */
097        private CatalogImpl c_articleCatalog;
098    
099        /**
100         * Stock which contains all {@link CIArticle CIArticles} currently available
101         */
102        private CSOffer cs_offer;
103    
104        /**
105         * Catalog which contains all orders placed by the manager that have not yet arrived.
106         */
107        private COpenPurchaseOrders c_openPurchaseOrders;
108    
109        /**
110         * Catalog that stores all customers' names.
111         * This catalog is needed for the customer stock ({@link #ss_tillQueue till queue}).
112         */
113        private CatalogImpl c_customer;
114    
115        /**
116         * Catalog that stores sales statistics for the current day. This Catalog is used to make sure that
117         * sales don't show up in the statistics unless the day-end closing has been completed.
118         */
119        private CSalesStats c_dailyStats;
120    
121        /**
122         * Catalog that stores sales statistics (amount of sold articles, revenue from sold articles...)
123         * for one month.
124         */
125        private CSalesStats c_monthlyStats;
126    
127        /**
128         * Catalog that stores {@link CSalesStats sales statistics} of all passed months.
129         */
130        private CCompleteStats c_completeStats;
131    
132        /**
133         * Catalog that stores the statistics of all market's customers. Those statistics are
134         * time independend, that means, it is not split up into months.
135         */
136        private CCustomerStats c_customerStats;
137    
138        /**
139         * The global queue of customers' orders waiting for warehouse-worker-processing.
140         */
141        private StoringStockImpl ss_warehouseQueue;
142    
143        /**
144         * The global queue of customers waiting at the till.
145         */
146        private StoringStockImpl ss_tillQueue;
147    
148        /**
149         * The money of the market.
150         */
151        private IntegerValue iv_account;
152    
153    
154    //####################### SalesPoint methods ################################################################
155    
156        /**
157         * Creates an SMarket, initiates global Catalogs, Stocks and other settings.
158         */
159        public SMarket(Time time){
160            super();
161            setTheShop(this);
162            setTimer(new StepTimer(time));
163            setShopFrameBounds(new Rectangle(50,50,400,300));
164            setShopFrameTitle(SHOP_CAPTION + "  -  " + getTime());
165            IconSetter.setIcon(getShopFrame());
166            open = 2; timeAdvanced = true; //shop starts in the morning
167            c_articleCatalog = new CArticleCatalog(CAT_ARTICLECATALOG);
168            addCatalog(c_articleCatalog);
169            cs_offer = new CSOffer(STK_OFFER, c_articleCatalog);
170            addStock(cs_offer);
171            c_customer = new CatalogImpl(CAT_CUSTOMER);
172            addCatalog(c_customer);
173            ss_tillQueue = new SSListenable(STK_TILLQUEUE, c_customer);
174            addStock(ss_tillQueue);
175            ss_warehouseQueue = new SSListenable(STK_WAREHOUSEQUEUE, c_customer);
176            addStock(ss_warehouseQueue);
177            iv_account = new IntegerValue(0);
178            //clone, otherwise dateOfOpening would change with current time
179            dateOfOpening = (Calendar)getTime().clone();
180        }
181    
182        /**
183         * Returns the JFrame of the Shop window. The difference to the {@link Shop Shop's} getShopFrame()
184         * method is, that this one is public, as the Shop's window is needed by a dialog.
185         * @see JDDShowMessage#showMessageDialog(String, String)
186         *
187         * @return the Shop's frame.
188         */
189        public JFrame getShopFrame() {
190            return super.getShopFrame();
191        }
192    
193        /**
194         * Starts the Shop and initializes statistics items.
195         */
196        public void start() {
197            c_openPurchaseOrders = new COpenPurchaseOrders(CAT_OPENPURCHASE);
198            addCatalog(c_openPurchaseOrders);
199            c_monthlyStats = new CSalesStats(getYear(), getMonth());
200            c_monthlyStats.initPriceHistory();
201            addCatalog(c_monthlyStats);
202            c_dailyStats = new CSalesStats(getYear(), getMonth());
203            c_customerStats = new CCustomerStats();
204            c_completeStats = new CCompleteStats(CAT_COMPLETE_SALESSTATS);
205            addCatalog(c_completeStats);
206            super.start();
207            try {
208                Log.setGlobalLogFile("marketlog.txt", true, false);
209            }
210            catch (IOException e) {
211                System.err.println("Cannot set log file");
212            }
213            setOpen(0);
214        }
215    
216        /**
217         * Closes the SMarket.
218         */
219        public void quit() {
220            if (shutdown (false)) {
221                System.exit(0);
222            }
223        }
224    
225        /**
226         * Sets the icon when market is loaded from persistence file.
227         */
228        public void resume() {
229            super.resume();
230            IconSetter.setIcon(getShopFrame());
231        }
232    
233        /**
234         * Creates the MenuSheet of the SMarket
235         *
236         * @return the MenuSheet of the SMarket
237         */
238        public MenuSheet createShopMenuSheet(){
239            MenuSheet msMenuBar = new MenuSheet("Menubar");
240            MenuSheet msShop = (MenuSheet)super.createShopMenuSheet().getTaggedItem(Shop.SHOP_MENU_TAG, false);
241            MenuSheet msLogOn = new MenuSheet("Anmeldung");
242            MenuSheet msSimulation = new MenuSheet("Simulation");
243            msiNewCustomer = new MenuSheetItem("Kundenregistrierung", SProcessCustomerEditProfile.create());
244            msiCustomer = new MenuSheetItem("Kunde", SProcessLogOn.createLogOnProcess(UMUserBase.CUSTOMER));
245            msiSeller = new MenuSheetItem("Kasse", SProcessLogOn.createLogOnProcess(UMUserBase.SELLER));
246            msiWorker = new MenuSheetItem("Lager", SProcessLogOn.createLogOnProcess(UMUserBase.WAREHOUSE_WORKER));
247            msiManager = new MenuSheetItem("Manager", SProcessLogOn.createLogOnProcess(UMUserBase.MANAGER));
248            MenuSheetItem msiAdvanceTime = new MenuSheetItem("Zu Wunschdatum vor", new Action() {
249                            private static final long serialVersionUID = -6709968809343202422L;
250                            public void doAction(SaleProcess p, SalesPoint sp) {
251                    if (isOpen()) {
252                        JDDShowMessage.showMessageDialog(
253                                "Die Zeit kann erst weitergeschaltet werden,\nwenn der Markt " +
254                                "geschlossen ist.\n\n (Manager -> System -> Öffnen/Schließen)", "Fehler");
255                    } else {
256                        SMarket.getTheShop().addSalesPoint(new SPTime());
257                    }
258                            }
259                    });
260            msLogOn.add(msiNewCustomer);
261            msLogOn.add(msiCustomer);
262            msLogOn.add(msiSeller);
263            msLogOn.add(msiWorker);
264            msLogOn.add(msiManager);
265            msSimulation.add(msiAdvanceTime);
266            msMenuBar.add(msShop);
267            msMenuBar.add(msLogOn);
268            msMenuBar.add(msSimulation);
269            return msMenuBar;
270        }
271    
272        /**
273         * Adds a {@link SalesPoint} to the market attaches a {@link MarketEventListener} to it.
274         *
275         * @param sp the SalesPoint to be added.
276         */
277        public void addSalesPoint(SalesPoint sp) {
278            super.addSalesPoint(sp);
279            if (sp instanceof SPListenable) SMarket.addEventListener((SPListenable)sp);
280            if (sp instanceof SPCustomer) SMarket.addEventListener((SPCustomer)sp);
281        }
282    
283        /**
284         * Removes a {@link SalesPoint} to the market detachses its {@link MarketEventListener}.
285         *
286         * @param sp the SalesPoint to be removed.
287         */
288        public void removeSalesPoint(SalesPoint sp) {
289            super.removeSalesPoint(sp);
290            if (sp instanceof SPListenable) SMarket.removeEventListener((SPListenable)sp);
291            if (sp instanceof SPCustomer) SMarket.removeEventListener((SPCustomer)sp);
292        }
293    
294    
295    
296    //##################### Our methods #########################################################################
297    
298    ////////////////////////////////////////////////////////////////////////////////////////////////////////
299    // Account (getting and setting)
300    ////////////////////////////////////////////////////////////////////////////////////////////////////////
301    
302        /**
303         * Adds a Value to the markets account.
304         *
305         * @param money the Value that will be added.
306         */
307        public static void addToAccount(Value money) {
308            ((SMarket)Shop.getTheShop()).iv_account.addAccumulating(money);
309        }
310    
311        /**
312         * Subtracts a Value from the markets account.
313         *
314         * @param money the Value that will be substracted.
315         */
316        public static void subtractFromAccount(Value money) {
317            ((SMarket)Shop.getTheShop()).iv_account.subtractAccumulating(money);
318        }
319    
320        /**
321         * @return the account of the market as Value.
322         */
323        public static Value getAccount(){
324            return ((SMarket)Shop.getTheShop()).iv_account;
325        }
326    
327        public static Options getOptions() {
328            return getTheMarket().options;
329        }
330    
331    
332    ////////////////////////////////////////////////////////////////////////////////
333    // Shortcuts
334    ////////////////////////////////////////////////////////////////////////////////
335    
336        /**
337         * @return the singleton instance of SMarket.
338         */
339        public static SMarket getTheMarket() {
340            return (SMarket)getTheShop();
341        }
342    
343        /**
344         * Shortcut for catalog with all articles.
345         */
346        public static CArticleCatalog getArticleCatalog() {
347          return (CArticleCatalog)getTheShop().getCatalog(CAT_ARTICLECATALOG);
348        }
349    
350        /**
351         * Shortcut to the market's current stock.
352         */
353        public static CSOffer getOffer() {
354          return (CSOffer)getTheShop().getStock(STK_OFFER);
355        }
356    
357        /**
358         * Shortcut to the catalog that holds the market's purchases which have not yet arrived.
359         */
360        public static COpenPurchaseOrders getOpenPurchaseOrder() {
361            return (COpenPurchaseOrders)getTheShop().getCatalog(CAT_OPENPURCHASE);
362        }
363    
364        /**
365         * Shortcut to the catalog that holds all customers of the market.
366         * This catalog is needed as a base for till- and warehouse-queue.
367         */
368        public static Catalog getCustomers(){
369            return Shop.getTheShop().getCatalog(SMarket.CAT_CUSTOMER);
370        }
371    
372        /**
373         * Shortcut for the queue of customers who want to pay.
374         */
375        public static SSListenable getTillQueue(){
376            return (SSListenable)Shop.getTheShop().getStock(SMarket.STK_TILLQUEUE);
377        }
378    
379        /**
380         * Shortcut for the queue of orders waiting at the warehouse.
381         */
382        public static SSListenable getWarehouseQueue(){
383            return (SSListenable)Shop.getTheShop().getStock(SMarket.STK_WAREHOUSEQUEUE);
384        }
385    
386        /**
387         * Shortcut to the catalog that holds the current day's statistics.
388         */
389        public static CSalesStats getDailySalesStats() {
390            return (CSalesStats)(getTheMarket()).c_dailyStats;
391        }
392    
393        /**
394         * Shortcut to the catalog that holds the current month's statistics.
395         */
396        public static CSalesStats getMonthlySalesStats() {
397            return (CSalesStats)(getTheMarket()).c_monthlyStats;
398        }
399    
400        /**
401         * Shortcut to the statistics catalog
402         */
403        public static CCompleteStats getCompleteSalesStats() {
404            return (CCompleteStats)getTheShop().getCatalog(CAT_COMPLETE_SALESSTATS);
405        }
406    
407        /**
408         * Shortcut to the customer stats catalog
409         */
410        public static CCustomerStats getCustomerStats() {
411            return getTheMarket().c_customerStats;
412        }
413    
414    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
415    // Misc.
416    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
417    
418        /**
419         * Returns Categories of all available Articles.
420         * This method is used by dropdown filters for initialization.
421         */
422        public static Object[] getArticleCategories(){
423            List<String> l = new ArrayList<String>();
424            l.add("Alles");
425            Iterator it = getArticleCatalog().iterator(null, false);
426            CIArticle art = null;
427            String category = null;
428            while (it.hasNext()) {
429                art = (CIArticle)it.next();
430                category = art.getCategory();
431                if (!l.contains(category)) {
432                    l.add(category);
433                }
434            }
435            return l.toArray();
436        }
437    
438        /**
439         * Sets the market's state.
440         *
441         * @param i <ul>
442         *             <li>0: The market is open, customers can buy</li>
443         *             <li>1: The market is about to close, customers cannot login nor start new
444         *                      purchases, even if they are already logged in.</li>
445         *             <li>2: The market is closed, only the manager can log in</li>
446         *          </ul>
447         */
448        public void setOpen(int i) {
449            open = i;
450            if (i == 0) {
451                timeAdvanced = false;
452                msiNewCustomer.setEnabled(true);
453                msiCustomer.setEnabled(true);
454                msiSeller.setEnabled(true);
455                msiWorker.setEnabled(true);
456            }
457            if (i == 1) {
458                fireMarketClosing();
459                msiNewCustomer.setEnabled(false);
460                msiCustomer.setEnabled(false);
461            }
462            if (i == 2) {
463                fireMarketClosed();
464                addDailyStatsToMonthlyStats();
465                msiNewCustomer.setEnabled(false);
466                msiCustomer.setEnabled(false);
467                msiSeller.setEnabled(false);
468                msiWorker.setEnabled(false);
469            }
470        }
471    
472        /**
473         * @return whether the market is currently open or not.
474         */
475         public static boolean isOpen() {
476            return getTheMarket().open == 0 || getTheMarket().open == 1;
477         }
478    
479         /**
480          * @return whether the manager has announced the market's closing or not.
481          */
482         public static boolean isToBeClosed() {
483            return getTheMarket().open == 1;
484         }
485    
486         /**
487          * @return whether the time has advanced or not.
488          * @see #timeAdvanced
489          */
490         public static boolean hasTimeAdvanced() {
491            return getTheMarket().timeAdvanced;
492         }
493    
494    
495    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
496    // Time
497    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
498    
499         /**
500          * Convenience method
501          *
502          * @return the current date.
503          */
504        public static Calendar getTime() {
505            return (Calendar)getTheMarket().getTimer().getTime();
506        }
507    
508        /**
509         * @return the date that the market has started its business.
510         */
511        public static Calendar getDateOfOpening() {
512            return getTheMarket().dateOfOpening;
513        }
514    
515        /**
516         * Convencience method.
517         *
518         * @return the current year.
519         */
520        public static int getYear() {
521            return getTime().get(Calendar.YEAR);
522        }
523    
524        /**
525         * Convenience method.
526         *
527         * @return the current month.
528         */
529        public static int getMonth() {
530            return getTime().get(Calendar.MONTH);
531        }
532    
533        /**
534         * Sets the market's time to a new date.
535         *
536         * @param newTime the new date to be set.
537         */
538        public static void setTime(Calendar newTime) {
539            int diff = Conversions.dayDifference(getTime(), newTime);
540            getTheShop().getTimer().setTime(newTime);
541            getTheMarket().computeEventsOnDayChanges(diff);
542        }
543    
544        /**
545         * Advances the market's time by 1 day.
546         */
547        public static void setNextDay() {
548            getTheShop().getTimer().goAhead();
549            getTheMarket().computeEventsOnDayChanges(1);
550        }
551    
552        /**
553         * Does things that need to be done when the time advances.
554         * The Shop's title is set to the new date, the waiting time for new orders is decreased,
555         * if new orders arrived they are added to the current offer.
556         * If not only the day but also the month changed, the statistics and the market's account
557         * are updated.
558         *
559         * @param daysAdvanced The number of days the time advanced.
560         */
561        private void computeEventsOnDayChanges(int daysAdvanced) {
562            setShopFrameTitle(SHOP_CAPTION + "  -  " + getTime());
563            timeAdvanced = true;
564            //when open purchase orders arrive, add them to market's stock, otherwise just decrease the
565            //numbers of days to wait
566            CountingStock arrivedOrders = getOpenPurchaseOrder().subtractPassedDays(daysAdvanced);
567            if(arrivedOrders.size(null)>0){
568                getOffer().addStock(arrivedOrders, null, false);
569                getWarehouseQueue().fireWakeUpOrders();
570            }
571            if (hasMonthChanged(daysAdvanced)) {//if month changed
572                getMonthlySalesStats().setWages(
573                        UMUserBase.getGlobalBase().getCurrentWages()); //save current wages to statistics
574                getCompleteSalesStats().add(getMonthlySalesStats(), null); //update statistics catalogs
575                int currentMiscCosts = c_monthlyStats.getCosts();
576                considerJumpedOverMonths();
577                c_monthlyStats = new CSalesStats(getYear(), getMonth());
578                c_monthlyStats.setCosts(currentMiscCosts);
579                c_monthlyStats.initPriceHistory();
580                subtractFromAccount(new IntegerValue(monthlyCosts()));      //update account
581            }
582            fireTimeAdvanced();
583        }
584    
585        /**
586         * This method checks if the month changed due to the progress of time.
587         *
588         * @param daysAdvanced The number of days the time advanced.
589         * @return true, if the month changed
590         */
591        private boolean hasMonthChanged(int daysAdvanced) {
592            int dayOfMonth = getTime().get(Calendar.DAY_OF_MONTH);
593            return daysAdvanced >= dayOfMonth;
594        }
595    
596        /**
597         * Adds an empty statistics entry to the statistics for every month that has been jumped over.
598         * Besides, the monthly costs of the market are subtracted from the account.
599         */
600        private void considerJumpedOverMonths() {
601            int currentMiscCosts = c_monthlyStats.getCosts();
602            CCompleteStats ccs = getCompleteSalesStats();
603            int m = Statistics.getLastArticleStatisticsMonth() + 1; //set not to last month, but to its successor
604            int y = Statistics.getLastArticleStatisticsYear();
605            if (m == 12) {
606                m = 0;
607                y++;
608            }
609            int mNow = getMonth();
610            int yNow = getYear();
611            while (m != mNow || y != yNow) {
612                CSalesStats css = new CSalesStats(y, m);
613                css.setCosts(currentMiscCosts);
614                css.initPriceHistory();
615                css.setWages(UMUserBase.getGlobalBase().getCurrentWages());
616                ccs.add(css, null);
617                subtractFromAccount(new IntegerValue(monthlyCosts()));      //update account
618                m++;
619                if (m == 12) {
620                    m = 0;
621                    y++;
622                }
623            }
624        }
625    
626        /**
627         * Adds today's statistic entries to the monthly stats.
628         * This covers the sales statistics of every single article and the current day's total revenue.
629         */
630        private void addDailyStatsToMonthlyStats() {
631            Iterator it = c_dailyStats.iterator(null, false);
632            while (it.hasNext()) {
633                CISalesStats dailyCiss = (CISalesStats)it.next();
634                c_monthlyStats.get(dailyCiss.getArticleID()).addAmount(dailyCiss.getAmount());
635                c_monthlyStats.get(dailyCiss.getArticleID()).addRevenue(dailyCiss.getRevenue());
636            }
637            c_monthlyStats.addRevenue(c_dailyStats.getRevenue());
638            c_dailyStats = new CSalesStats(getYear(), getMonth());
639        }
640    
641        /**
642         * Convenience method that returns the total costs per month.
643         * This covers both the whole wages and the miscellaneous costs that were set in the options.
644         */
645        private int monthlyCosts() {
646            return UMUserBase.getGlobalBase().getCurrentWages() + c_monthlyStats.getCosts();
647        }
648    
649    
650    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
651    // Event handling
652    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
653    
654        /**
655         * Adds a new EventListener to the market.
656         */
657        public static void addEventListener(MarketEventListener e) {
658            MarketEventListener[] evl = (getTheMarket()).evl;
659            int len = evl.length;
660            boolean exists = false;
661            for (int i = 0; i < len; i++) {
662                exists = exists || (evl[i] == e);
663            }
664            if (!exists) {
665                MarketEventListener[] temp = new MarketEventListener[len+1];
666                System.arraycopy(evl, 0, temp, 0, len);
667                temp[len] = e;
668                evl = temp;
669            }
670            (getTheMarket()).evl = evl;
671        }
672    
673        /**
674         * Removes an EventListener from the market.
675         */
676        public static void removeEventListener(MarketEventListener e) {
677            MarketEventListener[] evl = (getTheMarket()).evl;
678            for (int i = 0; i < evl.length; i++) {
679                if (evl[i] == e) {
680                    MarketEventListener[] temp = new MarketEventListener[evl.length-1];
681                    if (i > 0) System.arraycopy(evl,0,temp,0,i);
682                    if (i < evl.length-1) System.arraycopy(evl,i+1,temp,i,evl.length-1-i);
683                    evl = temp;
684                    break;
685                }
686            }
687            (getTheMarket()).evl = evl;
688        }
689    
690    
691        /**
692         * Fires an event to all listeners: The market is about to close. (Which means, the manager pressed
693         * his &quot;Closing-Time&quot; button.)
694         */
695        public static void fireMarketClosing()  {
696            MarketEventListener[] evl = (getTheMarket()).evl;
697            for (int i = 0; i < evl.length; i++) {
698                if (evl[i] != null) evl[i].notifyOnMarketClosing();
699            }
700        }
701    
702        /**
703         * Fires an event to all listeners: The market isn't about to close anymore. (Which means, the manager
704         * canceled closing time.)
705         */
706        public static void fireMarketNotClosing()  {
707            MarketEventListener[] evl = (getTheMarket()).evl;
708            for (int i = 0; i < evl.length; i++) {
709                if (evl[i] != null) evl[i].notifyOnMarketNotClosing();
710            }
711        }
712    
713        /**
714         * Fires an event to all listeners: The market has just closed.
715         */
716        public static void fireMarketClosed()  {
717            MarketEventListener[] evl = (getTheMarket()).evl;
718            for (int i = 0; i < evl.length; i++) {
719                if (evl[i] != null) evl[i].marketClosed();
720            }
721        }
722    
723        /**
724         * Fires an event to all listeners: The market has just opened.
725         */
726        public static void fireMarketOpened()  {
727            MarketEventListener[] evl = (getTheMarket()).evl;
728            for (int i = 0; i < evl.length; i++) {
729                if (evl[i] != null) evl[i].marketOpened();
730            }
731        }
732    
733        /**
734         * Fires an event to all listeners: The time has advanced..
735         */
736        public static void fireTimeAdvanced()  {
737            MarketEventListener[] evl = (getTheMarket()).evl;
738            for (int i = 0; i < evl.length; i++) {
739                if (evl[i] != null) evl[i].timeAdvanced();
740            }
741        }
742    
743        /**
744         * Fires an event to all listeners: The number of workers or orders to process has changed.
745         */
746        public static void fireUpdateWorkerScreen(){
747             MarketEventListener[] evl = (getTheMarket()).evl;
748            for (int i = 0; i < evl.length; i++) {
749                if (evl[i] != null) evl[i].workerInformationChanged();
750            }
751        }
752    }