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) THROWS.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 (this == other)                       return true;
149            if (other == null)                       return false;
150            if (other.getClass() != this.getClass()) return false;
151        
152            accepted o = (accepted) other;
153        
154            return
155                    (this.port == o.port)
156                &&  Objects.equals(this.connectionId, o.connectionId);
157        }
158        
159        /** Generates a Hash-Code for {@code 'this'} instance */
160        public int hashCode()
161        {
162            return
163                    this.port
164                +   Objects.hashCode(this.connectionId);
165        }
166    }
167    
168    
169    // Counter for keeping the WebSocket Request ID's distinct.
170    private static int counter = 1;
171    
172    /**
173     * Request browser port binding.
174     * 
175     * @param port Port number to bind.
176     * 
177     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
178     * {@link Ret0}&gt;</CODE>
179     *
180     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
181     * browser receives the invocation-request.
182     *
183     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
184     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
185     * {@code >} to ensure the Browser Function has run to completion.
186     */
187    public static Script<String, JsonObject, Ret0> bind(int port)
188    {
189        final int       webSocketID = 40000000 + counter++;
190        final boolean[] optionals   = { false, };
191        
192        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
193        String requestJSON = WriteJSON.get(
194            parameterTypes.get("bind"),
195            parameterNames.get("bind"),
196            optionals, webSocketID,
197            "Tethering.bind",
198            port
199        );
200        
201        // This Remote Command does not have a Return-Value.
202        return new Script<>
203            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
204    }
205    
206    /**
207     * Request browser port unbinding.
208     * 
209     * @param port Port number to unbind.
210     * 
211     * @return An instance of <CODE>{@link Script}&lt;String, {@link JsonObject},
212     * {@link Ret0}&gt;</CODE>
213     *
214     * <BR /><BR />This {@code Script} instance must be <B STYLE='color:red'>executed</B> before the
215     * browser receives the invocation-request.
216     *
217     * <BR /><BR />This Browser-Function <I>does not have</I> a return-value.  You may choose to
218     * <B STYLE='color: red'>await</B> the {@link Promise}{@code <JsonObject,} {@link Ret0}
219     * {@code >} to ensure the Browser Function has run to completion.
220     */
221    public static Script<String, JsonObject, Ret0> unbind(int port)
222    {
223        final int       webSocketID = 40001000 + counter++;
224        final boolean[] optionals   = { false, };
225        
226        // Convert Method Parameters into JSON.  Build the JSON Request-Object (as a String)
227        String requestJSON = WriteJSON.get(
228            parameterTypes.get("unbind"),
229            parameterNames.get("unbind"),
230            optionals, webSocketID,
231            "Tethering.unbind",
232            port
233        );
234        
235        // This Remote Command does not have a Return-Value.
236        return new Script<>
237            (webSocketID, requestJSON, VOID_RETURN.NoReturnValues);
238    }
239    
240}