package org.nwapw.abacus;

import org.nwapw.abacus.config.Configuration;
import org.nwapw.abacus.fx.AbacusApplication;
import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.parsing.LexerTokenizer;
import org.nwapw.abacus.parsing.ShuntingYardParser;
import org.nwapw.abacus.parsing.TreeBuilder;
import org.nwapw.abacus.plugin.ClassFinder;
import org.nwapw.abacus.plugin.NumberImplementation;
import org.nwapw.abacus.plugin.PluginManager;
import org.nwapw.abacus.plugin.StandardPlugin;
import org.nwapw.abacus.tree.NumberReducer;
import org.nwapw.abacus.tree.TreeNode;

import java.io.File;
import java.io.IOException;

/**
 * The main calculator class. This is responsible
 * for piecing together all of the components, allowing
 * their interaction with each other.
 */
public class Abacus {

    public static final NumberImplementation DEFAULT_IMPLEMENTATION = StandardPlugin.IMPLEMENTATION_NAIVE;
    /**
     * The file used for saving and loading configuration.
     */
    public static final File CONFIG_FILE = new File("config.toml");

    /**
     * The plugin manager responsible for
     * loading and unloading plugins,
     * and getting functions from them.
     */
    private PluginManager pluginManager;
    /**
     * The reducer used to evaluate the tree.
     */
    private NumberReducer numberReducer;
    /**
     * The configuration loaded from a file.
     */
    private Configuration configuration;
    /**
     * The tree builder used to construct a tree
     * from a string.
     */
    private TreeBuilder treeBuilder;

    /**
     * Creates a new instance of the Abacus calculator.
     */
    public Abacus() {
        pluginManager = new PluginManager(this);
        numberReducer = new NumberReducer(this);
        configuration = new Configuration(CONFIG_FILE);
        configuration.saveTo(CONFIG_FILE);
        LexerTokenizer lexerTokenizer = new LexerTokenizer();
        ShuntingYardParser shuntingYardParser = new ShuntingYardParser(this);
        treeBuilder = new TreeBuilder<>(lexerTokenizer, shuntingYardParser);

        pluginManager.addListener(lexerTokenizer);
        pluginManager.addListener(shuntingYardParser);
        pluginManager.addInstantiated(new StandardPlugin(pluginManager));
        try {
            ClassFinder.loadJars("plugins")
                    .forEach(plugin -> pluginManager.addClass(plugin));
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        pluginManager.load();
    }

    public static void main(String[] args) {
        AbacusApplication.launch(AbacusApplication.class, args);
    }

    /**
     * Gets the current tree builder.
     *
     * @return the main tree builder in this abacus instance.
     */
    public TreeBuilder getTreeBuilder() {
        return treeBuilder;
    }

    /**
     * Gets the current plugin manager,
     *
     * @return the plugin manager in this abacus instance.
     */
    public PluginManager getPluginManager() {
        return pluginManager;
    }

    /**
     * Get the reducer that is responsible for transforming
     * an expression into a number.
     *
     * @return the number reducer in this abacus instance.
     */
    public NumberReducer getNumberReducer() {
        return numberReducer;
    }

    /**
     * Gets the configuration object associated with this instance.
     *
     * @return the configuration object.
     */
    public Configuration getConfiguration() {
        return configuration;
    }

    /**
     * Parses a string into a tree structure using the main
     * tree builder.
     *
     * @param input the input string to parse
     * @return the resulting tree, null if the tree builder or the produced tree are null.
     */
    public TreeNode parseString(String input) {
        return treeBuilder.fromString(input);
    }

    /**
     * Evaluates the given tree using the main
     * number reducer.
     *
     * @param tree the tree to reduce, must not be null.
     * @return the resulting number, or null of the reduction failed.
     */
    public NumberInterface evaluateTree(TreeNode tree) {
        return tree.reduce(numberReducer);
    }

    /**
     * Creates a number from a string.
     *
     * @param numberString the string to create the number from.
     * @return the resulting number.
     */
    public NumberInterface numberFromString(String numberString) {
        NumberImplementation toInstantiate =
                pluginManager.numberImplementationFor(configuration.getNumberImplementation());
        if (toInstantiate == null) toInstantiate = DEFAULT_IMPLEMENTATION;

        return toInstantiate.instanceForString(numberString);
    }
}

@@ -804,16 +804,125 @@
 acus %7B%0A%0A
+    /**%0A     * The default number implementation to be used if no other one is available / selected.%0A     */%0A
     publ

Add missing comment.