package com.base2art.jeqll.impl;
import com.base2art.jeqll.IQuery;
import com.base2art.jeqll.SequenceContainsNoItemsException;
import com.base2art.jeqll.matchers.IMatcher;
import com.base2art.jeqll.matchers.SkipUntilMatcher;
import com.base2art.jeqll.matchers.TakeUntilMatcher;
import com.base2art.jeqll.projections.IArithmaticField;
import com.base2art.jeqll.projections.IField;
import com.base2art.jeqll.util.IPair;
import java.util.ArrayList;
import java.util.Iterator;
public class IterableQuery<T>
implements IQuery<T>
{
private final Iterable<T> list;
private final IMatcher matcher;
private final Class<T> klazz;
public IterableQuery(Iterable<T> list, Class<T> klazz)
{
this(list, klazz, null);
}
private IterableQuery(Iterable<T> list, Class<T> klazz, IMatcher matcher)
{
this.list = list;
this.klazz = klazz;
this.matcher = matcher;
}
@Override
public Iterator<T> iterator()
{
return this.iterable().iterator();
}
@Override
public IQuery<T> where(IMatcher matcher)
{
return new IterableQuery(list, this.klazz, matcher);
}
@Override
public T first()
{
for (T item : this.iterable())
{
return item;
}
throw new SequenceContainsNoItemsException();
}
@Override
public T last()
{
boolean hasItem = false;
T lastItem = null;
for (T item : this.iterable())
{
hasItem = true;
lastItem = item;
}
if (hasItem)
{
return lastItem;
}
throw new SequenceContainsNoItemsException();
}
@Override
public T single()
{
Iterator<T> iter = this.iterable().iterator();
if (iter.hasNext())
{
T item = iter.next();
if (iter.hasNext())
{
throw new SequenceContainsNoItemsException();
}
return item;
}
throw new SequenceContainsNoItemsException();
}
@Override
public T elementAt(int i)
{
int j = -1;
for (T item : this.iterable())
{
j += 1;
if (j == i)
{
return item;
}
if (j > i)
{
throw new UnsupportedOperationException("Programming Error");
}
}
throw new SequenceContainsNoItemsException();
}
@Override
public <TProjected> IQuery<TProjected> select(IField<TProjected> convertor)
{
return new IterableQuery<TProjected>(
new IterableQuerySelectProjectable<T, TProjected>(this.iterable(), convertor), convertor.getKlazz());
}
@Override
public <TProjected> IQuery<TProjected> selectMany(IField<TProjected> convertor)
{
return new IterableQuery<TProjected>(
new IterableQuerySelectManyProjectable<T, TProjected>(this.iterable(), convertor), convertor.getKlazz());
}
@Override
public int count()
{
int i = 0;
for (T t : this.iterable())
{
i += 1;
}
return i;
}
@Override
public <TProjected extends Comparable<TProjected>> TProjected min(IField<TProjected> convertor)
{
TProjected item = null;
boolean hasItem = false;
for (TProjected current : this.select(convertor))
{
hasItem = true;
if (item == null || item.compareTo(current) > 0)
{
item = current;
}
}
if (!hasItem)
{
throw new SequenceContainsNoItemsException();
}
return item;
}
@Override
public <TProjected extends Comparable<TProjected>> TProjected max(IField<TProjected> convertor)
{
TProjected item = null;
boolean hasItem = false;
for (TProjected current : this.select(convertor))
{
hasItem = true;
if (item == null || item.compareTo(current) < 0)
{
item = current;
}
}
if (!hasItem)
{
throw new SequenceContainsNoItemsException();
}
return item;
}
@Override
public <TProjected> TProjected sum(IArithmaticField<TProjected> convertor)
{
TProjected localSum = null;
boolean hasItem = false;
for (TProjected current : this.select(convertor))
{
hasItem = true;
if (localSum == null)
{
localSum = current;
}
else
{
if (current != null)
{
localSum = convertor.add(localSum, current);
}
}
}
if (!hasItem)
{
throw new SequenceContainsNoItemsException();
}
return localSum;
}
@Override
public <TProjected> TProjected average(IArithmaticField<TProjected> convertor)
{
TProjected localSum = null;
boolean hasItem = false;
int i = 0;
for (TProjected current : this.select(convertor))
{
hasItem = true;
if (localSum == null)
{
i += 1;
localSum = current;
}
else
{
if (current != null)
{
i += 1;
localSum = convertor.add(localSum, current);
}
}
}
if (!hasItem)
{
throw new SequenceContainsNoItemsException();
}
return convertor.divideByInt(localSum, i);
}
@Override
public T[] toArray()
{
T[] ar = (T[]) java.lang.reflect.Array.newInstance(this.klazz, 0);
return this.toList().toArray(ar);
}
@Override
public ArrayList<T> toList()
{
ArrayList<T> returnList = new ArrayList<>();
for (T item : this.iterable())
{
returnList.add(item);
}
return returnList;
}
@Override
public <TKey extends Comparable<TKey>> IQuery<IPair<TKey, IQuery<T>>> groupBy(IField<TKey> field)
{
Class<IPair<TKey, IQuery<T>>> returnKlazz = (Class<IPair<TKey, IQuery<T>>>) (Class<?>) IPair.class;
return new IterableQuery<IPair<TKey, IQuery<T>>>(
new IterableQueryGroupable<TKey, T>(this.iterable(), field, this.klazz), returnKlazz);
}
@Override
public IQuery<T> take(int i)
{
return new IterableQuery(this.iterable(), this.klazz, new TakeUntilMatcher(i));
}
@Override
public IQuery<T> skip(int i)
{
return new IterableQuery(this.iterable(), this.klazz, new SkipUntilMatcher(i));
}
// @Override
// public IPartitionedQuery<T> takeWhile(IPredicate<T> predicate)
// {
// throw new UnsupportedOperationException("Not supported yet.");
// }
//
// @Override
// public IPartitionedQuery<T> skipWhile(IPredicate<T> predicate)
// {
// throw new UnsupportedOperationException("Not supported yet.");
// }
private Iterable<T> iterable()
{
if (this.matcher == null)
{
return this.list;
}
return new IterableQueryIterable<>(this.list, this.matcher);
}
}