001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
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,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.http.classic.part;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020import static org.apache.juneau.commons.utils.StringUtils.*;
021import static org.apache.juneau.commons.utils.StringUtils.isEmpty;
022
023import java.util.*;
024import java.util.function.*;
025
026import org.apache.http.*;
027import org.apache.juneau.bct.assertions.*;
028
029/**
030 * A {@link NameValuePair} that consists of a comma-delimited list of string values.
031 *
032 * <h5 class='section'>See Also:</h5><ul>
033 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommon">juneau-rest-common</a>
034 * </ul>
035 */
036@SuppressWarnings({
037   "java:S2160" // equals() inherited from BasicPart compares name+value; typed field is accessed via getValue()
038})
039public class BasicCsvArrayPart extends BasicPart {
040   private static final String[] EMPTY = {};
041
042   /**
043    * Static creator.
044    *
045    * @param name The part name.
046    * @param value The part value.
047    * @return A new {@link BasicCsvArrayPart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
048    */
049   public static BasicCsvArrayPart of(String name, String...value) {
050      if (isEmpty(name) || value == null)
051         return null;
052      return new BasicCsvArrayPart(name, value);
053   }
054
055   /**
056    * Static creator with delayed value.
057    *
058    * <p>
059    * Part value is re-evaluated on each call to {@link NameValuePair#getValue()}.
060    *
061    * @param name The part name.
062    * @param value The part value supplier.
063    * @return A new {@link BasicCsvArrayPart} object, or <jk>null</jk> if the name or supplier is <jk>null</jk>.
064    */
065   public static BasicCsvArrayPart of(String name, Supplier<String[]> value) {
066      if (isEmpty(name) || value == null)
067         return null;
068      return new BasicCsvArrayPart(name, value);
069   }
070
071   private final String[] value;
072   private final Supplier<String[]> supplier;
073   private String stringValue;
074
075   /**
076    * Constructor.
077    *
078    * @param name The part name.  Must not be <jk>null</jk>.
079    * @param value The part value.  Can be <jk>null</jk>.
080    */
081   public BasicCsvArrayPart(String name, String...value) {
082      super(name, value);
083      this.value = value;
084      this.supplier = null;
085      this.stringValue = null;
086   }
087
088   /**
089    * Constructor.
090    *
091    * <p>
092    * <jk>null</jk> values are treated as <jk>null</jk>.
093    * Otherwise parses as a comma-delimited list with whitespace trimmed.
094    *
095    * @param name The part name.  Must not be <jk>null</jk>.
096    * @param value The part value.  Can be <jk>null</jk>.
097    */
098   public BasicCsvArrayPart(String name, String value) {
099      super(name, value);
100      this.value = splita(value);
101      this.supplier = null;
102      stringValue = value;
103   }
104
105   /**
106    * Constructor.
107    *
108    * @param name The part name.  Must not be <jk>null</jk>.
109    * @param value The part value supplier.  Can be <jk>null</jk> or supply <jk>null</jk>.
110    */
111   public BasicCsvArrayPart(String name, Supplier<String[]> value) {
112      super(name, value);
113      this.value = null;
114      supplier = value;
115      this.stringValue = null;
116   }
117
118   /**
119    * Returns The part value as an array wrapped in an {@link Optional}.
120    *
121    * <p>
122    * Array is a copy of the value of this part.
123    *
124    * @return The part value as an array wrapped in an {@link Optional}.  Never <jk>null</jk>.
125    */
126   public Optional<String[]> asArray() {
127      return o(cp(value()));
128   }
129
130   /**
131    * Returns The part value as a {@link List} wrapped in an {@link Optional}.
132    *
133    * <p>
134    * The list is unmodifiable.
135    *
136    * @return The part value as a {@link List} wrapped in an {@link Optional}.  Never <jk>null</jk>.
137    */
138   public Optional<List<String>> asList() {
139      return o(toList());
140   }
141
142   /**
143    * Provides the ability to perform fluent-style assertions on this part.
144    *
145    * @return A new fluent assertion object.
146    * @throws AssertionError If assertion failed.
147    */
148   public FluentListAssertion<String,BasicCsvArrayPart> assertList() {
149      return new FluentListAssertion<>(u(l(value())), this);
150   }
151
152   /**
153    * Returns <jk>true</jk> if this part contains the specified value.
154    *
155    * @param val The value to check for.
156    * @return <jk>true</jk> if this part contains the specified value.
157    */
158   public boolean contains(String val) {
159      if (nn(val))
160         for (var v : value())
161            if (eq(v, val))
162               return true;
163      return false;
164   }
165
166   /**
167    * Returns <jk>true</jk> if this part contains the specified value using {@link String#equalsIgnoreCase(String)}.
168    *
169    * @param val The value to check for.
170    * @return <jk>true</jk> if this part contains the specified value.
171    */
172   public boolean containsIgnoreCase(String val) {
173      if (nn(val))
174         for (var v : value())
175            if (eqic(v, val))
176               return true;
177      return false;
178   }
179
180   @Override /* Overridden from Header */
181   public String getValue() {
182      if (nn(supplier))
183         return join(supplier.get(), ',');
184      if (!nn(stringValue))
185         stringValue = join(value, ',');
186      return stringValue;
187   }
188
189   /**
190    * Return the value if present, otherwise return <c>other</c>.
191    *
192    * <p>
193    * This is a shortened form for calling <c>asArray().orElse(<jv>other</jv>)</c>.
194    *
195    * @param other The value to be returned if there is no value present, can be <jk>null</jk>.
196    * @return The value, if present, otherwise <c>other</c>.
197    */
198   public String[] orElse(String[] other) {
199      String[] x = value();
200      return nn(x) ? cp(x) : other;
201   }
202
203   /**
204    * Returns The part value as an array.
205    *
206    * <p>
207    * The array is a copy of the value of this part.
208    *
209    * @return The part value as an array, or <jk>null</jk> if the value <jk>null</jk>.
210    */
211   public String[] toArray() {
212      return cp(value());
213   }
214
215   /**
216    * Returns The part value as a {@link List}.
217    *
218    * <p>
219    * The list is unmodifiable.
220    *
221    * @return The part value as a {@link List}, or <jk>null</jk> if the value <jk>null</jk>.
222    */
223   public List<String> toList() {
224      return u(l(value()));
225   }
226
227   private String[] value() {
228      if (nn(supplier)) {
229         String[] v = supplier.get();
230         return nn(v) ? v : EMPTY;
231      }
232      return value;
233   }
234}