001    package videoautomat;
002    import java.util.Iterator;
003    
004    import sale.*;
005    import sale.FormSheet.FormButton;
006    import sale.stdforms.FormSheetStrategy;
007    import users.User;
008    import videoautomat.gui.Rent;
009    import data.*;
010    import data.events.StockChangeAdapter;
011    import data.events.StockChangeEvent;
012    import data.events.VetoException;
013    import data.ooimpl.CountingStockItemDBEntry;
014    import data.ooimpl.MoneyBagImpl;
015    import data.stdforms.TwoTableFormSheet;
016    import data.stdforms.twotableformsheet.CCSStrategy;
017    import data.stdforms.twotableformsheet.CSDBStrategy;
018    import data.swing.DefaultStoringStockDBETableEntryDescriptor;
019    /**
020     * This class implements a <code>SaleProcess</code> used to rent videos.
021     *  
022     */
023    public class SaleProcessRent extends SaleProcess {
024            /*
025             * Key of a Databasket-subbasket which contains the temporary removed videos of the VideoShops stock
026             */
027            private static final String SUB_SHOP_VIDEO = "videos_cs";
028            /*
029             * Key of Databasket-subbasket which contains the temporary added videos of the users-stock
030             */
031            private static final String SUB_USER_VIDEO = "video_ss";
032            /*
033             * Key of Databasket-subbasket which contains the temporary added money of the user
034             */
035            private static final String SUB_TMP_MONEY = "money_temp";
036            /*
037             * Key of Databasket-subbasket which contains the temporary removed money of the VideoShops MoneyBag
038             */
039            private static final String SUB_SHOP_MONEY = "money_shop";
040            /*
041             * The inital Gate where the offer of this automat is presented
042             */
043            private UIGate uig_offer = new UIGate(null, null);
044    
045            /*
046             * The Gate where the user has to pay for the selected videos
047             */
048            private UIGate uig_pay = new UIGate(null, null);
049    
050            /*
051             * The Gate which shows what the user has rented and how much change he/she gets
052             */
053            private UIGate uig_confirm = new UIGate(null, null);
054            /*
055             * A MoneyBag used to temporary hold the money in it, therefor not the whole money of the VideoShop is visible
056             */
057            private MoneyBagImpl mb_temp =
058                    new MoneyBagImpl("mb_user", VideoShop.getCurrency());
059    
060            /*
061             * A NumberValue used to store the sum the user has to pay
062             */
063            private NumberValue nv_sum = null;
064            /**
065             * Constructs a new SaleProcessRent
066             *  
067             */
068            public SaleProcessRent() {
069                    super("SaleProcessRent");
070            }
071            /**
072             * Implementation of the inherited abstract method.
073             * 
074             * @return a <code>Gate</code> where the user makes a selection
075             * 
076             * @see sale.SaleProcess#getInitialGate()
077             */
078            protected Gate getInitialGate() {
079                    getBasket().setCurrentSubBasket(SUB_SHOP_VIDEO);
080                    CSDBStrategy csdbs = new CSDBStrategy();
081                    csdbs.setErrorHandler(FormSheetStrategy.MSG_POPUP_ERROR_HANDLER);
082                    TwoTableFormSheet ttfs_rent =
083                            Rent.getRentFormSheet(
084                                    VideoShop.getVideoStock(),
085                                    getBasket(),
086                                    uig_offer,
087                                    null,
088                                    null,
089                                    false,
090                                    new TEDVideoStock(),
091                                    null,
092                                    csdbs);
093    
094                    ttfs_rent.addContentCreator(new FormSheetContentCreator() {
095                            protected void createFormSheetContent(FormSheet fs) {
096                                    fs.getButton(Rent.FB_RENT).setAction(new sale.Action() {
097                                            public void doAction(SaleProcess p, SalesPoint sp) {
098                                                    uig_offer.setNextTransition(getSumUpTransition());
099                                            }
100                                    });
101                                    fs.getButton(Rent.FB_CANCEL).setAction(new sale.Action() {
102                                            public void doAction(SaleProcess p, SalesPoint sp) {
103                                                    uig_offer.setNextTransition(
104                                                            GateChangeTransition.CHANGE_TO_ROLLBACK_GATE);
105                                            }
106                                    });
107    
108                            }
109                    });
110                    return uig_offer;
111            }
112            /**
113             * @return a <code>Gate</code> where the money gets inserted
114             */
115            private Gate getPayGate() {
116                    String value = VideoShop.getCurrency().toString(nv_sum);
117                    CCSStrategy ccss = new CCSStrategy();
118                    ccss.setErrorHandler(FormSheetStrategy.MSG_POPUP_ERROR_HANDLER);
119                    TwoTableFormSheet ttfs_pay =
120                            Rent.getPayFormSheet(
121                                    VideoShop.getCurrency(),
122                                    mb_temp,
123                                    getBasket(),
124                                    uig_pay,
125                                    new ComparatorCurrency(),
126                                    new ComparatorCurrency(),
127                                    false,
128                                    null,
129                                    null,
130                                    ccss,
131                                    value);
132                    ttfs_pay.addContentCreator(new FormSheetContentCreator() {
133                            protected void createFormSheetContent(final FormSheet fs) {
134                                    fs.getButton(Rent.FB_PAY).setAction(new sale.Action() {
135                                            public void doAction(SaleProcess p, SalesPoint sp) {
136                                                    uig_pay.setNextTransition(getPayConfirmTransition());
137                                            }
138                                    });
139                                    fs.getButton(Rent.FB_PAY).setEnabled(false);
140                                    setButtonStockListener(fs.getButton(Rent.FB_PAY));
141                                    fs.getButton(Rent.FB_CANCEL).setAction(new sale.Action() {
142                                            public void doAction(SaleProcess p, SalesPoint sp) {
143                                                    uig_pay.setNextTransition(getPayRollbackTransition());
144                                            }
145                                    });
146                            }
147                    });
148                    return uig_pay;
149            }
150            /**
151             * @return a <code>Gate</code> where the selected videos and the change money is shown
152             */
153            private Gate getConfirmGate() {
154                    FormSheet fs =
155                            Rent.getConfirmFormSheet(
156                                    getBasket(),
157                                    DataBasketConditionImpl.allStockItemsWithDest(
158                                            ((AutomatUser) ((SalesPoint) getContext()).getUser()).getVideoStock()),
159                                    new DefaultStoringStockDBETableEntryDescriptor(),
160                                    mb_temp,
161                                    null);
162                    fs.addContentCreator(new FormSheetContentCreator() {
163                            public void createFormSheetContent(FormSheet fs) {
164                                    fs.getButton(FormSheet.BTNID_OK).setAction(new Action() {
165                                            public void doAction(SaleProcess p, SalesPoint sp) {
166                                                    uig_confirm.setNextTransition(
167                                                            GateChangeTransition.CHANGE_TO_COMMIT_GATE);
168                                            }
169                                    });
170                            }
171                    });
172    
173                    uig_confirm.setFormSheet(fs);
174                    return uig_confirm;
175            }
176            /**
177             * @return a <code>Transition</code> that sums up the prices of the selected videos and leads to the
178             *              {@link SaleProcessRent#getPayGate()}, if no video is selected it leads to the
179             *              {@link SaleProcessRent#getInitialGate()}
180             */
181            private Transition getSumUpTransition() {
182                    return new Transition() {
183                            public Gate perform(SaleProcess p, User u) {
184                                    nv_sum = (NumberValue) getBasket().sumSubBasket(SUB_SHOP_VIDEO,
185                                                    null, new BasketEntryValue() {
186                                                            public Value getEntryValue(DataBasketEntry dbe) {
187                                                                    try {
188                                                                            CatalogItem ci = VideoShop
189                                                                                            .getVideoCatalog().get(
190                                                                                                            dbe.getSecondaryKey(),
191                                                                                                            null, false);
192                                                                            int count = ((Integer) dbe.getValue())
193                                                                                            .intValue();
194                                                                            return ((QuoteValue) ci.getValue())
195                                                                                            .getOffer().multiply(count);
196                                                                    } catch (VetoException e) {
197                                                                            e.printStackTrace();
198                                                                            getBasket().rollback();
199                                                                    }
200                                                                    return null;
201                                                            }
202                                                    }, new IntegerValue(0));
203                                    if (nv_sum.isAddZero())
204                                            return getInitialGate();
205                                    getBasket().setCurrentSubBasket(SUB_TMP_MONEY);
206                                    return getPayGate();
207                            }
208                    };
209            }
210            /**
211             * @return a <code>Transition</code> that rollback the money-transactions and leads back to the
212             *              {@link SaleProcessRent#getInitialGate()}
213             */
214            private Transition getPayRollbackTransition() {
215                    return new Transition() {
216                            public Gate perform(SaleProcess p, User u) {
217                                    getBasket().rollbackSubBasket(SUB_TMP_MONEY);
218                                    return getInitialGate();
219                            }
220                    };
221            }
222            /**
223             * @return a <code>Transition</code> that temporary adds the selected videos to the
224             *              {@link AutomatUser#getVideoStock()}, the inserted money to the {@link VideoShop#getVideoStock()}and from
225             *              there transacts the change money
226             */
227            private Transition getPayConfirmTransition() {
228                    return new Transition() {
229                            public Gate perform(SaleProcess p, User u) {
230                                    /*
231                                     * first add new rent-cassettes to the user`s stock
232                                     */
233                                    getBasket().setCurrentSubBasket(SUB_USER_VIDEO);
234                                    StoringStock ss_user =
235                                            ((AutomatUser) ((SalesPoint) p.getContext()).getUser())
236                                                    .getVideoStock();
237                                    Iterator i =
238                                            getBasket().subBasketIterator(
239                                                    SUB_SHOP_VIDEO,
240                                                    DataBasketConditionImpl.ALL_ENTRIES);
241                                    while (i.hasNext()) {
242                                            VideoCassette vc =
243                                                    new VideoCassette(
244                                                            ((CountingStockItemDBEntry) i.next())
245                                                                    .getSecondaryKey());
246                                            ss_user.add(vc, getBasket());
247                                    }
248                                    /*
249                                     * calculate what is in the temporar moneybag
250                                     */
251                                    getBasket().setCurrentSubBasket(SUB_TMP_MONEY);
252                                    NumberValue nv =
253                                            (NumberValue)
254                                                    (
255                                                            (NumberValue) mb_temp.sumStock(
256                                                                    getBasket(),
257                                                                    new CatalogItemValue(),
258                                                                    new IntegerValue(0))).subtract(
259                                                    nv_sum);
260                                    /*
261                                     * this prevents an exception that is caused by removing all items from the table
262                                     * while it is shown
263                                     */
264                                    try {
265                                            p.getContext().setFormSheet(p, null);
266                                    } catch (InterruptedException e1) {
267                                            e1.printStackTrace();
268                                    }
269                                    /*
270                                     * put the content of the temporar moneybag to the shop`s one and get the change
271                                     */
272                                    VideoShop.getMoneyBag().addStock(mb_temp, getBasket(), true);
273                                    getBasket().setCurrentSubBasket(SUB_SHOP_MONEY);
274                                    try{    
275                                            VideoShop.getMoneyBag().transferMoney(mb_temp, getBasket(), nv);                                        
276                                    }catch(NotEnoughMoneyException e){
277                                            getBasket().rollbackSubBasket(SUB_USER_VIDEO);
278                                            getBasket().rollbackSubBasket(SUB_TMP_MONEY);
279                                            getBasket().rollbackSubBasket(SUB_SHOP_MONEY);
280                                            DisplayMoneyStockError dmse = new DisplayMoneyStockError();
281                                            getBasket().setCurrentSubBasket(SUB_TMP_MONEY);
282                                            return getPayGate();
283                                    }
284                                    return getConfirmGate();
285                            }
286                    };
287            }
288            /**
289             * Adds an implementation of the <code>StockChangeListener</code> to the given button, so that this button gets
290             * enabled if there is enough money in the temporar-moneybag and otherwise it gets disabled
291             * 
292             * @param fb
293             *                  the <code>FormButton</code> the listener should en/disable
294             */
295            private void setButtonStockListener(final FormButton fb) {
296                    StockChangeAdapter sca = new StockChangeAdapter() {
297                            public void addedStockItems(StockChangeEvent e) {
298                                    if (mb_temp
299                                            .sumStock(getBasket(), new CatalogItemValue(), new IntegerValue(0))
300                                            .compareTo(nv_sum)
301                                            >= 0)
302                                            fb.setEnabled(true);
303                            }
304                            public void removedStockItems(StockChangeEvent e) {
305                                    if (mb_temp
306                                            .sumStock(getBasket(), new CatalogItemValue(), new IntegerValue(0))
307                                            .compareTo(nv_sum)
308                                            < 0)
309                                            fb.setEnabled(false);
310                            }
311                    };
312                    mb_temp.addStockChangeListener(sca);
313            }
314    }