001/*
002 * ============================================================================
003 *  Copyright © 2002-2026 by Thomas Thrien.
004 *  All Rights Reserved.
005 * ============================================================================
006 *  Licensed to the public under the agreements of the GNU Lesser General Public
007 *  License, version 3.0 (the "License"). You may obtain a copy of the License at
008 *
009 *       http://www.gnu.org/licenses/lgpl.html
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014 *  License for the specific language governing permissions and limitations
015 *  under the License.
016 */
017
018package org.tquadrat.foundation.jsonbuilder;
019
020import static org.apiguardian.api.API.Status.STABLE;
021import static org.tquadrat.foundation.jsonbuilder.JSONLiteral.FALSE;
022import static org.tquadrat.foundation.jsonbuilder.JSONLiteral.TRUE;
023
024import java.math.BigDecimal;
025import java.math.BigInteger;
026import java.util.Optional;
027import java.util.SequencedCollection;
028
029import org.apiguardian.api.API;
030import org.tquadrat.foundation.annotation.ClassVersion;
031import org.tquadrat.foundation.jsonbuilder.internal.JSONObjectImpl;
032import org.tquadrat.foundation.lang.value.Dimension;
033import org.tquadrat.foundation.lang.value.DimensionedValue;
034
035/**
036 *  <p>{@summary The definition of a JSON object.}</p>
037 *
038 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
039 *  @version $Id: JSONObject.java 1258 2026-06-04 18:33:06Z tquadrat $
040 *  @since 0.25.0
041 *
042 *  @UMLGraph.link
043 */
044@SuppressWarnings( "ClassWithTooManyMethods" )
045@ClassVersion( sourceVersion = "$Id: JSONObject.java 1258 2026-06-04 18:33:06Z tquadrat $" )
046@API( status = STABLE, since = "0.25.0" )
047public sealed interface JSONObject extends Iterable<JSONValue>, JSONValue
048    permits JSONObjectImpl
049{
050        /*---------*\
051    ====** Methods **==========================================================
052        \*---------*/
053    /**
054     *  <p>{@summary Checks if a specified member is present as a child of this
055     *  object.} This will not test if that child is the JSON literal
056     *  {@null}, This needs to be tested separately.</p>
057     *
058     *  @param  name The name of the member to check for.
059     *  @return {@true} if there is a member with the given name,
060     *      {@false} if not.
061     */
062    public boolean contains( final String name );
063
064    /**
065     *  <p>{@summary Returns the value of the member with the specified name in
066     *  this object.}</p>
067     *
068     *  @param  name    The name of the member whose value is to be returned.
069     *  @return An instance of
070     *      {@link Optional}
071     *      that holds the value.
072     */
073    public Optional<JSONValue> get( final String name );
074
075    /**
076     *  <p>{@summary Convenience method that returns the value with the
077     *  specified name as a
078     *  {@link JSONArray}.}</p>
079     *
080     *  @param  name    The name of the member whose value is to be returned.
081     *  @param  defaultValue    The value to be returned if the requested
082     *      member is missing; can be {@null}.
083     *  @return The value of the member with the specified name, or the given
084     *      default value if this object does not contain a member with that
085     *      name.
086     *  @throws IllegalStateException   The member exists, but it is not a
087     *      JSON Array.
088     */
089    public default JSONArray getArray( final String name, final JSONArray defaultValue ) throws IllegalStateException
090    {
091        final var retValue = get( name ).map( JSONValue::asArray ).orElse( defaultValue );
092
093        //---* Done *----------------------------------------------------------
094        return retValue;
095    }   //  getArray()
096
097    /**
098     *  <p>{@summary Convenience method that returns the value with the
099     *  specified name as a
100     *  {@link BigDecimal}.}</p>
101     *
102     *  @param  name    The name of the member whose value is to be returned.
103     *  @param  defaultValue    The value to be returned if the requested
104     *      member is missing; can be {@null}.
105     *  @return The value of the member with the specified name, or the given
106     *      default value if this object does not contain a member with that
107     *      name.
108     *  @throws IllegalStateException   The member exists, but it is not a
109     *      number.
110     *  @throws NumberFormatException   The member exists, and it is a number,
111     *      but cannot be parsed to a valid {@code BigDecimal}.
112     */
113    public default BigDecimal getBigDecimal( final String name, final BigDecimal defaultValue ) throws IllegalStateException, NumberFormatException
114    {
115        var retValue = defaultValue;
116        final var value = get( name );
117        if( value.isPresent() )
118        {
119            final var number = value.get().asNumber();
120            retValue = number.getBigDecimal();
121        }
122
123        //---* Done *----------------------------------------------------------
124        return retValue;
125    }   //  getBigDecimal()
126
127    /**
128     *  <p>{@summary Convenience method that returns the value with the
129     *  specified name as a
130     *  {@link BigInteger}.}</p>
131     *
132     *  @param  name    The name of the member whose value is to be returned.
133     *  @param  defaultValue    The value to be returned if the requested
134     *      member is missing; can be {@null}.
135     *  @return The value of the member with the specified name, or the given
136     *      default value if this object does not contain a member with that
137     *      name.
138     *  @throws IllegalStateException   The member exists, but it is not a
139     *      number.
140     *  @throws NumberFormatException   The member exists, and it is a number,
141     *      but cannot be parsed to a valid {@code BigInteger}.
142     */
143    public default BigInteger getBigInteger( final String name, final BigInteger defaultValue ) throws IllegalStateException, NumberFormatException
144    {
145        var retValue = defaultValue;
146        final var value = get( name );
147        if( value.isPresent() )
148        {
149            final var number = value.get().asNumber();
150            retValue = number.getBigInteger();
151        }
152
153        //---* Done *----------------------------------------------------------
154        return retValue;
155    }   //  getBigInteger()
156
157    /**
158     *  <p>{@summary Convenience method that returns the value with the
159     *  specified name as a {@code boolean}.}</p>
160     *
161     *  @param  name    The name of the member whose value is to be returned.
162     *  @param  defaultValue    The value to be returned if the requested
163     *      member is missing.
164     *  @return The value of the member with the specified name, or the given
165     *      default value if this object does not contain a member with that
166     *      name.
167     *  @throws IllegalStateException   The member exists, but it is not a
168     *      boolean.
169     */
170    @SuppressWarnings( "BooleanMethodNameMustStartWithQuestion" )
171    public default boolean getBoolean( final String name, final boolean defaultValue ) throws IllegalStateException
172    {
173        var retValue = defaultValue;
174        final var value = get( name );
175        if( value.isPresent() )
176        {
177            final var flag = value.get().asBoolean();
178            retValue = flag.isTrue();
179        }
180
181        //---* Done *----------------------------------------------------------
182        return retValue;
183    }   //  getBoolean()
184
185    /**
186     *  <p>{@summary Convenience method that returns the value with the
187     *  specified name as a {@code double}.}</p>
188     *
189     *  @param  name    The name of the member whose value is to be returned.
190     *  @param  defaultValue    The value to be returned if the requested
191     *      member is missing.
192     *  @return The value of the member with the specified name, or the given
193     *      default value if this object does not contain a member with that
194     *      name.
195     *  @throws IllegalStateException   The member exists, but it is not a
196     *      number.
197     *  @throws NumberFormatException   The member exists, and it is a number,
198     *      but cannot be parsed to a valid {@code double}.
199     */
200    public default double getDouble( final String name, final double defaultValue ) throws IllegalStateException, NumberFormatException
201    {
202        var retValue = defaultValue;
203        final var value = get( name );
204        if( value.isPresent() )
205        {
206            final var number = value.get().asNumber();
207            retValue = number.getDouble();
208        }
209
210        //---* Done *----------------------------------------------------------
211        return retValue;
212    }   //  getDouble()
213
214    /**
215     *  <p>{@summary Convenience method that returns the value with the
216     *  specified name as a {@code float}.}</p>
217     *
218     *  @param  name    The name of the member whose value is to be returned.
219     *  @param  defaultValue    The value to be returned if the requested
220     *      member is missing.
221     *  @return The value of the member with the specified name, or the given
222     *      default value if this object does not contain a member with that
223     *      name.
224     *  @throws IllegalStateException   The member exists, but it is not a
225     *      number.
226     *  @throws NumberFormatException   The member exists, and it is a number,
227     *      but cannot be parsed to a valid {@code float}.
228     */
229    public default float getFloat( final String name, final float defaultValue ) throws IllegalStateException, NumberFormatException
230    {
231        var retValue = defaultValue;
232        final var value = get( name );
233        if( value.isPresent() )
234        {
235            final var number = value.get().asNumber();
236            retValue = number.getFloat();
237        }
238
239        //---* Done *----------------------------------------------------------
240        return retValue;
241    }   //  getFloat()
242
243    /**
244     *  <p>{@summary Convenience method that returns the value with the
245     *  specified name as a {@code int}.}</p>
246     *
247     *  @param  name    The name of the member whose value is to be returned.
248     *  @param  defaultValue    The value to be returned if the requested
249     *      member is missing; can be {@null}.
250     *  @return The value of the member with the specified name, or the given
251     *      default value if this object does not contain a member with that
252     *      name.
253     *  @throws IllegalStateException   The member exists, but it is not a
254     *      number.
255     *  @throws NumberFormatException   The member exists, and it is a number,
256     *      but cannot be parsed to a valid {@code int}.
257     */
258    public default int getInt( final String name, final int defaultValue ) throws IllegalStateException, NumberFormatException
259    {
260        var retValue = defaultValue;
261        final var value = get( name );
262        if( value.isPresent() )
263        {
264            final var number = value.get().asNumber();
265            retValue = number.getInt();
266        }
267
268        //---* Done *----------------------------------------------------------
269        return retValue;
270    }   //  getInt()
271
272    /**
273     *  <p>{@summary Convenience method that returns the value with the
274     *  specified name as a {@code long}.}</p>
275     *
276     *  @param  name    The name of the member whose value is to be returned.
277     *  @param  defaultValue    The value to be returned if the requested
278     *      member is missing.
279     *  @return The value of the member with the specified name, or the given
280     *      default value if this object does not contain a member with that
281     *      name.
282     *  @throws IllegalStateException   The member exists, but it is not a
283     *      number.
284     *  @throws NumberFormatException   The member exists, and it is a number,
285     *      but cannot be parsed to a valid {@code long}.
286     */
287    public default long getLong( final String name, final long defaultValue ) throws IllegalStateException, NumberFormatException
288    {
289        var retValue = defaultValue;
290        final var value = get( name );
291        if( value.isPresent() )
292        {
293            final var number = value.get().asNumber();
294            retValue = number.getLong();
295        }
296
297        //---* Done *----------------------------------------------------------
298        return retValue;
299    }   //  getLong()
300
301    /**
302     *  <p>{@summary Convenience method that returns the value with the
303     *  specified name as a {@code JSONObject}.}</p>
304     *
305     *  @param  name    The name of the member whose value is to be returned.
306     *  @param  defaultValue    The value to be returned if the requested
307     *      member is missing; can be {@null}.
308     *  @return The value of the member with the specified name, or the given
309     *      default value if this object does not contain a member with that
310     *      name.
311     *  @throws IllegalStateException   The member exists, but it is not a
312     *      JSON Object.
313     */
314    public default JSONObject getObject( final String name, final JSONObject defaultValue ) throws IllegalStateException
315    {
316        final var retValue = get( name ).map( JSONValue::asObject ).orElse( defaultValue );
317
318        //---* Done *----------------------------------------------------------
319        return retValue;
320    }   //  getObject()
321
322    /**
323     *  <p>{@summary Convenience method that returns the value with the
324     *  specified name as a
325     *  {@link String}.}</p>
326     *
327     *  @param  name    The name of the member whose value is to be returned.
328     *  @param  defaultValue    The value to be returned if the requested
329     *      member is missing; can be {@null}.
330     *  @return The value of the member with the specified name, or the given
331     *      default value if this object does not contain a member with that
332     *      name.
333     *  @throws IllegalStateException   The member exists, but it is not a
334     *      {@code String}.
335     */
336    public default String getString( final String name, final String defaultValue ) throws IllegalStateException
337    {
338        var retValue = defaultValue;
339        final var value = get( name );
340        if( value.isPresent() )
341        {
342            final var jsonString = value.get().asString();
343            retValue = jsonString.getString();
344        }
345
346        //---* Done *----------------------------------------------------------
347        return retValue;
348    }   //  getString()
349
350    /**
351     *  Checks whether this object has members.
352     *
353     *  @return {@true} if the object does not have any members,
354     *      {@false} otherwise.
355     */
356    public boolean isEmpty();
357
358    /**
359     *  <p>{@summary Copies all members of the specified object into this
360     *  object.} When the specified object contains members with names that
361     *  also exist in this object, the existing values in this object will be
362     *  replaced by the corresponding values in the specified object.</p>
363     *
364     *  @param  object  The object to merge.
365     *  @return This object itself, to enable method chaining.
366     */
367    public JSONObject merge( final JSONObject object );
368
369    /**
370     *  <p>{@summary Returns the names of the members of this object in
371     *  document order.}</p>
372     *  <p>The return value is backed by this object and will reflect
373     *  subsequent changes. It cannot be used to modify this object. Attempts
374     *  to modify the returned data structure will result in an exception.</p>
375     *
376     *  @return The names.
377     */
378    public SequencedCollection<String> names();
379
380    /**
381     *  <p>{@summary Removes a member with the specified name from this
382     *  object.} If this object does not contain a member with the specified
383     *  name, the object is not modified.</p>
384     *
385     *  @param  name    The name of the member to remove.
386     *  @return This object itself, to enable method chaining.
387     */
388    public JSONObject remove( final String name );
389
390    /**
391     *  <p>{@summary Sets the value of the member with the specified name to
392     *  the JSON representation of the specified
393     *  {@link BigDecimal}
394     *  value.}</p>
395     *  <p>If this object does not contain a member with this name, a new
396     *  member is added at the end of the object.</p>
397     *
398     *  @param  name    The name of the member to replace or to add.
399     *  @param  value   The value to set to the member.
400     *  @return This object itself, to enable method chaining.
401     */
402    public JSONObject set( final String name, final BigDecimal value );
403
404    /**
405     *  <p>{@summary Sets the value of the member with the specified name to
406     *  the JSON representation of the specified
407     *  {@link BigInteger}
408     *  value.}</p>
409     *  <p>If this object does not contain a member with this name, a new
410     *  member is added at the end of the object.</p>
411     *
412     *  @param  name    The name of the member to replace or to add.
413     *  @param  value   The value to set to the member.
414     *  @return This object itself, to enable method chaining.
415     */
416    public JSONObject set( final String name, final BigInteger value );
417
418    /**
419     *  <p>{@summary Sets the value of the member with the specified name to
420     *  the JSON representation of the specified {@code boolean} value.}</p>
421     *  <p>If this object does not contain a member with this name, a new
422     *  member is added at the end of the object.</p>
423     *
424     *  @param  name    The name of the member to replace or to add.
425     *  @param  value   The value to set to the member.
426     *  @return This object itself, to enable method chaining.
427     */
428    public default JSONObject set( final String name, final boolean value )
429    {
430        return set( name, value ? TRUE : FALSE );
431    }   //  set()
432
433    /**
434     *  <p>{@summary Sets the value of the member with the specified name to
435     *  the JSON representation of the specified
436     *  {@link DimensionedValue }
437     *  value.}</p>
438     *  <p>If this object does not contain a member with this name, a new
439     *  member is added at the end of the object.</p>
440     *
441     *  @param  <T> The type of the dimension for the value.
442     *  @param  name    The name of the member to replace or to add.
443     *  @param  value   The value.
444     *  @param  targetUnit  The dimension for the output.
445     *  @return This object itself, to enable method chaining.
446     *
447     *  @see JSONBuilder#valueOf(DimensionedValue, Dimension)
448     */
449    public <T extends Dimension> JSONObject set( final String name, final DimensionedValue<T> value, final T targetUnit );
450
451    /**
452     *  <p>{@summary Sets the value of the member with the specified name to
453     *  the JSON representation of the specified {@code double} value.}</p>
454     *  <p>If this object does not contain a member with this name, a new
455     *  member is added at the end of the object.</p>
456     *
457     *  @param  name    The name of the member to replace or to add.
458     *  @param  value   The value to set to the member.
459     *  @return This object itself, to enable method chaining.
460     */
461    public JSONObject set( final String name, final double value );
462
463    /**
464     *  <p>{@summary Sets the value of the member with the specified name to
465     *  the JSON representation of the specified
466     *  {@link Double}
467     *  value.}</p>
468     *  <p>If this object does not contain a member with this name, a new
469     *  member is added at the end of the object.</p>
470     *
471     *  @param  name    The name of the member to replace or to add.
472     *  @param  value   The value to set to the member.
473     *  @return This object itself, to enable method chaining.
474     */
475    public JSONObject set( final String name, final Double value );
476
477    /**
478     *  <p>{@summary Sets the value of the member with the specified name to
479     *  the JSON representation of the specified {@code float} value.}</p>
480     *  <p>If this object does not contain a member with this name, a new
481     *  member is added at the end of the object.</p>
482     *
483     *  @param  name    The name of the member to replace or to add.
484     *  @param  value   The value to set to the member.
485     *  @return This object itself, to enable method chaining.
486     */
487    public JSONObject set( final String name, final float value );
488
489    /**
490     *  <p>{@summary Sets the value of the member with the specified name to
491     *  the JSON representation of the specified
492     *  {@link Float}
493     *  value.}</p>
494     *  <p>If this object does not contain a member with this name, a new
495     *  member is added at the end of the object.</p>
496     *
497     *  @param  name    The name of the member to replace or to add.
498     *  @param  value   The value to set to the member.
499     *  @return This object itself, to enable method chaining.
500     */
501    public JSONObject set( final String name, final Float value );
502
503    /**
504     *  <p>{@summary Sets the value of the member with the specified name to
505     *  the JSON representation of the specified {@code int} value.}</p>
506     *  <p>If this object does not contain a member with this name, a new
507     *  member is added at the end of the object.</p>
508     *
509     *  @param  name    The name of the member to replace or to add.
510     *  @param  value   The value to set to the member.
511     *  @return This object itself, to enable method chaining.
512     */
513    public JSONObject set( final String name, final int value );
514
515    /**
516     *  <p>{@summary Sets the value of the member with the specified name to
517     *  the JSON representation of the specified
518     *  {@link Integer}
519     *  value.}</p>
520     *  <p>If this object does not contain a member with this name, a new
521     *  member is added at the end of the object.</p>
522     *
523     *  @param  name    The name of the member to replace or to add.
524     *  @param  value   The value to set to the member.
525     *  @return This object itself, to enable method chaining.
526     */
527    public JSONObject set( final String name, final Integer value );
528
529    /**
530     *  <p>{@summary Sets the value of the member with the specified name to
531     *  the specified
532     *  {@link JSONValue}
533     *  value.}</p>
534     *  <p>If this object does not contain a member with this name, a new
535     *  member is added at the end of the object.</p>
536     *
537     *  @param  name    The name of the member to replace or to add.
538     *  @param  value   The value to set to the member.
539     *  @return This object itself, to enable method chaining.
540     */
541    public JSONObject set( final String name, final JSONValue value );
542
543    /**
544     *  <p>{@summary Sets the value of the member with the specified name to
545     *  the JSON representation of the specified {@code long} value.}</p>
546     *  <p>If this object does not contain a member with this name, a new
547     *  member is added at the end of the object.</p>
548     *
549     *  @param  name    The name of the member to replace or to add.
550     *  @param  value   The value to set to the member.
551     *  @return This object itself, to enable method chaining.
552     */
553    public JSONObject set( final String name, final long value );
554
555    /**
556     *  <p>{@summary Sets the value of the member with the specified name to
557     *  the JSON representation of the specified
558     *  {@link Long}
559     *  value.}</p>
560     *  <p>If this object does not contain a member with this name, a new
561     *  member is added at the end of the object.</p>
562     *
563     *  @param  name    The name of the member to replace or to add.
564     *  @param  value   The value to set to the member.
565     *  @return This object itself, to enable method chaining.
566     */
567    public JSONObject set( final String name, final Long value );
568
569    /**
570     *  <p>{@summary Sets the value of the member with the specified name to
571     *  the JSON representation of the specified
572     *  {@link String}
573     *  value.}</p>
574     *  <p>If this object does not contain a member with this name, a new
575     *  member is added at the end of the object.</p>
576     *
577     *  @param  name    The name of the member to replace or to add.
578     *  @param  value   The value to set to the member.
579     *  @return This object itself, to enable method chaining.
580     */
581    public JSONObject set( final String name, final String value );
582
583    /**
584     *  <p>{@summary Sets a new empty instance of
585     *  {@link JSONArray}
586     *  to this object and returns that.}</p>
587     *
588     *  @param  name    The name of the member.
589     *  @return The freshly created {@code JSONArray}.
590     */
591    public JSONArray setArray( final String name );
592
593    /**
594     *  <p>{@summary Sets a new empty instance of {@code JSONObject} to this
595     *  object and returns that.}</p>
596     *
597     *  @param  name    The name of the member.
598     *  @return The freshly created {@code JSONObject}.
599     */
600    public JSONObject setObject( final String name );
601
602    /**
603     *  <p>{@summary Returns the number of members (name/value pairs) in this
604     *  object.}</p>
605     *
606     *  @return The number of members in this object.
607     */
608    public int size();
609}
610//  interface JSONObject
611
612/*
613 *  End of File
614 */