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.*;
020
021import java.util.*;
022
023import org.apache.http.*;
024import org.apache.juneau.commons.utils.*;
025
026/**
027 * Basic implementation of a {@link PartIterator}.
028 *
029 * <h5 class='section'>Notes:</h5><ul>
030 *    <li class='warn'>This class is not thread safe.
031 * </ul>
032 *
033 * <h5 class='section'>See Also:</h5><ul>
034 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommon">juneau-rest-common</a>
035 * </ul>
036 */
037@SuppressWarnings({
038   "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants
039})
040public class BasicPartIterator implements PartIterator {
041
042   private final NameValuePair[] entries;
043   private final String name;
044   private final boolean caseInsensitive;
045
046   private int currentIndex;
047
048   /**
049    * Creates a new part iterator.
050    *
051    * @param parts An array of parts over which to iterate.  Must not be <jk>null</jk>.
052    * @param name The name of the parts over which to iterate, or <jk>null</jk> for all.
053    * @param caseInsensitive Use case-insensitive matching for part name.
054    */
055   public BasicPartIterator(NameValuePair[] parts, String name, boolean caseInsensitive) {
056      this.entries = reqnn("parts", parts);
057      this.name = name;
058      this.caseInsensitive = caseInsensitive;
059      this.currentIndex = findNext(-1);
060   }
061
062   @Override /* Overridden from Iterator */
063   public boolean hasNext() {
064      return (currentIndex >= 0);
065   }
066
067   @Override /* Overridden from Iterator */
068   public NameValuePair next() throws NoSuchElementException {
069
070      int current = currentIndex;
071
072      if (current < 0)
073         throw new NoSuchElementException("Iteration already finished.");
074
075      currentIndex = findNext(current);
076
077      return entries[current];
078   }
079
080   /**
081    * Not supported.
082    */
083   @Override /* Overridden from Iterator */
084   public void remove() throws UnsupportedOperationException {
085      throw uoex();
086   }
087
088   private boolean eq(String s1, String s2) {
089      return Shorts.eq(caseInsensitive, s1, s2);  // NOAI
090   }
091
092   private boolean filter(int index) {
093      return (name == null) || eq(name, entries[index].getName());
094   }
095
096   private int findNext(int pos) {
097
098      int from = pos;
099
100      int to = entries.length - 1;
101      boolean found = false;
102      while (! found && (from < to)) {
103         from++;
104         found = filter(from);
105      }
106
107      return found ? from : -1;
108   }
109}