/// <summary> /// <inheritdoc/> /// <remarks> /// This is the appropriate action for <see cref="T:VendingMachine.WaitUserSelectionState"/> i.e. when the machine is ready for the user to select an item. /// <list type="bullet"> /// <item> /// <description> /// Case 1. Checks the total machine inventory and if it is empty, it transitions back to <see cref="T:VendingMachine.SoldOutState"/>. /// Machine needs a refill. /// </description> /// </item> /// <item> /// <description> /// Case 2. Checks if there is sufficient stock of the selected item and transitions the state to <see cref="T:VendingMachine.WaitCoinState"/>. /// User is in a position to insert the coins. /// </description> /// </item> /// <item> /// <description> /// Case 3. If there is no stock left for the selected item it transitions back to <see cref="T:VendingMachine.WaitUserSelectionState"/>. /// This allows the user to reselect a different item. /// </description> /// </item> /// </list> /// </remarks> /// </summary> /// <param name="itemName">Name of the product</param> public void SelectItem(string itemName) { // Machine's inventory is Zero. Everything is sold out. Make the state transition to the sold out state if (_machine.TotalItemCount == 0) { _machine.State = _machine.GetSoldOutState; return; } // check if the machine has enough stock of the selected item if (_machine.GetItemCount(itemName) > 0) { // tell the machine to update the selected product in transaction _machine.AddItem(itemName); _machine.DisplayMessage(string.Format("You selected {0} with a value of {1} ", _machine.SelectedItem.Name, _machine.SelectedItem.Price)); // change the state to "wait for coins". _machine.State = _machine.GetWaitCoinState; // display an appropriate message to the user _machine.DisplayMessage(string.Format("Please insert coins to buy '{0}'", _machine.SelectedItem.Name)); } else { // Sufficient stock is not available. Hence, change the state to wait selection state // such that the user can select a different drink. Notify this to the user. _machine.State = _machine.GetUserSelectItemState; throw new ApplicationException(string.Format("Sorry, '{0}' is not available. Please select a different drink.", _machine.SelectedItem.Name)); } }
/// <summary> /// <inheritdoc/> /// <remarks> /// The operation checks if the customer has tendered the correct amount for the selected product. /// If the customer owes more then it propmpts to enter further amount else the state is changed to /// <see cref="T:VendingMachine.SoldState"/> /// </remarks> /// </summary> public void InsertCoins() { // if balance is negative that means machine needs to return the amount to the customer if (_machine.CustomerBalance <= 0) { _machine.State = _machine.GetSoldState; } else { _machine.DisplayMessage(string.Format("Balance amount remaining {0}", _machine.CustomerBalance)); } }
/// <summary> /// <inheritdoc/> /// <remarks> /// Dispenses the changes and sets the state back to user wait selection /// </remarks> /// </summary> public void DispenseChange() { var change = _machine.TenderChange(); _machine.DisplayMessage(string.Format("Please collect your change : \n{0}", change)); _machine.State = _machine.GetUserSelectItemState; }
/// <summary> /// <inheritdoc/> /// <remarks> /// The current state is the <see cref="T:VendingMachine.SoldState"/>. This means that the user has paid. /// The following scenarios are possible in this case :- /// <list type="bullet"> /// <item> /// <description> /// Case 1. Machine does not have exact change to tender. Hence, refund the user money and set the transition state to /// <see cref="T:VendingMachine.WaitUserSelectionState"/> /// </description> /// </item> /// <item> /// <description> /// Case 2. Everything is fine. Ask the machine to release the drink. /// </description> /// </item> /// <item> /// <description> /// Case 3. After releasing the item, check if the machine owes any amount to the user. If yes, then, /// the state is changed to <see cref="T:VendingMachine.DispenseChangeState"/> /// </description> /// </item> /// <item> /// <description> /// Case 4. After releasing the item, checks if the machine has enough inventory and it owes nothing to the user. /// Transitions the state to <see cref="T:VendingMachine.WaitUserSelectionState"/> /// </description> /// </item> /// <item> /// <description> /// Case 5. After releasing the item, check the total inventory count. /// If its zero, then transition the state to <see cref="T:VendingMachine.SoldOutState"/> /// </description> /// </item> /// </list> /// </remarks> /// </summary> public void DispenseItem() { // Machine does not have exact change to tender, hence do not dispense the item // Change back the state to user selection state, refund the money and show an appropriate message to the user. if (String.IsNullOrEmpty(_machine.TenderChange())) { var refund = _machine.RefundMoney(); _machine.State = _machine.GetUserSelectItemState; throw new ApplicationException(string.Format("Machine does not have sufficient change. Please tender exact change. Please collect your inserted amount{0}", refund)); } _machine.ReleaseItem(); _machine.DisplayMessage("Item has been dispensed. Please do not forget to collect it."); // machine has to refund if (_machine.CustomerBalance < 0) { _machine.State = _machine.GetDispenseChangeState; } // Machine has enough products and has nothing to refund back to the user if (_machine.TotalItemCount > 0 && _machine.CustomerBalance == 0) { _machine.State = _machine.GetUserSelectItemState; } // Machine is empty. Everything is sold out. Hence, change the state to SoldOut if (_machine.TotalItemCount == 0) { _machine.State = _machine.GetSoldOutState; throw new ApplicationException("Sorry, the machine is out of stock."); } }
/// <summary> /// <inheritdoc /> /// This can only happen when total item count is zero and machine is in sold out state. /// User tries to select an item /// </summary> public void SelectItem(string itemName) { _machine.DisplayMessage("Products are not available. Machine needs a refill."); }