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 }