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