/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira.drafts
 */
package net.ranides.assira.index;

import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import net.ranides.assira.collection.query.CQueryAbstract;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public abstract class IQueryAbstract<V> extends CQueryAbstract<V> implements IQuery<V> {
    
    protected abstract Collection<V> select();
    
    protected abstract <T> Function<V,T> mindex(String name);
    
    protected abstract Comparator<V> sindex(String name);
    
    @Override
    public Stream<V> stream() {
        return select().stream();
    }

    @Override
    public int size() {
        return select().size();
    }

    @Override
    public Iterator<V> iterator() {
        return select().iterator();
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public final IQuery<V> eq(String index, Object value) {
        return filter(index, a -> eq(a,value), a -> eq(a,(V)value));
    }

    @SuppressWarnings("unchecked")
    @Override
    public final IQuery<V> lt(String index, Object value) {
        return filter(index, a -> lt(a,value), a -> lt(a,(V)value));
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public final IQuery<V> gt(String index, Object value) {
        return filter(index, a -> gt(a,value), a -> gt(a,(V)value));
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public final IQuery<V> in(String index, Object begin, Object end) {
        return filter(index, a -> in(a,begin,end), a -> in(a,(V)begin,(V)end));
    }

    private IQuery<V> filter(
            String index, 
            Function<Function<V, Object>, IQuery<V>> mf, 
            Function<Comparator<V>, IQuery<V>> sf
    ) {
        Function<V, Object> mi = mindex(index);
        if(mi != null) {
            return mf.apply(mi);
        }
        Comparator<V> si = sindex(index);
        if(si != null) {
            return sf.apply(si);
        }
        throw new IllegalArgumentException("Unknown index: " + index);
    }
    
    public static abstract class IQMap<V> implements IQueryMap<V> {

        @Override
        public final IQuery<V> find(Comparator<V> index, V value) {
            return find().eq(index, value);
        }

        @Override
        public <T> IQuery<V> find(Function<V, T> index, T value) {
            return find().eq(index, value);
        }

        @SuppressWarnings("unchecked")
        @Override
        public final IQuery<V> find(String index, Object value) {
            return find().eq(index, value);
        }

        @Override
        public final void put(Collection<? extends V> values) {
            for(V value : values) {
                put(value);
            }
        }

        @Override
        public final void remove(Comparator<V> index, V value) {
            find().eq(index, value).remove();
        }

        @Override
        public <T> void remove(Function<V, T> index, T value) {
            find().eq(index, value).remove();
        }

        @Override
        public final void remove(String index, Object value) {
            find().eq(index, value).remove();
        }

        @Override
        public void removeAll(Collection<V> values) {
            for(V item : values) {
                remove(item);
            }
        }

        @Override
        public void update(V value, Consumer<? super V> consumer) {
            remove(value);
            consumer.accept(value);
            put(value);
        }

    }
    
}
