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