001package Torello.Browser;
002
003import java.util.*;
004import javax.json.*;
005import javax.json.stream.*;
006import java.io.*;
007
008import java.lang.reflect.Method;
009import java.lang.reflect.Parameter;
010import java.util.function.Function;
011
012import Torello.Java.Additional.*;
013import Torello.Java.JSON.*;
014
015import static Torello.Java.JSON.JFlag.*;
016
017import Torello.Java.StrCmpr;
018import Torello.JavaDoc.StaticFunctional;
019import Torello.JavaDoc.JDHeaderBackgroundImg;
020import Torello.JavaDoc.Excuse;
021
022/**
023 * <SPAN CLASS=COPIEDJDK><B>A domain for interacting with Cast, Presentation API, and Remote Playback API
024 * functionalities.</B></SPAN>
025 * 
026 * <EMBED CLASS='external-html' DATA-FILE-ID=CODE_GEN_NOTE>
027 */
028@StaticFunctional(Excused={"counter"}, Excuses={Excuse.CONFIGURATION})
029@JDHeaderBackgroundImg(EmbedTagFileID="WOOD_PLANK_NOTE")
030public class Cast
031{
032    // ********************************************************************************************
033    // ********************************************************************************************
034    // Class Header Stuff
035    // ********************************************************************************************
036    // ********************************************************************************************
037
038
039    // No Pubic Constructors
040    private Cast () { }
041
042    // These two Vector's are used by all the "Methods" exported by this class.  java.lang.reflect
043    // is used to generate the JSON String's.  It saves thousands of lines of Auto-Generated Code.
044    private static final Map<String, Vector<String>>    parameterNames = new HashMap<>();
045    private static final Map<String, Vector<Class<?>>>  parameterTypes = new HashMap<>();
046
047    // Some Methods do not take any parameters - for instance all the "enable()" and "disable()"
048    // I simply could not get ride of RAW-TYPES and UNCHECKED warnings... so there are now,
049    // offically, two empty-vectors.  One for String's, and the other for Classes.
050
051    private static final Vector<String>     EMPTY_VEC_STR = new Vector<>();
052    private static final Vector<Class<?>>   EMPTY_VEC_CLASS = new Vector<>();
053
054    static
055    {
056        for (Method m : Cast.class.getMethods())
057        {
058            // This doesn't work!  The parameter names are all "arg0" ... "argN"
059            // It works for java.lang.reflect.Field, BUT NOT java.lang.reflect.Parameter!
060            //
061            // Vector<String> parameterNamesList = new Vector<>(); -- NOPE!
062
063            Vector<Class<?>> parameterTypesList = new Vector<>();
064        
065            for (Parameter p : m.getParameters()) parameterTypesList.add(p.getType());
066
067            parameterTypes.put(
068                m.getName(),
069                (parameterTypesList.size() > 0) ? parameterTypesList : EMPTY_VEC_CLASS
070            );
071        }
072    }
073
074    static
075    {
076        Vector<String> v = null;
077
078        v = new Vector<String>(1);
079        parameterNames.put("enable", v);
080        Collections.addAll(v, new String[]
081        { "presentationUrl", });
082
083        parameterNames.put("disable", EMPTY_VEC_STR);
084
085        v = new Vector<String>(1);
086        parameterNames.put("setSinkToUse", v);
087        Collections.addAll(v, new String[]
088        { "sinkName", });
089
090        v = new Vector<String>(1);
091        parameterNames.put("startTabMirroring", v);
092        Collections.addAll(v, new String[]
093        { "sinkName", });
094
095        v = new Vector<String>(1);
096        parameterNames.put("stopCasting", v);
097        Collections.addAll(v, new String[]
098        { "sinkName", });
099    }
100
101
102    // ********************************************************************************************
103    // ********************************************************************************************
104    // Types - Static Inner Classes
105    // ********************************************************************************************
106    // ********************************************************************************************
107
108    /** <CODE>[No Description Provided by Google]</CODE> */
109    public static class Sink
110        extends BaseType
111        implements java.io.Serializable
112    {
113        /** For Object Serialization.  java.io.Serializable */
114        protected static final long serialVersionUID = 1;
115        
116        public boolean[] optionals()
117        { return new boolean[] { false, false, true, }; }
118        
119        /** <CODE>[No Description Provided by Google]</CODE> */
120        public final String name;
121        
122        /** <CODE>[No Description Provided by Google]</CODE> */
123        public final String id;
124        
125        /**
126         * Text describing the current session. Present only if there is an active
127         * session on the sink.
128         * <BR />
129         * <BR /><B>OPTIONAL</B>
130         */
131        public final String session;
132        
133        /**
134         * Constructor
135         *
136         * @param name -
137         * 
138         * @param id -
139         * 
140         * @param session 
141         * Text describing the current session. Present only if there is an active
142         * session on the sink.
143         * <BR /><B>OPTIONAL</B>
144         */
145        public Sink(String name, String id, String session)
146        {
147            // Exception-Check(s) to ensure that if any parameters which are not declared as
148            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
149            
150            if (name == null) THROWS.throwNPE("name");
151            if (id == null)   THROWS.throwNPE("id");
152            
153            this.name     = name;
154            this.id       = id;
155            this.session  = session;
156        }
157        
158        /**
159         * JSON Object Constructor
160         * @param jo A Json-Object having data about an instance of {@code 'Sink'}.
161         */
162        public Sink (JsonObject jo)
163        {
164            this.name     = ReadJSON.getString(jo, "name", false, true);
165            this.id       = ReadJSON.getString(jo, "id", false, true);
166            this.session  = ReadJSON.getString(jo, "session", true, false);
167        }
168        
169        
170        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
171        public boolean equals(Object other)
172        {
173            if (this == other)                       return true;
174            if (other == null)                       return false;
175            if (other.getClass() != this.getClass()) return false;
176        
177            Sink o = (Sink) other;
178        
179            return
180                    Objects.equals(this.name, o.name)
181                &&  Objects.equals(this.id, o.id)
182                &&  Objects.equals(this.session, o.session);
183        }
184        
185        /** Generates a Hash-Code for {@code 'this'} instance */
186        public int hashCode()
187        {
188            return
189                    Objects.hashCode(this.name)
190                +   Objects.hashCode(this.id)
191                +   Objects.hashCode(this.session);
192        }
193    }
194    
195    /**
196     * This is fired whenever the list of available sinks changes. A sink is a
197     * device or a software surface that you can cast to.
198     */
199    public static class sinksUpdated
200        extends BrowserEvent
201        implements java.io.Serializable
202    {
203        /** For Object Serialization.  java.io.Serializable */
204        protected static final long serialVersionUID = 1;
205        
206        public boolean[] optionals()
207        { return new boolean[] { false, }; }
208        
209        /** <CODE>[No Description Provided by Google]</CODE> */
210        public final Cast.Sink[] sinks;
211        
212        /**
213         * Constructor
214         *
215         * @param sinks -
216         */
217        public sinksUpdated(Cast.Sink[] sinks)
218        {
219            super("Cast", "sinksUpdated", 1);
220            
221            // Exception-Check(s) to ensure that if any parameters which are not declared as
222            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
223            
224            if (sinks == null) THROWS.throwNPE("sinks");
225            
226            this.sinks  = sinks;
227        }
228        
229        /**
230         * JSON Object Constructor
231         * @param jo A Json-Object having data about an instance of {@code 'sinksUpdated'}.
232         */
233        public sinksUpdated (JsonObject jo)
234        {
235            super("Cast", "sinksUpdated", 1);
236        
237            this.sinks = (jo.getJsonArray("sinks") == null)
238                ? null
239                : RJArrIntoStream.objArr(jo.getJsonArray("sinks"), null, 0, Cast.Sink.class).toArray(Cast.Sink[]::new);
240        
241        }
242        
243        
244        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
245        public boolean equals(Object other)
246        {
247            if (this == other)                       return true;
248            if (other == null)                       return false;
249            if (other.getClass() != this.getClass()) return false;
250        
251            sinksUpdated o = (sinksUpdated) other;
252        
253            return
254                    Arrays.deepEquals(this.sinks, o.sinks);
255        }
256        
257        /** Generates a Hash-Code for {@code 'this'} instance */
258        public int hashCode()
259        {
260            return
261                    Arrays.deepHashCode(this.sinks);
262        }
263    }
264    
265    /**
266     * This is fired whenever the outstanding issue/error message changes.
267     * |issueMessage| is empty if there is no issue.
268     */
269    public static class issueUpdated
270        extends BrowserEvent
271        implements java.io.Serializable
272    {
273        /** For Object Serialization.  java.io.Serializable */
274        protected static final long serialVersionUID = 1;
275        
276        public boolean[] optionals()
277        { return new boolean[] { false, }; }
278        
279        /** <CODE>[No Description Provided by Google]</CODE> */
280        public final String issueMessage;
281        
282        /**
283         * Constructor
284         *
285         * @param issueMessage -
286         */
287        public issueUpdated(String issueMessage)
288        {
289            super("Cast", "issueUpdated", 1);
290            
291            // Exception-Check(s) to ensure that if any parameters which are not declared as
292            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
293            
294            if (issueMessage == null) THROWS.throwNPE("issueMessage");
295            
296            this.issueMessage  = issueMessage;
297        }
298        
299        /**
300         * JSON Object Constructor
301         * @param jo A Json-Object having data about an instance of {@code 'issueUpdated'}.
302         */
303        public issueUpdated (JsonObject jo)
304        {
305            super("Cast", "issueUpdated", 1);
306        
307            this.issueMessage  = ReadJSON.getString(jo, "issueMessage", false, true);
308        }
309        
310        
311        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
312        public boolean equals(Object other)
313        {
314            if (this == other)                       return true;
315            if (other == null)                       return false;
316            if (other.getClass() != this.getClass()) return false;
317        
318            issueUpdated o = (issueUpdated) other;
319        
320            return
321                    Objects.equals(this.issueMessage, o.issueMessage);
322        }
323        
324        /** Generates a Hash-Code for {@code 'this'} instance */
325        public int hashCode()
326        {
327            return
328                    Objects.hashCode(this.issueMessage);
329        }
330    }
331    
332    
333    // Counter for keeping the WebSocket Request ID's distinct.
334    private static int counter = 1;
335    
336    /**
337     * Starts observing for sinks that can be used for tab mirroring, and if set,
338     * sinks compatible with |presentationUrl| as well. When sinks are found, a
339     * |sinksUpdated| event is fired.
340     * Also starts observing for issue messages. When an issue is added or removed,
341     * an |issueUpdated| event is fired.
342     * 
343     * @param presentationUrl -
344     * <BR /><B>OPTIONAL</B>
345     * 
346     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
347     * {@link Ret0}&gt;</CODE>
348     *
349     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
350     * browser receives the invocation-request.
351     *
352     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
353     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
354     * {@code >} to ensure the Browser Function has run to completion.
355     */
356    public static Script<String, JsonObject, Ret0> enable(String presentationUrl)
357    {
358        final int       webSocketID = 14000000 + counter++;
359        final boolean[] optionals   = { true, };
360        
361        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
362        String requestJSON = WriteJSON.get(
363            parameterTypes.get("enable"),
364            parameterNames.get("enable"),
365            optionals, webSocketID,
366            "Cast.enable",
367            presentationUrl
368        );
369        
370        // This Remote Command does not have a Return-Value.
371        return new Script<>
372            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
373    }
374    
375    /**
376     * Stops observing for sinks and issues.
377     * 
378     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
379     * {@link Ret0}&gt;</CODE>
380     *
381     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
382     * browser receives the invocation-request.
383     *
384     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
385     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
386     * {@code >} to ensure the Browser Function has run to completion.
387     */
388    public static Script<String, JsonObject, Ret0> disable()
389    {
390        final int          webSocketID = 14001000 + counter++;
391        final boolean[]    optionals   = new boolean[0];
392        
393        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
394        String requestJSON = WriteJSON.get(
395            parameterTypes.get("disable"),
396            parameterNames.get("disable"),
397            optionals, webSocketID,
398            "Cast.disable"
399        );
400        
401        // This Remote Command does not have a Return-Value.
402        return new Script<>
403            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
404    }
405    
406    /**
407     * Sets a sink to be used when the web page requests the browser to choose a
408     * sink via Presentation API, Remote Playback API, or Cast SDK.
409     * 
410     * @param sinkName -
411     * 
412     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
413     * {@link Ret0}&gt;</CODE>
414     *
415     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
416     * browser receives the invocation-request.
417     *
418     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
419     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
420     * {@code >} to ensure the Browser Function has run to completion.
421     */
422    public static Script<String, JsonObject, Ret0> setSinkToUse(String sinkName)
423    {
424        // Exception-Check(s) to ensure that if any parameters which are not declared as
425        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
426        
427        if (sinkName == null) THROWS.throwNPE("sinkName");
428        
429        final int       webSocketID = 14002000 + counter++;
430        final boolean[] optionals   = { false, };
431        
432        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
433        String requestJSON = WriteJSON.get(
434            parameterTypes.get("setSinkToUse"),
435            parameterNames.get("setSinkToUse"),
436            optionals, webSocketID,
437            "Cast.setSinkToUse",
438            sinkName
439        );
440        
441        // This Remote Command does not have a Return-Value.
442        return new Script<>
443            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
444    }
445    
446    /**
447     * Starts mirroring the tab to the sink.
448     * 
449     * @param sinkName -
450     * 
451     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
452     * {@link Ret0}&gt;</CODE>
453     *
454     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
455     * browser receives the invocation-request.
456     *
457     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
458     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
459     * {@code >} to ensure the Browser Function has run to completion.
460     */
461    public static Script<String, JsonObject, Ret0> startTabMirroring(String sinkName)
462    {
463        // Exception-Check(s) to ensure that if any parameters which are not declared as
464        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
465        
466        if (sinkName == null) THROWS.throwNPE("sinkName");
467        
468        final int       webSocketID = 14003000 + counter++;
469        final boolean[] optionals   = { false, };
470        
471        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
472        String requestJSON = WriteJSON.get(
473            parameterTypes.get("startTabMirroring"),
474            parameterNames.get("startTabMirroring"),
475            optionals, webSocketID,
476            "Cast.startTabMirroring",
477            sinkName
478        );
479        
480        // This Remote Command does not have a Return-Value.
481        return new Script<>
482            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
483    }
484    
485    /**
486     * Stops the active Cast session on the sink.
487     * 
488     * @param sinkName -
489     * 
490     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
491     * {@link Ret0}&gt;</CODE>
492     *
493     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
494     * browser receives the invocation-request.
495     *
496     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
497     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
498     * {@code >} to ensure the Browser Function has run to completion.
499     */
500    public static Script<String, JsonObject, Ret0> stopCasting(String sinkName)
501    {
502        // Exception-Check(s) to ensure that if any parameters which are not declared as
503        // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
504        
505        if (sinkName == null) THROWS.throwNPE("sinkName");
506        
507        final int       webSocketID = 14004000 + counter++;
508        final boolean[] optionals   = { false, };
509        
510        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
511        String requestJSON = WriteJSON.get(
512            parameterTypes.get("stopCasting"),
513            parameterNames.get("stopCasting"),
514            optionals, webSocketID,
515            "Cast.stopCasting",
516            sinkName
517        );
518        
519        // This Remote Command does not have a Return-Value.
520        return new Script<>
521            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
522    }
523    
524}