#include <vector>
#include <DataLink/DataLink.hpp>
#include <Widget/Layout/CompoundWidget/DataInputTable/DataInputTable.hpp>
#include <Widget/Layout/Column/Column.hpp>
#include <Widget/Layout/ScrollPanel/ScrollPanel.hpp>
#include <Widget/Label/Label.hpp>
#include <Widget/Layout/Row/Row.hpp>
#include <Widget/Button/Button.hpp>
#include <Widget/Builder/Builder.hpp>
#include <Widget/Layout/Frame/Frame.hpp>
#include <Widget/Panel/Panel.hpp>
#include <Widget/Layout/Center/Center.hpp>
#include <Widget/Layout/Row/VerticalSeparator/VerticalSeparator.hpp>
#include <Widget/Layout/Column/HorizontalSeparator/HorizontalSeparator.hpp>
#include <Widget/IconToggle/IconToggle.hpp>
#include <MachineComponent/DataCableComponent/DataCableComponent.hpp>
#include <Widget/IconLabel/IconLabel.hpp>
#include <Widget/Layout/Margin/Margin.hpp>

Widget* DataInputTable::makeRuleRow(
    RemoteDataComponent &remoteDataComponent,
    std::vector<DataCableComponent::InputRule> &rules,
    size_t index
)
{
    DataCableComponent::InputRule &rule = rules[index];

    auto onDestStateChanged = [&remoteDataComponent, index, &rule]()
    {
        remoteDataComponent.setInputRuleDestState(index, rule.destState);
    };

    return new Frame(
        (index & 1) ? Color::tableRowOdd : Color::tableRowEven,
        new Row(
            new Center(
                new Column(
                    new Center(
                        new DataChannelSelector(rule.channel, [&remoteDataComponent, index, &rule]()
                        {
                            remoteDataComponent.setInputRuleChannel(index, rule.channel);
                        })
                    ),

                    new HorizontalSeparator(),

                    new Center(
                        new Row(
                            (new IconToggle<bool>(rule.destState, true, Material::wireActivated))
                                ->withChangedCallback(onDestStateChanged)
                                ->withToolTip("When wire switches on"),
                            (new IconToggle<bool>(rule.destState, false, Material::wireDeactivated))
                                ->withChangedCallback(onDestStateChanged)
                                ->withToolTip("When wire switches off")
                        )
                    )
                )
            ),

            new Center(
                new Margin<2>(new IconLabel(Material::rightArrow))
            ),

            new Center(
                new Margin<2>(
                    new VerbSelector(
                        rule.verb,
                        verbOptions,
                        [&remoteDataComponent, index, &rule]
                        {
                            remoteDataComponent.setInputRuleVerb(index, rule.verb);
                        }
                    )
                )
            ),

            Layout::WithProportion<1>(),
            new Panel(),

            new Center(
                (new Button("", [&remoteDataComponent, index]()
                    {
                        remoteDataComponent.removeInputRule(index);
                    }))
                    ->withToolTip("Delete rule")
                    ->withFaceColor(Color::danger)
                    ->withIcon(Material::trash)
            )
        )
    );
}

DataInputTable::DataInputTable(
    std::vector<DataCableComponent::InputRule> &inputRules,
    RemoteDataComponent& remoteDataComponent,
    const std::vector<VerbOption> &verbOptions
) :
    CompoundWidget(
        new Column(
            Layout::WithProportion<1>(),
            new ScrollPanel(
                naturalHeight,
                new Builder<size_t>(
                    [&inputRules]() -> size_t { return inputRules.size(); },
                    [this, &inputRules, &remoteDataComponent](size_t count) -> Widget*
                    {
                        std::vector<Widget*> rows;

                        for (size_t i=0; i<count; i++)
                        {
                            rows.push_back(makeRuleRow(remoteDataComponent, inputRules, i));
                        }

                        return new Column(rows);
                    }
                )
            ),

            new Row(
                (new Button("", [this, &remoteDataComponent]()
                    {
                        DataCableComponent::InputRule newRule{DataLink::Channel::Red, false, this->verbOptions[0].value};
                        remoteDataComponent.addInputRule(newRule);
                    }))
                    ->withIcon(Material::create)
                    ->withToolTip("Add rule")
            )
        )
    ),
    verbOptions(verbOptions)
{}