package net.ranides.assira.ui.query;

import net.ranides.assira.collection.arrays.ArrayUtils;
import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.reflection.BeanPropertyBinding;

import java.util.function.Consumer;

public class IPropertySelector {

    private final IComponents scope;

    private final String[] component;

    private final String property;

    private final String qualifier;

    private IPropertySelector(IComponents scope, String[] component, String property, String qualifier) {
        this.scope = scope;
        this.component = component;
        this.property = property;
        this.qualifier = qualifier;
    }

    public static IPropertySelector of(String path) {
        return of(IComponentUtils.windows(), path);
    }

    public static IPropertySelector of(IComponent scope, String path) {
        return of(IComponents.of(scope), path);
    }

    public static IPropertySelector of(IComponents scope, String path) {
        String[] parts = path.trim().split("[ ./]+");
        if(parts.length > 2) {
            if(parts[parts.length-1].startsWith("@")) {
                String prop = parts[parts.length - 2];
                String qual = parts[parts.length - 1].substring(1).trim();
                return new IPropertySelector(scope, ArrayUtils.slice(parts, 0, parts.length-2), prop, qual);
            }
        }
        return new IPropertySelector(scope, ArrayUtils.slice(parts, 0, parts.length-1), parts[parts.length-1], "");
    }

    public static IPropertySelector of(String path, String property) {
        return of(IComponentUtils.windows(), path, property);
    }

    public static IPropertySelector of(IComponent scope, String path, String property) {
        return of(IComponents.of(scope), path, property);
    }

    public static IPropertySelector of(IComponents scope, String path, String property) {
        return of(scope, path + " " + property);
    }

    public static IPropertySelector parse(String path) {
        return of(IComponents.empty(), path);
    }

    public IComponents scope() {
        return scope;
    }

    public String[] path() {
        return component;
    }

    public String property() {
        return property;
    }

    public String qualifier() {
        return qualifier;
    }

    public IComponentSelector parent() {
        return new IComponentSelector(scope, component);
    }

    public CQuery<BeanPropertyBinding<Object>> stream() {
        return scope().find(component).stream().map(component -> component.property(property));
    }

    public CQuery<BeanPropertyBinding<Object>> stream(IComponent scope) {
        return scope.find(component).stream().map(component -> component.property(property));
    }

    public CQuery<BeanPropertyBinding<Object>> stream(IComponents scope) {
        return scope.find(component).stream().map(component -> component.property(property));
    }

    public void forEach(Consumer<? super BeanPropertyBinding<Object>> consumer) {
        stream().forEach(consumer);
    }
}
