package net.ranides.assira.ui.query;

import javax.accessibility.AccessibleContext;
import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.generic.Ref;
import net.ranides.assira.reflection.BeanPropertyBinding;

import java.awt.*;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collector;

public interface IComponents extends Iterable<IComponent> {

    static IComponents of(IComponent value) {
        return new RComponents(CQuery.from().value(value));
    }

    static IComponents of(IComponent... values) {
        return new RComponents(CQuery.from().array(values));
    }

    static IComponents empty() {
        return RComponents.EMPTY.$empty();
    }

    /**
     * Returns number of elements.
     *
     * Invocation of this method can trigger computation of whole content of collection.
     *
     * @return int
     */
    int count();

    /**
     * Returns true if collection is empty.
     *
     * Invocation of this method can trigger computation of whole content of collection.
     *
     * @return boolean
     */
    boolean isEmpty();

    /**
     * Converts this collection into CQuery.
     * Each element is converted using provided mapper.
     *
     * @param mapper mapper
     * @param <R> R
     * @return CQuery
     */
    <R> CQuery<R> stream(Function<? super IComponent, R> mapper);

    /**
     * Converts this collection into CQuery.
     *
     * @return CQuery
     */
    CQuery<IComponent> stream();

    /**
     * Iterates over all elements inside collection.
     *
     * @param consumer consumer
     */
    void each(Consumer<? super IComponent> consumer);

    /**
     * Converts this collection into List.
     * Each element is converted using provided mapper.
     *
     * @param mapper mapper
     * @param <R> R
     * @return List
     */
    <R> List<R> list(Function<? super IComponent, R> mapper);

    /**
     * Converts this collection into List.
     *
     * @return List
     */
    List<IComponent> list();

    /**
     * Converts this collection into Collection.
     *
     * @param collector collector
     * @param <R> R
     * @param <A> A
     * @return Collection
     */
    <R, A> R collect(Collector<? super IComponent, A, R> collector);

    IComponents filter(Predicate<IComponent> predicate);

    <T extends Component> IComponents filter(Class<T> type);

    Ref<IComponent> first();

    <T extends Component> Ref<T> first(Class<T> type);

    Ref<IComponent> single();

    <T extends Component> Ref<T> single(Class<T> type);

    Ref<IComponent> at(int index);

    CQuery<String> names();

    CQuery<AccessibleContext> accessibles();

    IComponents parent();

    IComponents find(String[] path);

    IComponents find(String path);

    IComponents find(Predicate<IComponent> visitor);

    CQuery<BeanPropertyBinding<Object>> property(String name);

    void property(String name, Object value);

    void set(String name, Object value);

    CQuery<Object> get(String name);

}
