package net.ranides.assira.ui.parsers;

import lombok.experimental.UtilityClass;
import net.ranides.assira.collection.query.CQuery;
import net.ranides.assira.grammar.G4Exception;
import net.ranides.assira.grammar.G4Node;
import net.ranides.assira.grammar.G4Parser;
import net.ranides.assira.grammar.G4Selector;
import net.ranides.assira.grammar.properties.G4NodeProperty;
import net.ranides.grammars.generated.UiGrammarLexer;
import net.ranides.grammars.generated.UiGrammarParser;

import javax.swing.*;
import java.util.NoSuchElementException;

@UtilityClass
public class GrammarBase {

    public static final G4NodeProperty<JComponent> COMPONENT = G4NodeProperty.of(JComponent.class, "component");

    public static final G4Parser PARSER = G4Parser.builder()
        .lexer(UiGrammarLexer.class)
        .parser(UiGrammarParser.class)
        .build();

    public static JComponent component(G4Node node) {
        return node.get(GrammarBase.COMPONENT).orElseThrow(() -> new IllegalArgumentException("There is no associated JComponent with node + " + node));
    }

    public static <T> T parseSingle(G4Selector<T> selector, String rule, String value) {
        return parseSingle(selector, rule, null, value);
    }

    public static <T> T parseSingle(G4Selector<T> selector, String rule, JComponent component, String value) {
        try {
            G4Node node = GrammarBase.PARSER.parse(rule, value);
            if(component != null) {
                node.set(GrammarBase.COMPONENT, component);
            }
            return selector.single(node);
        } catch (NoSuchElementException | G4Exception e) {
            throw new IllegalArgumentException("Invalid value: \"" + value + "\"", e);
        }
    }

    public static <T> CQuery<T> parseStream(G4Selector<T> selector, String rule, String values) {
        return parseStream(selector, rule, null, values);
    }

    public static <T> CQuery<T> parseStream(G4Selector<T> selector, String rule, JComponent component, String values) {
        try {
            G4Node node = GrammarBase.PARSER.parse(rule, values);
            if(component != null) {
                node.set(GrammarBase.COMPONENT, component);
            }
            return selector.stream(node);
        } catch (NoSuchElementException | G4Exception e) {
            throw new IllegalArgumentException("Invalid value: \"" + values + "\"", e);
        }
    }

}
