001/*
002 *   Copyright 2024 Vonage
003 *
004 *   Licensed under the Apache License, Version 2.0 (the "License");
005 *   you may not use this file except in compliance with the License.
006 *   You may obtain a copy of the License at
007 *
008 *        http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *   Unless required by applicable law or agreed to in writing, software
011 *   distributed under the License is distributed on an "AS IS" BASIS,
012 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *   See the License for the specific language governing permissions and
014 *   limitations under the License.
015 */
016package com.vonage.client.voice.ncco;
017
018import com.fasterxml.jackson.annotation.JsonProperty;
019import com.vonage.client.JsonableBaseObject;
020import java.util.*;
021
022/**
023 * An NCCO input action which allows for the collection of digits and automatic speech recognition from a person.
024 */
025public class InputAction extends JsonableBaseObject implements Action {
026    private static final String ACTION = "input";
027
028    @JsonProperty(required = true)
029    private Collection<String> type;
030    private DtmfSettings dtmf;
031    private Collection<String> eventUrl;
032    private SpeechSettings speech;
033    private EventMethod eventMethod;
034    private InputMode mode;
035
036    InputAction() {}
037
038    private InputAction(Builder builder) {
039        eventUrl = builder.eventUrl;
040        eventMethod = builder.eventMethod;
041        speech = builder.speech;
042        mode = builder.mode;
043        if ((type = builder.type).isEmpty()) {
044            throw new IllegalStateException("At least one input type must be specified.");
045        }
046        if ((dtmf = builder.dtmf) != null && mode == InputMode.ASYNCHRONOUS) {
047            throw new IllegalStateException("DTMF settings cannot be used with asynchronous mode.");
048        }
049    }
050
051    @Override
052    public String getAction() {
053        return ACTION;
054    }
055
056    @JsonProperty("type")
057    public Collection<String> getType() {
058        return type;
059    }
060
061    @JsonProperty("dtmf")
062    public DtmfSettings getDtmf() {
063        return dtmf;
064    }
065
066    @JsonProperty("eventUrl")
067    public Collection<String> getEventUrl() {
068        return eventUrl;
069    }
070
071    @JsonProperty("eventMethod")
072    public EventMethod getEventMethod() {
073        return eventMethod;
074    }
075
076    @JsonProperty("speech")
077    public SpeechSettings getSpeech() {
078        return speech;
079    }
080
081    /**
082     * How the input should be processed. If not set, the default is {@linkplain InputMode#SYNCHRONOUS}.
083     *
084     * @return The mode as an enum, or {@code null} if unspecified.
085     * @since 8.12.0
086     */
087    @JsonProperty("mode")
088    public InputMode getMode() {
089        return mode;
090    }
091
092    /**
093     * Entrypoint for constructing an instance of this class.
094     *
095     * @return A new Builder.
096     */
097    public static Builder builder() {
098        return new Builder();
099    }
100
101    /**
102     * Builder for specifying the properties of an InputAction.
103     */
104    public static class Builder {
105        private final Collection<String> type = new LinkedHashSet<>(2, 1f);
106        private DtmfSettings dtmf;
107        private Collection<String> eventUrl;
108        private EventMethod eventMethod;
109        private SpeechSettings speech;
110        private InputMode mode;
111
112        private Builder() {}
113
114        /**
115         * Enables DTMF with the default settings.
116         *
117         * @return This builder to keep building the input action.
118         * @since 8.12.0
119         */
120        public Builder dtmf() {
121            dtmf(null);
122            type.add("dtmf");
123            return this;
124        }
125
126        /**
127         * Enable DTMF input with the provided settings. Note that if you override any of
128         * the defaults, you cannot set {@linkplain #mode(InputMode)} to {@linkplain InputMode#ASYNCHRONOUS}.
129         *
130         * @param dtmf The DTMF settings object.
131         * @return This builder to keep building the input action.
132         * @since 6.0.0
133         */
134        public Builder dtmf(DtmfSettings dtmf) {
135            if ((this.dtmf = dtmf) != null) {
136                type.add("dtmf");
137            }
138            else {
139                type.remove("dtmf");
140            }
141            return this;
142        }
143
144        /**
145         * Automatic Speech Recognition (ASR) settings to enable speech input.
146         * Required if {@linkplain #dtmf(DtmfSettings)} is not provided.
147         *
148         * @param speech The speech settings object.
149         * @return This builder to keep building the input action.
150         * @since 6.0.0
151         */
152        public Builder speech(SpeechSettings speech) {
153            if ((this.speech = speech) != null) {
154                type.add("speech");
155            }
156            else {
157                type.remove("speech");
158            }
159            return this;
160        }
161
162        /**
163         * Vonage sends the digits pressed by the callee to this URL after timeOut pause inactivity or when
164         * {@code #} is pressed.
165         *
166         * @param eventUrl The URL wrapped in a singleton collection to send the event metadata to.
167         *
168         * @return This builder to keep building the input action.
169         * @deprecated This will be removed in a future release. Use {@link #eventUrl(String)} instead.
170         */
171        @Deprecated
172        public Builder eventUrl(Collection<String> eventUrl) {
173            this.eventUrl = eventUrl;
174            return this;
175        }
176
177        /**
178         * Vonage sends the digits pressed by the callee to this URL after timeOut pause inactivity or when
179         * {@code #} is pressed.
180         *
181         * @param eventUrl The URL to send the event metadata to.
182         *
183         * @return This builder to keep building the input action.
184         * @deprecated This will be removed in a future release. Use {@link #eventUrl(String)} instead.
185         */
186        @Deprecated
187        public Builder eventUrl(String... eventUrl) {
188            return eventUrl(Arrays.asList(eventUrl));
189        }
190
191        /**
192         * Vonage sends the digits pressed by the callee to this URL after timeOut pause inactivity or when
193         * {@code #} is pressed.
194         *
195         * @param eventUrl The URL to send the event metadata to.
196         *
197         * @return This builder to keep building the input action.
198         *
199         * @since 8.12.0
200         */
201        public Builder eventUrl(String eventUrl) {
202            return eventUrl(Collections.singletonList(eventUrl));
203        }
204
205        /**
206         * The HTTP method used to send event information to event_url The default value is POST.
207         *
208         * @param eventMethod The HTTP method to use for the event as an enum.
209         *
210         * @return This builder to keep building the input action.
211         */
212        public Builder eventMethod(EventMethod eventMethod) {
213            this.eventMethod = eventMethod;
214            return this;
215        }
216
217        /**
218         * How the input should be processed. If not set, the default is {@linkplain InputMode#SYNCHRONOUS}.
219         * If set to {@linkplain InputMode#ASYNCHRONOUS}, use {@link #dtmf()} instead of {@link #dtmf(DtmfSettings)}.
220         *
221         * @param mode The DTMF processing mode as an enum.
222         * @return This builder to keep building the input action.
223         * @since 8.12.0
224         */
225        public Builder mode(InputMode mode) {
226            this.mode = mode;
227            return this;
228        }
229
230        /**
231         * Sets the acceptable input types. From v8.12.0 onwards, you should not call this method manually;
232         * instead, use {@link #dtmf()} and / or {@link #speech(SpeechSettings)}. This method will be removed
233         * in a future release.
234         *
235         * @param type Acceptable input types as a collection. Valid values are ["dtmf"] for DTMF input only,
236         *             ["speech"] for ASR only, or ["dtmf", "speech"] for both.
237         *
238         * @return This builder to keep building the input action.
239         *
240         * @deprecated Use {@link #dtmf(DtmfSettings)} and {@link #speech(SpeechSettings)} instead.
241         * The type will be set automatically based on the provided settings.
242         */
243        @Deprecated
244        public Builder type(Collection<String> type) {
245            this.type.clear();
246            if (type != null) {
247                this.type.addAll(type);
248            }
249            return this;
250        }
251
252        /**
253         * Builds the InputAction.
254         *
255         * @return A new InputAction object from the stored builder options.
256         */
257        public InputAction build() {
258            return new InputAction(this);
259        }
260    }
261}