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 }