/* * Copyright (C) 2017 by Fonoster Inc (http://fonoster.com) * http://astivetoolkit.org * * This file is part of Astive Toolkit(ATK) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.astivetoolkit.menu; import java.util.ArrayList; import org.astivetoolkit.menu.action.Action; import org.astivetoolkit.menu.event.FailEvent; import org.astivetoolkit.menu.event.FailureListener; import org.astivetoolkit.menu.event.InterDigitsTimeoutEvent; import org.astivetoolkit.menu.event.InterDigitsTimeoutListener; import org.astivetoolkit.menu.event.MaxFailureEvent; import org.astivetoolkit.menu.event.MaxFailureListener; import org.astivetoolkit.menu.event.MaxTimeoutEvent; import org.astivetoolkit.menu.event.MaxTimeoutListener; import org.astivetoolkit.menu.event.PositionChangeEvent; import org.astivetoolkit.menu.event.PositionChangeListener; import org.astivetoolkit.menu.event.TimeoutEvent; import org.astivetoolkit.menu.event.TimeoutListener; /** * * @since 1.0 * @see MenuItem */ public class Menu extends MenuItem { private ArrayList<MenuItem> childs = new ArrayList<MenuItem>(); private ArrayList<FailureListener> failListenerList = new ArrayList<FailureListener>(); private ArrayList<InterDigitsTimeoutListener> interDigitsTimeoutListenerList = new ArrayList<InterDigitsTimeoutListener>(); private ArrayList<MaxFailureListener> maxFailureListenerList = new ArrayList<MaxFailureListener>(); private ArrayList<MaxTimeoutListener> maxTimeoutListenerList = new ArrayList<MaxTimeoutListener>(); private ArrayList<PositionChangeListener> positionChangeListenerList = new ArrayList<PositionChangeListener>(); private ArrayList<TimeoutListener> timeoutListenerList = new ArrayList<TimeoutListener>(); private String exitFile; private String greetingsFile; private String invalidDigitsFile; private boolean canInterruptGreetings = true; private boolean greetingsPlayed = false; private boolean playGreetingsAllways = false; private boolean sortChildsByDigits = true; private int failuresCount; private int interDigitsTimeout = 500; private int lastDigitsTimeout = 1500; private int maxDigits = 1; private int maxFailures = 3; private int maxTimeouts = 3; private int timeoutCount; /** * {@inheritDoc} */ public Menu() { super(); } /** * {@inheritDoc} */ public Menu(final String digits, final String file) { super(digits, file); } /** * {@inheritDoc} */ public Menu(final String digits, final String file, final Action action) { super(digits, file, action); } /** * {@inheritDoc} */ public Menu(final String digits, final String file, final Action action, final int priority) { super(digits, file, action, priority); } /** * Registers a new menu item. * * @param item the new menu item. */ public void addChild(MenuItem item) { item.parent = this; childs.add(item); } /** * Registers the specified <code>fail listener</code> to receive fail events * from this <code>menu</code>. * * @param listener the object that receives a notification when an event of * the specified type occurs. */ public void addFailListener(FailureListener listener) { failListenerList.add(listener); } /** * Registers the specified <code>integer digit timeout listener</code> to * receive inter digits events from this menu. * * @param listener the object that receives a notification when an event of * the specified type occurs. */ public void addInterDigitsTimeoutListener(InterDigitsTimeoutListener listener) { interDigitsTimeoutListenerList.add(listener); } /** * Registers the specified <code>max failure listener</code> to receive max * failure events from this menu. * * @param listener the object that receives a notification when an event of * the specified type occurs. */ public void addMaxFailureListener(MaxFailureListener listener) { maxFailureListenerList.add(listener); } /** * Registers the specified <code>max timeout listener</code> to receive max * timeout events from this menu. * * @param listener the object that receives a notification when an event of * the specified type occurs. */ public void addMaxTimeoutListener(MaxTimeoutListener listener) { maxTimeoutListenerList.add(listener); } /** * Registers the specified <code>position change listener</code> to receive * position change events from this menu. * * @param listener the object that receives a notification when an event of * the specified type occurs. */ public void addPositionChangeListener(PositionChangeListener listener) { positionChangeListenerList.add(listener); } /** * Registers the specified <code>timeout listener</code> to receive position * timeout events from this menu. * * @param listener the object that receives a notification when an event of * the specified type occurs. */ public void addTimeoutListener(TimeoutListener listener) { timeoutListenerList.add(listener); } /** * Returns an array of all the child's registered on this menu. * * @return all of this menu child's or an empty array if no voice * compositions are currently registered. */ public ArrayList<MenuItem> getChilds() { return childs; } /** * Returns the goodbye file. * * @return the <code>file</code> to be stream, without extension. */ public String getExitFile() { return exitFile; } /** * Returns the greetings file. * * @return the <code>file</code> to be streamed, without extension. */ public String getGreetingsFile() { return greetingsFile; } /** * Returns the maximum time in between digits. * * @return the maximum time allow in between digits. */ public int getInterDigitsTimeout() { return interDigitsTimeout; } /** * Returns the <code>invalid digits</code> file. * * @return the <code>file</code> to be streamed, without extension. */ public String getInvalidDigitsFile() { return invalidDigitsFile; } /** * Returns the maximum timeout for the last menu item in the menu. * * @return the maximum time that a <code>Subject</code> have, to press the * digits before the file for the last menu item finish. */ public int getLastDigitsTimeout() { return lastDigitsTimeout; } /** * Returns the maximum digits allow for menu items in this menu. * * @return maximum digits for menu items. */ public int getMaxDigits() { return maxDigits; } /** * Returns the maximum failure that a <code>Subject</code> is allow to. * * @return the maximum attempts that a <code>Subject</code>(user) is allow * to introduce invalid digits. */ public int getMaxFailures() { return maxFailures; } /** * Returns whether or not the greetings can be interrupted by user * iteration. * * @return true if the greetings can be skipped. */ public boolean isCanInterruptGreetings() { return canInterruptGreetings; } /** * Whether or not the greetings has been played. * * @return true if greetings was played already. */ public boolean isGreetingsPlayed() { return greetingsPlayed; } /** * Whether or not greetings will be played every cycle of the menu. * * @return true if greetings will be played every time. */ public boolean isPlayGreetingsAllways() { return playGreetingsAllways; } /** * Indicates if childs will be sort using the digits as criteria. * * @return true if menu items will be sorted. */ public boolean isSortChildsByDigits() { return sortChildsByDigits; } /** * Removes the specified <code>inter digits listener</code> so it no longer * receives inter digits events from this menu. * * @param listener the object that receives a notification when an event of * the specified type occurs. */ public void removeInterDigitsTimeoutListener(InterDigitsTimeoutListener listener) { interDigitsTimeoutListenerList.remove(listener); } /** * Removes the specified <code>max failure listener</code> so it no longer * receives max failure events from this menu. * * @param listener the object that receives a notification when an event of * the specified type occurs. */ public void removeMaxFailureListener(MaxFailureListener listener) { maxFailureListenerList.remove(listener); } /** * Removes the specified <code>max timeout listener</code> so it no longer * receives max timeout events from this menu. * * @param listener the object that receives a notification when an event of * the specified type occurs. */ public void removeMaxTimeoutListener(MaxTimeoutListener listener) { maxTimeoutListenerList.remove(listener); } /** * Removes the specified <code>max failure listener</code> so it no longer * receives max failure events from this menu. * * @param listener the object that receives a notification when an event of * the specified type occurs. */ public void removePositionChangeListener(PositionChangeListener listener) { positionChangeListenerList.remove(listener); } /** * Removes the specified <code>timeout listener</code> so it no longer * receives timeout events from this menu. * * @param listener the object that receives a notification when an event of * the specified type occurs. */ public void removeTimeoutListener(TimeoutListener listener) { timeoutListenerList.remove(listener); } /** * Removes the specified <code>failure listener</code> so it no longer * receives failure events from this menu. * * @param listener the object that receives a notification when an event of * the specified type occurs. */ public void removeFailureListener(FailureListener listener) { failListenerList.remove(listener); } /** * Restarts the the failures count, to prevent {@link MaxFailureEvent}. */ public void resetFailuresCount() { setFailuresCount(0); } /** * Restarts the timeout count, to prevent {@link MaxTimeoutEvent}. */ public void resetTimeoutCount() { setTimeoutCount(0); } /** * Establish whether or not the greetings can be interrupted by user * iteration. * * @param canInterruptGreetings 'true' will allow users to skip the * greetings. */ public void setCanInterruptGreetings(boolean canInterruptGreetings) { this.canInterruptGreetings = canInterruptGreetings; } /** * Registers an array of menu items. * * @param childs an array of memu items. */ public void setChilds(ArrayList<MenuItem> childs) { this.childs = childs; } /** * Sets the goodbye sound. * * @param exitFile the file extension must not be included in the filename. */ public void setExitFile(String exitFile) { this.exitFile = exitFile; } /** * Sets the greetings sound. * * @param greetingsFile the file extension must not be included in the * filename. */ public void setGreetingsFile(String greetingsFile) { this.greetingsFile = greetingsFile; } /** * Sets the maximum time allow in between digits. * * @param interDigitsTimeout the maximum time allow in between digits. */ public void setInterDigitsTimeout(int interDigitsTimeout) { this.interDigitsTimeout = interDigitsTimeout; } /** * Sets the file to stream if invalid digits are introduce by a * <code>Subject</code>. * * @param greetingsFile the file extension must not be included in the * filename. */ public void setInvalidDigitFile(String invalidDigitFile) { this.invalidDigitsFile = invalidDigitFile; } /** * Sets maximum time waiting for user interaction. * * @param lastDigitsTimeout the maximum time waiting for user interaction * after the audio of last menu item finished. */ public void setLastDigitsTimeout(int lastDigitsTimeout) { this.lastDigitsTimeout = lastDigitsTimeout; } /** * Maximum digits length for menu items. * * @param maxDigits maximum length. */ public void setMaxDigits(int maxDigits) { this.maxDigits = maxDigits; } /** * Defines the maximum amount failures that a <code>Subject</code> is allow * to. * * @param maxFailures the maximum amount of attempts to select invalid * options. */ public void setMaxFailures(int maxFailures) { this.maxFailures = maxFailures; } /** * Defines the maximum amount of timeouts that <code>Subject</code> is allow * to. * * @param maxFailures the maximum amount of time that user is allow to skip * menu item selection. */ public void setMaxTimeouts(int maxTimeouts) { this.maxTimeouts = maxTimeouts; } /** * Whether or not greetings will be played every menu cycle. * * @param playGreetingsAllways by default is set to false. */ public void setPlayGreetingsAllways(boolean playGreetingsAllways) { this.playGreetingsAllways = playGreetingsAllways; } /** * Whether or not will sort menu items by digits. * * @param sortChildsByDigits is true by default. */ public void setSortChildsByDigits(boolean sortChildsByDigits) { this.sortChildsByDigits = sortChildsByDigits; } /** * Returns the maximum timeout. * * @return the maximum consecutive timeouts that a <code>Subject</code> is * allow to. */ public int getMaxTimeouts() { return maxTimeouts; } /** * Returns the current timeout count. * * @return the number of consecutive timeouts. */ protected int getTimeoutCount() { return timeoutCount; } /** * Use by {@link MenuNavigator} to increment the consecutive timeout count. */ protected void incremenTimeoutCount() { setTimeoutCount(getTimeoutCount() + 1); } /** * Use by {@link MenuNavigator} to increment the consecutive failures count. */ protected void incrementFailuresCount() { setFailuresCount(getFailuresCount() + 1); } private void setTimeoutCount(int timeoutCount) { this.timeoutCount = timeoutCount; } /** * Checks for duplicate digits in menu items. * * @param digits if there is any digit duplicated, the exception * {@link DuplicateDigitException} is thrown. */ protected void checkDigits(String digits) { for (MenuItem m : getChilds()) { if (m.getDigits().equals(digits)) { throw new DuplicatedDigitException(); } } } /** * Notifies <code>failure listeners</code> about a <code>failure event</code>. * * @param evt the event. */ protected void fireFailureListener_failurePerform(FailEvent evt) { for (FailureListener listener : failListenerList) { listener.failurePerform(evt); } } /** * Notifies <code>inter digits timeout listeners</code> about an * <code>inter digits timeout<code>. * event. * * @param evt the event. */ protected void fireInterDigitsTimeoutListener_timeoutPerform(InterDigitsTimeoutEvent evt) { for (InterDigitsTimeoutListener listener : interDigitsTimeoutListenerList) { listener.timeoutPerform(evt); } } /** * Notifies <code>inter digits timeout listeners</code> about an * <code>inter digits timeout event</code>. * * @param evt the event. */ protected void fireMaxFailureEvent_maxFailurePerform(MaxFailureEvent evt) { for (MaxFailureListener listener : maxFailureListenerList) { listener.maxFailurePerform(evt); } } /** * Notifies <code>max timeout listeners</code> about a * <code>max timeout event</code>. * * @param evt the event. */ protected void fireMaxTimeoutEvent_maxTimeoutPerform(MaxTimeoutEvent evt) { for (MaxTimeoutListener listener : maxTimeoutListenerList) { listener.maxTimeoutPerform(evt); } } /** * Notifies <code>position change listeners</code> about a * <code>position change event</code>. * * @param evt the event. */ protected void firePositionChangeEvent_positionChange(PositionChangeEvent evt) { for (PositionChangeListener listener : positionChangeListenerList) { listener.positionChange(evt); } } /** * Notifies <code>timeout listeners</code> about a * <code>timeout event</code>. * * @param evt the event. */ protected void fireTimeoutListener_timeoutPerform(TimeoutEvent evt) { for (TimeoutListener listener : timeoutListenerList) { listener.timeoutPerform(evt); } } /** * Returns the current failures count. * * @return use by {@link MenuNavigator} to perform {@link MaxFailuresEvent}. */ protected int getFailuresCount() { return failuresCount; } private void setFailuresCount(int failuresCount) { this.failuresCount = failuresCount; } /** * Sets the <code>greetings played</code>. * * @param greetingsPlayed use by {@link MenuNavigator} to avoid greetings * repetition unless is the desire behavior. */ protected void setGreetingsPlayed(boolean greetingsPlayed) { this.greetingsPlayed = greetingsPlayed; } }