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>The Tethering domain defines methods and events for browser port binding.</B></SPAN>
028 * 
029 * <EMBED CLASS='external-html' DATA-FILE-ID=CODE_GEN_NOTE>
030 */
031@StaticFunctional(Excused={"counter"}, Excuses={Excuse.CONFIGURATION})
032@JDHeaderBackgroundImg(EmbedTagFileID="WOOD_PLANK_NOTE")
033public class Tethering
034{
035    // ********************************************************************************************
036    // ********************************************************************************************
037    // Class Header Stuff
038    // ********************************************************************************************
039    // ********************************************************************************************
040
041
042    // No Pubic Constructors
043    private Tethering () { }
044
045    // These two Vector's are used by all the "Methods" exported by this class.  java.lang.reflect
046    // is used to generate the JSON String's.  It saves thousands of lines of Auto-Generated Code.
047    private static final Map<String, Vector<String>>    parameterNames = new HashMap<>();
048    private static final Map<String, Vector<Class<?>>>  parameterTypes = new HashMap<>();
049
050    // Some Methods do not take any parameters - for instance all the "enable()" and "disable()"
051    // I simply could not get ride of RAW-TYPES and UNCHECKED warnings... so there are now,
052    // offically, two empty-vectors.  One for String's, and the other for Classes.
053
054    private static final Vector<String>     EMPTY_VEC_STR = new Vector<>();
055    private static final Vector<Class<?>>   EMPTY_VEC_CLASS = new Vector<>();
056
057    static
058    {
059        for (Method m : Tethering.class.getMethods())
060        {
061            // This doesn't work!  The parameter names are all "arg0" ... "argN"
062            // It works for java.lang.reflect.Field, BUT NOT java.lang.reflect.Parameter!
063            //
064            // Vector<String> parameterNamesList = new Vector<>(); -- NOPE!
065
066            Vector<Class<?>> parameterTypesList = new Vector<>();
067        
068            for (Parameter p : m.getParameters()) parameterTypesList.add(p.getType());
069
070            parameterTypes.put(
071                m.getName(),
072                (parameterTypesList.size() > 0) ? parameterTypesList : EMPTY_VEC_CLASS
073            );
074        }
075    }
076
077    static
078    {
079        Vector<String> v = null;
080
081        v = new Vector<String>(1);
082        parameterNames.put("bind", v);
083        Collections.addAll(v, new String[]
084        { "port", });
085
086        v = new Vector<String>(1);
087        parameterNames.put("unbind", v);
088        Collections.addAll(v, new String[]
089        { "port", });
090    }
091
092
093    // ********************************************************************************************
094    // ********************************************************************************************
095    // Types - Static Inner Classes
096    // ********************************************************************************************
097    // ********************************************************************************************
098
099    /** Informs that port was successfully bound and got a specified connection id. */
100    public static class accepted
101        extends BrowserEvent
102        implements java.io.Serializable
103    {
104        /** For Object Serialization.  java.io.Serializable */
105        protected static final long serialVersionUID = 1;
106        
107        public boolean[] optionals()
108        { return new boolean[] { false, false, }; }
109        
110        /** Port number that was successfully bound. */
111        public final int port;
112        
113        /** Connection id to be used. */
114        public final String connectionId;
115        
116        /**
117         * Constructor
118         *
119         * @param port Port number that was successfully bound.
120         * 
121         * @param connectionId Connection id to be used.
122         */
123        public accepted(int port, String connectionId)
124        {
125            super("Tethering", "accepted", 2);
126            
127            // Exception-Check(s) to ensure that if any parameters which are not declared as
128            // 'Optional', but have a 'null' value anyway, that a NullPointerException shall throw.
129            
130            if (connectionId == null) THROWS.throwNPE("connectionId");
131            
132            this.port          = port;
133            this.connectionId  = connectionId;
134        }
135        
136        /**
137         * JSON Object Constructor
138         * @param jo A Json-Object having data about an instance of {@code 'accepted'}.
139         */
140        public accepted (JsonObject jo)
141        {
142            super("Tethering", "accepted", 2);
143        
144            this.port          = ReadPrimJSON.getInt(jo, "port");
145            this.connectionId  = ReadJSON.getString(jo, "connectionId", false, true);
146        }
147        
148        
149        /** Checks whether {@code 'this'} equals an input Java-{@code Object} */
150        public boolean equals(Object other)
151        {
152            if (this == other)                       return true;
153            if (other == null)                       return false;
154            if (other.getClass() != this.getClass()) return false;
155        
156            accepted o = (accepted) other;
157        
158            return
159                    (this.port == o.port)
160                &&  Objects.equals(this.connectionId, o.connectionId);
161        }
162        
163        /** Generates a Hash-Code for {@code 'this'} instance */
164        public int hashCode()
165        {
166            return
167                    this.port
168                +   Objects.hashCode(this.connectionId);
169        }
170    }
171    
172    
173    // Counter for keeping the WebSocket Request ID's distinct.
174    private static int counter = 1;
175    
176    /**
177     * Request browser port binding.
178     * 
179     * @param port Port number to bind.
180     * 
181     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
182     * {@link Ret0}&gt;</CODE>
183     *
184     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
185     * browser receives the invocation-request.
186     *
187     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
188     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
189     * {@code >} to ensure the Browser Function has run to completion.
190     */
191    public static Script<String, JsonObject, Ret0> bind(int port)
192    {
193        final int       webSocketID = 43000000 + counter++;
194        final boolean[] optionals   = { false, };
195        
196        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
197        String requestJSON = WriteJSON.get(
198            parameterTypes.get("bind"),
199            parameterNames.get("bind"),
200            optionals, webSocketID,
201            "Tethering.bind",
202            port
203        );
204        
205        // This Remote Command does not have a Return-Value.
206        return new Script<>
207            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
208    }
209    
210    /**
211     * Request browser port unbinding.
212     * 
213     * @param port Port number to unbind.
214     * 
215     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
216     * {@link Ret0}&gt;</CODE>
217     *
218     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
219     * browser receives the invocation-request.
220     *
221     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
222     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
223     * {@code >} to ensure the Browser Function has run to completion.
224     */
225    public static Script<String, JsonObject, Ret0> unbind(int port)
226    {
227        final int       webSocketID = 43001000 + counter++;
228        final boolean[] optionals   = { false, };
229        
230        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
231        String requestJSON = WriteJSON.get(
232            parameterTypes.get("unbind"),
233            parameterNames.get("unbind"),
234            optionals, webSocketID,
235            "Tethering.unbind",
236            port
237        );
238        
239        // This Remote Command does not have a Return-Value.
240        return new Script<>
241            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
242    }
243    
244}