All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.orientechnologies.common.collection.OMultiCollectionIterator Maven / Gradle / Ivy

/*
  *
  *  *  Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
  *  *
  *  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  *  you may not use this file except in compliance with the License.
  *  *  You may obtain a copy of the License at
  *  *
  *  *       http://www.apache.org/licenses/LICENSE-2.0
  *  *
  *  *  Unless required by applicable law or agreed to in writing, software
  *  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  *  See the License for the specific language governing permissions and
  *  *  limitations under the License.
  *  *
  *  * For more information: http://www.orientechnologies.com
  *
  */
package com.orientechnologies.common.collection;

import com.orientechnologies.common.util.OResettable;
import com.orientechnologies.common.util.OSizeable;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;

/**
 * Iterator that allow to iterate against multiple collection of elements.
 *
 * @author Luca Garulli (l.garulli--at--orientechnologies.com)
 */
public class OMultiCollectionIterator implements Iterator, Iterable, OResettable, OSizeable {
  private Collection sources;
  private Iterator        iteratorOfInternalCollections;
  private Iterator        partialIterator;

  private int                browsed  = 0;
  private int                limit    = -1;
  private boolean            embedded = false;

  public OMultiCollectionIterator() {
    sources = new ArrayList();
  }

  public OMultiCollectionIterator(final Collection iSources) {
    sources = iSources;
    iteratorOfInternalCollections = iSources.iterator();
    getNextPartial();
  }

  public OMultiCollectionIterator(final Iterator> iterator) {
    iteratorOfInternalCollections = iterator;
    getNextPartial();
  }

  @Override
  public boolean hasNext() {
    if (iteratorOfInternalCollections == null) {
      if (sources == null || sources.isEmpty())
        return false;

      // THE FIRST TIME CREATE THE ITERATOR
      iteratorOfInternalCollections = sources.iterator();
      getNextPartial();
    }

    if (partialIterator == null)
      return false;

    if (limit > -1 && browsed >= limit)
      return false;

    if (partialIterator.hasNext())
      return true;
    else if (iteratorOfInternalCollections.hasNext())
      return getNextPartial();

    return false;
  }

  @Override
  public T next() {
    if (!hasNext())
      throw new NoSuchElementException();

    browsed++;
    return partialIterator.next();
  }

  @Override
  public Iterator iterator() {
    reset();
    return this;
  }

  @Override
  public void reset() {
    iteratorOfInternalCollections = null;
    partialIterator = null;
    browsed = 0;
  }

  public OMultiCollectionIterator add(final Object iValue) {
    if (iValue != null) {
      if (iteratorOfInternalCollections != null)
        throw new IllegalStateException("MultiCollection iterator is in use and new collections cannot be added");
      sources.add(iValue);
    }
    return this;
  }

  public int size() {
    // SUM ALL THE COLLECTION SIZES
    int size = 0;
    for (Object o : sources) {
      if (o != null)
        if (o instanceof Collection)
          size += ((Collection) o).size();
        else if (o instanceof Map)
          size += ((Map) o).size();
        else if (o instanceof OSizeable)
          size += ((OSizeable) o).size();
        else if (o.getClass().isArray())
          size += Array.getLength(o);
        else if (o instanceof Iterator && o instanceof OResettable) {
          while (((Iterator) o).hasNext()) {
            size++;
            ((Iterator) o).next();
          }
          ((OResettable) o).reset();
        } else
          size++;
    }
    return size;
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException("OMultiCollectionIterator.remove()");
  }

  public int getLimit() {
    return limit;
  }

  public void setLimit(final int limit) {
    this.limit = limit;
  }

  @SuppressWarnings("unchecked")
  protected boolean getNextPartial() {
    if (iteratorOfInternalCollections != null)
      while (iteratorOfInternalCollections.hasNext()) {
        Object next = iteratorOfInternalCollections.next();
        if (next != null) {

          if (next instanceof Iterable)
            next = ((Iterable) next).iterator();

          if (next instanceof Iterator) {
            if (next instanceof OResettable)
              ((OResettable) next).reset();

            if (((Iterator) next).hasNext()) {
              partialIterator = (Iterator) next;
              return true;
            }
          } else if (next instanceof Collection) {
            if (!((Collection) next).isEmpty()) {
              partialIterator = ((Collection) next).iterator();
              return true;
            }
          } else if (next.getClass().isArray()) {
            final int arraySize = Array.getLength(next);
            if (arraySize > 0) {
              if (arraySize == 1)
                partialIterator = new OIterableObject((T) Array.get(next, 0));
              else
                partialIterator = (Iterator) OMultiValue.getMultiValueIterator(next);
              return true;
            }
          } else {
            partialIterator = new OIterableObject((T) next);
            return true;
          }
        }
      }

    return false;
  }

  public boolean isEmbedded() {
    return embedded;
  }

  public OMultiCollectionIterator setEmbedded(final boolean embedded) {
    this.embedded = embedded;
    return this;
  }

  @Override
  public String toString() {
    return "[" + size() + "]";
  }
}