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.internal;
019
020import org.apiguardian.api.API;
021import org.tquadrat.foundation.annotation.ClassVersion;
022import org.tquadrat.foundation.jsonbuilder.JSONArray;
023import org.tquadrat.foundation.jsonbuilder.JSONBuilder;
024import org.tquadrat.foundation.jsonbuilder.JSONObject;
025import org.tquadrat.foundation.jsonbuilder.JSONValue;
026import org.tquadrat.foundation.lang.value.Dimension;
027import org.tquadrat.foundation.lang.value.DimensionedValue;
028
029import java.io.IOException;
030import java.io.UncheckedIOException;
031import java.math.BigDecimal;
032import java.math.BigInteger;
033import java.util.ArrayList;
034import java.util.Formatter;
035import java.util.Iterator;
036import java.util.List;
037import java.util.StringJoiner;
038
039import static java.lang.Integer.max;
040import static org.apiguardian.api.API.Status.INTERNAL;
041import static org.tquadrat.foundation.jsonbuilder.JSONLiteral.NULL;
042import static org.tquadrat.foundation.lang.CommonConstants.EMPTY_STRING;
043import static org.tquadrat.foundation.lang.Objects.hash;
044import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument;
045
046/**
047 *  <p>{@summary The implementation for the interface
048 *  {@link JSONArray}.}</p>
049 *
050 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
051 *  @version $Id: JSONArrayImpl.java 1195 2026-04-15 21:33:40Z tquadrat $
052 *  @since 0.25.0
053 *
054 *  @UMLGraph.link
055 */
056@ClassVersion( sourceVersion = "$Id: JSONArrayImpl.java 1195 2026-04-15 21:33:40Z tquadrat $" )
057@API( status = INTERNAL, since = "0.25.0" )
058public final class JSONArrayImpl implements JSONArray
059{
060        /*------------*\
061    ====** Attributes **=======================================================
062        \*------------*/
063    /**
064     *  The reference to the
065     *  {@link JSONBuilder}
066     *  that was used to create this {@code JSONObject}, and that is used to
067     *  create the members.
068     */
069    private final JSONBuilderImpl m_Builder;
070
071    /**
072     *  The elements for this {@code JSONArray} instance.
073     */
074    private final List<JSONValue> m_Elements = new ArrayList<>();
075
076        /*--------------*\
077    ====** Constructors **=====================================================
078        \*--------------*/
079    /**
080     *  Creates a new instance of {@code JSONArrayImpl}.
081     *
082     *  @param  builder The reference to the
083     *      {@link JSONBuilder}.
084     */
085    public JSONArrayImpl( final JSONBuilderImpl builder )
086    {
087        m_Builder = requireNonNullArgument( builder, "builder" );
088    }   //  JSONArrayImpl()
089
090    /**
091     *  <p>{summary Creates a new instance of {@code JSONArrayImpl} from the
092     *  given other array.}</p>
093     *  <p>The new array is a deep copy of the given instance.</p>
094     *
095     *  @param  other   The other JSON array.
096     */
097    public JSONArrayImpl( final JSONArrayImpl other )
098    {
099        m_Builder = requireNonNullArgument( other, "other" ).m_Builder;
100        for( final var element : other.m_Elements )
101        {
102            m_Elements.add( switch( element )
103            {
104                case null -> NULL;
105                case JSONArrayImpl array -> new JSONArrayImpl( array );
106                case JSONObjectImpl object -> new JSONObjectImpl( object );
107                default -> element;
108            });
109        }
110    }   //  JSONArrayImpl()
111
112        /*---------*\
113    ====** Methods **==========================================================
114        \*---------*/
115    /**
116     *  {@inheritDoc}
117     */
118    @Override
119    public final void add( final BigDecimal value ) { add( m_Builder.valueOf( value ) ); }
120
121    /**
122     *  {@inheritDoc}
123     */
124    @Override
125    public final void add( final BigInteger value ) { add( m_Builder.valueOf( value ) ); }
126
127    /**
128     *  {@inheritDoc}
129     */
130    @Override
131    public final <T extends Dimension> void add( final DimensionedValue<T> value, final T targetUnit )
132    {
133        add( m_Builder.valueOf( value, targetUnit ) );
134    }   //  add()
135
136    /**
137     *  {@inheritDoc}
138     */
139    @Override
140    public final void add( final double value ) { add( m_Builder.valueOf( value ) ); }
141
142    /**
143     *  {@inheritDoc}
144     */
145    @Override
146    public final void add( final Double value ) { add( m_Builder.valueOf( value ) ); }
147
148    /**
149     *  {@inheritDoc}
150     */
151    @Override
152    public final void add( final float value ) { add( m_Builder.valueOf( value ) ); }
153
154    /**
155     *  {@inheritDoc}
156     */
157    @Override
158    public final void add( final Float value ) { add( m_Builder.valueOf( value ) ); }
159
160    /**
161     *  {@inheritDoc}
162     */
163    @Override
164    public final void add( final int value ) { add( m_Builder.valueOf( value ) ); }
165
166    /**
167     *  {@inheritDoc}
168     */
169    @Override
170    public final void add( final Integer value ) { add( m_Builder.valueOf( value ) ); }
171
172    /**
173     *  {@inheritDoc}
174     */
175    @Override
176    public final void add( final JSONValue value )
177    {
178        m_Elements.add( requireNonNullArgument( value, "value" ) );
179    }   //  add()
180
181    /**
182     *  {@inheritDoc}
183     */
184    @Override
185    public final void add( final long value ) { add( m_Builder.valueOf( value ) ); }
186
187    /**
188     *  {@inheritDoc}
189     */
190    @Override
191    public final void add( final Long value ) { add( m_Builder.valueOf( value ) ); }
192
193    /**
194     *  {@inheritDoc}
195     */
196    @Override
197    public final void add( final String value ) { add( m_Builder.valueOf( value ) ); }
198
199    /**
200     *  {@inheritDoc}
201     */
202    @Override
203    public final void add( final int index, final BigDecimal value )  throws IndexOutOfBoundsException
204    {
205        add( index, m_Builder.valueOf( value ) );
206    }   //  add()
207
208    /**
209     *  {@inheritDoc}
210     */
211    @Override
212    public final void add( final int index, final BigInteger value ) throws IndexOutOfBoundsException
213    {
214        add( index, m_Builder.valueOf( value ) );
215    }   //  add()
216
217    /**
218     *  {@inheritDoc}
219     */
220    @Override
221    public final <T extends Dimension> void add( final int index, final DimensionedValue<T> value, final T targetUnit ) throws IndexOutOfBoundsException
222    {
223        add( index, m_Builder.valueOf( value, targetUnit ) );
224    }   //  add()
225
226    /**
227     *  {@inheritDoc}
228     */
229    @Override
230    public final void add( final int index, final double value ) throws IndexOutOfBoundsException
231    {
232        add( index, m_Builder.valueOf( value ) );
233    }   //  add()
234
235    /**
236     *  {@inheritDoc}
237     */
238    @Override
239    public final void add( final int index, final Double value ) throws IndexOutOfBoundsException
240    {
241        add( index, m_Builder.valueOf( value ) );
242    }   //  add()
243
244    /**
245     *  {@inheritDoc}
246     */
247    @Override
248    public final void add( final int index, final float value ) throws IndexOutOfBoundsException
249    {
250        add( index, m_Builder.valueOf( value ) );
251    }   //  add()
252
253    /**
254     *  {@inheritDoc}
255     */
256    @Override
257    public final void add( final int index, final Float value ) throws IndexOutOfBoundsException
258    {
259        add( index, m_Builder.valueOf( value ) );
260    }   //  add()
261
262    /**
263     *  {@inheritDoc}
264     */
265    @Override
266    public final void add( final int index, final int value ) throws IndexOutOfBoundsException
267    {
268        add( index, m_Builder.valueOf( value ) );
269    }   //  add()
270
271    /**
272     *  {@inheritDoc}
273     */
274    @Override
275    public final void add( final int index, final Integer value ) throws IndexOutOfBoundsException
276    {
277        add( index, m_Builder.valueOf( value ) );
278    }   //  add()
279
280    /**
281     *  {@inheritDoc}
282     */
283    @Override
284    public final void add( final int index, final JSONValue value ) throws IndexOutOfBoundsException
285    {
286        m_Elements.add( index, requireNonNullArgument( value, "value" ) );
287    }   //  add()
288
289    /**
290     *  {@inheritDoc}
291     */
292    @Override
293    public final void add( final int index, final long value ) throws IndexOutOfBoundsException
294    {
295        add( index, m_Builder.valueOf( value ) );
296    }   //  add()
297
298    /**
299     *  {@inheritDoc}
300     */
301    @Override
302    public final void add( final int index, final Long value ) throws IndexOutOfBoundsException
303    {
304        add( index, m_Builder.valueOf( value ) );
305    }   //  add()
306
307    /**
308     *  {@inheritDoc}
309     */
310    @Override
311    public final void add( final int index, final String value ) throws IndexOutOfBoundsException
312    {
313        add( index, m_Builder.valueOf( value ) );
314    }   //  add()
315
316    /**
317     *  {@inheritDoc}
318     */
319    @Override
320    public final boolean addAll( final JSONArray array )
321    {
322        final var retValue = m_Elements.addAll( ((JSONArrayImpl) requireNonNullArgument( array, "array" )).m_Elements );
323
324        //---* Done *----------------------------------------------------------
325        return retValue;
326    }   //  addAll()
327
328    /**
329     *  {@inheritDoc}
330     */
331    @Override
332    public final JSONArray addArray()
333    {
334        final var retValue = m_Builder.createArray();
335        add( retValue );
336
337        //---* Done *----------------------------------------------------------
338        return retValue;
339    }   //  addArray()
340
341    /**
342     *  {@inheritDoc}
343     */
344    @Override
345    public JSONArray addArray( final int index ) throws IndexOutOfBoundsException
346    {
347        final var retValue = m_Builder.createArray();
348        add( index, retValue );
349
350        //---* Done *----------------------------------------------------------
351        return retValue;
352    }   //  addArray()
353
354    /**
355     *  {@inheritDoc}
356     */
357    @Override
358    public JSONObject addObject()
359    {
360        final var retValue = m_Builder.createObject();
361        add( retValue );
362
363        //---* Done *----------------------------------------------------------
364        return retValue;
365    }   //  addObject()
366
367    /**
368     *  {@inheritDoc}
369     */
370    @Override
371    public JSONObject addObject( final int index ) throws IndexOutOfBoundsException
372    {
373        final var retValue = m_Builder.createObject();
374        add( index, retValue );
375
376        //---* Done *----------------------------------------------------------
377        return retValue;
378    }   //  addObject()
379
380    /**
381     *  {@inheritDoc}
382     */
383    @Override
384    public final boolean equals( final Object o )
385    {
386        var retValue = this == o;
387        if( !retValue && o instanceof final JSONArrayImpl other )
388        {
389            retValue = m_Builder.equals( other.m_Builder )
390                && m_Elements.equals( other.m_Elements );
391        }
392
393        //---* Done *----------------------------------------------------------
394        return retValue;
395    }   //  equals()
396
397    /**
398     * {@inheritDoc}
399     */
400    @Override
401    public void formatTo( final Formatter formatter, final int flags, final int width, final int precision )
402    {
403        final var indentation1 = "\n" + (width <= 0 ? EMPTY_STRING : " ".repeat( width ));
404        final var newWidth = max( 0, width ) + m_Builder.getIndentation();
405        final var indentation2 = "\n" + " ".repeat( newWidth );
406        final var appendable = formatter.out();
407        try
408        {
409            switch( m_Elements.size() )
410            {
411                case 0 -> appendable.append( "[]" );
412                case 1 ->
413                {
414                    appendable.append( "[" );
415                    final var element = m_Elements.getFirst();
416                    element.formatTo( formatter, flags, newWidth, precision );
417                    appendable.append( "]" );
418                }
419                default ->
420                {
421                    var isFirst = true;
422                    appendable.append( "[" );
423                    for( final var element : m_Elements )
424                    {
425                        if( isFirst )
426                        {
427                            isFirst = false;
428                        }
429                        else
430                        {
431                            appendable.append( ',' );
432                        }
433                        appendable.append( indentation2 );
434                        element.formatTo( formatter, flags, newWidth, precision );
435                    }
436                    appendable.append( indentation1 )
437                        .append( "]" );
438                }
439            }
440        }
441        catch( final IOException e )
442        {
443            throw new UncheckedIOException( e.getMessage(), e );
444        }
445    }   //  formatTo()
446
447    /**
448     *  {@inheritDoc}
449     */
450    @Override
451    public final JSONValue get( final int index )  throws IndexOutOfBoundsException
452    {
453        return m_Elements.get( index );
454    }   //  get()
455
456    /**
457     *  {@inheritDoc}
458     */
459    @Override
460    public final int hashCode() { return hash( m_Builder, m_Elements ); }
461
462    /**
463     *  {@inheritDoc}
464     */
465    @Override
466    public final boolean isEmpty() { return m_Elements.isEmpty(); }
467
468    /**
469     *  {@inheritDoc}
470     */
471    @Override
472    public final Iterator<JSONValue> iterator() { return m_Elements.listIterator(); }
473
474    /**
475     *  {@inheritDoc}
476     */
477    @Override
478    public final void remove( final int index ) throws IndexOutOfBoundsException
479    {
480        m_Elements.remove( index );
481    }   //  remove()
482
483    /**
484     *  {@inheritDoc}
485     */
486    @Override
487    public final void remove( final JSONValue element ) throws IndexOutOfBoundsException
488    {
489        m_Elements.remove( requireNonNullArgument( element, "element" ) );
490    }   //  remove()
491
492    /**
493     *  {@inheritDoc}
494     */
495    @Override
496    public final void set( final int index, final BigDecimal value ) throws IndexOutOfBoundsException
497    {
498        set( index, m_Builder.valueOf( value ) );
499    }   //  set()
500
501    /**
502     *  {@inheritDoc}
503     */
504    @Override
505    public void set( final int index, final BigInteger value ) throws IndexOutOfBoundsException
506    {
507        set( index, m_Builder.valueOf( value ) );
508    }   //  set()
509
510    /**
511     *  {@inheritDoc}
512     */
513    @Override
514    public <T extends Dimension> void set( final int index, final DimensionedValue<T> value, final T targetUnit ) throws IndexOutOfBoundsException
515    {
516        set( index, m_Builder.valueOf( value, targetUnit ) );
517    }   //  set()
518
519    /**
520     *  {@inheritDoc}
521     */
522    @Override
523    public void set( final int index, final double value ) throws IndexOutOfBoundsException
524    {
525        set( index, m_Builder.valueOf( value ) );
526    }   //  set()
527
528    /**
529     *  {@inheritDoc}
530     */
531    @Override
532    public void set( final int index, final Double value ) throws IndexOutOfBoundsException
533    {
534        set( index, m_Builder.valueOf( value ) );
535    }   //  set()
536
537    /**
538     *  {@inheritDoc}
539     */
540    @Override
541    public void set( final int index, final float value ) throws IndexOutOfBoundsException
542    {
543        set( index, m_Builder.valueOf( value ) );
544    }   //  set()
545
546    /**
547     *  {@inheritDoc}
548     */
549    @Override
550    public void set( final int index, final Float value ) throws IndexOutOfBoundsException
551    {
552        set( index, m_Builder.valueOf( value ) );
553    }   //  set()
554
555    /**
556     *  {@inheritDoc}
557     */
558    @Override
559    public void set( final int index, final int value ) throws IndexOutOfBoundsException
560    {
561        set( index, m_Builder.valueOf( value ) );
562    }   //  set()
563
564    /**
565     *  {@inheritDoc}
566     */
567    @Override
568    public void set( final int index, final Integer value ) throws IndexOutOfBoundsException
569    {
570        set( index, m_Builder.valueOf( value ) );
571    }   //  set()
572
573    /**
574     *  {@inheritDoc}
575     */
576    @Override
577    public final void set( final int index, final JSONValue value ) throws IndexOutOfBoundsException
578    {
579        m_Elements.set( index, requireNonNullArgument( value, "value" ) );
580    }   //  set()
581
582    /**
583     *  {@inheritDoc}
584     */
585    @Override
586    public void set( final int index, final long value ) throws IndexOutOfBoundsException
587    {
588        set( index, m_Builder.valueOf( value ) );
589    }   //  set()
590
591    /**
592     *  {@inheritDoc}
593     */
594    @Override
595    public void set( final int index, final Long value ) throws IndexOutOfBoundsException
596    {
597        set( index, m_Builder.valueOf( value ) );
598    }   //  set()
599
600    /**
601     *  {@inheritDoc}
602     */
603    @Override
604    public void set( final int index, final String value ) throws IndexOutOfBoundsException
605    {
606        set( index, m_Builder.valueOf( value ) );
607    }   //  set()
608
609    /**
610     *  {@inheritDoc}
611     */
612    @Override
613    public final JSONArray setArray( final int index ) throws IndexOutOfBoundsException
614    {
615        final var retValue = m_Builder.createArray();
616        set( index, retValue );
617
618        //---* Done *----------------------------------------------------------
619        return retValue;
620    }   //  setArray()
621
622    /**
623     *  {@inheritDoc}
624     */
625    @Override
626    public final JSONObject setObject( final int index ) throws IndexOutOfBoundsException
627    {
628        final var retValue = m_Builder.createObject();
629        set( index, retValue );
630
631        //---* Done *----------------------------------------------------------
632        return retValue;
633    }   //  setObject()
634
635    /**
636     *  {@inheritDoc}
637     */
638    @Override
639    public final int size() { return m_Elements.size(); }
640
641    /**
642     *  {@inheritDoc}
643     */
644    @Override
645    public final String toString()
646    {
647        final var buffer = new StringJoiner( ",", "[", "]" );
648        for( final var element : m_Elements )
649        {
650            buffer.add( element.toString() );
651        }
652        final var retValue = buffer.toString();
653
654        //---* Done *----------------------------------------------------------
655        return retValue;
656    }   //  toString()
657}
658//  class JSONArrayImpl
659
660/*
661 *  End of File
662 */