#ifndef EXPLORER_HPP_
#define EXPLORER_HPP_

#include <RuntimeStateCache/RuntimeStateCache.hpp>
#include <Widget/Layout/CompoundWidget/CompoundWidget.hpp>
#include <functional>
#include <vector>
#include <Widget/Layout/Column/Column.hpp>
#include <Widget/Layout/Row/Row.hpp>
#include <Widget/Layout/Center/Center.hpp>
#include <Widget/Builder/Builder.hpp>
#include <Widget/Button/Button.hpp>
#include <Widget/TextField/TextField.hpp>
#include <Widget/Panel/Panel.hpp>
#include <Widget/Layout/Frame/Frame.hpp>
#include <Widget/Label/Label.hpp>
#include <Utilities/Utilities.hpp>
#include <Widget/Layout/Column/HorizontalSeparator/HorizontalSeparator.hpp>
#include <Widget/Layout/ScrollPanel/ScrollPanel.hpp>
#include <Widget/Layout/Frame/Frame.hpp>

/**
 * @brief The explorer widget.
 * 
 * This widget displays a search bar, and a scrollable list. Each entry is created by converting
 * an "item" into a widget. The explorer allows the user to search through a collection of items.
 * 
 * This is used for example in "recipe book" GUIs.
 */
template<typename TItem>
class Explorer : public CompoundWidget
{
private:
    static constexpr int naturalScrollPanelHeight = 100;
    struct State
    {
        std::string query;
        int scrollPos;
    };

    std::shared_ptr<State> state;

public:
    /**
     * @brief Construct the explorer.
     * 
     * @param queryItems Function which returns a vector of items given a query string.
     * @param renderItem Function which returns a widget given an item.
     */
    Explorer(
        const std::string &stateUrl,
        std::function<std::vector<TItem>(std::string)> queryItems,
        std::function<Widget*(TItem)> renderItem
    )
    {
        state = RuntimeStateCache::get<State>(stateUrl);

        addChildren(
            new Column(
                (new TextField(state->query))
                    ->withPlaceholder("Search...")
                    ->withAutoSelect(),

                new HorizontalSeparator(),

                Layout::WithProportion<1>(),
                new Builder<std::string>(
                    state->query,
                    [this, queryItems, renderItem](std::string query)
                    {
                        std::vector<TItem> items = queryItems(query);
                        std::list<Widget*> widgets;

                        for (int i=0; i<(int)items.size(); i++)
                        {
                            widgets.push_back(
                                new Frame(
                                    (i & 1) ? Color::tableRowOdd : Color::tableRowEven,
                                    renderItem(items[i])
                                )
                            );
                        }

                        return new ScrollPanel(state->scrollPos, naturalScrollPanelHeight, new Column(widgets));
                    }
                )
            )
        );
    }
};

#endif