#include "TestFramework.h"
#include "TestUtils.h"
#include "TestRenderUtils.h"

#include "ElectronicCircuit.h"
#include "ElectronicCircuitNode.h"

#include "BasicLogicGates.h"

TEST_CASE(TestElectronicCircuit, "circuits")
{
    TestRenderer renderer(800, 800);

    auto circuit = std::make_unique<ElectronicCircuit>();

    // Add three labelled terminals (two in, one out)
    auto input0 = std::make_unique<Terminal>(Terminal::TerminalType::INPUT, "p");
    auto input1 = std::make_unique<Terminal>(Terminal::TerminalType::INPUT, "q");
    auto input2 = std::make_unique<Terminal>(Terminal::TerminalType::INPUT, "r");

    auto output = std::make_unique<Terminal>(Terminal::TerminalType::OUTPUT, "s");

    // Add gates
    auto and_gate = std::make_unique<AndLogicGate>();
    auto or_gate = std::make_unique<OrLogicGate>();

    // Add wires
    auto wire0 = std::make_unique<Wire>(input0.get(), and_gate.get());
    auto wire1 = std::make_unique<Wire>(input1.get(), and_gate.get());

    auto wire2 = std::make_unique<Wire>(and_gate.get(), or_gate.get());
    auto wire3 = std::make_unique<Wire>(input2.get(), or_gate.get());

    auto wire4 = std::make_unique<Wire>(or_gate.get(), output.get());

    // Join wires
    and_gate->setInput0(wire0.get());
    and_gate->setInput1(wire1.get());
    and_gate->setOutput(wire2.get());

    or_gate->setInput0(wire2.get());
    or_gate->setInput1(wire3.get());
    or_gate->setOutput(wire4.get());

    input0->setConnection(wire0.get());
    input1->setConnection(wire1.get());
    input2->setConnection(wire3.get());
    output->setConnection(wire4.get());

    // Add to circuit
    circuit->addWire(std::move(wire0));
    circuit->addWire(std::move(wire1));
    circuit->addWire(std::move(wire2));
    circuit->addWire(std::move(wire3));
    circuit->addWire(std::move(wire4));

    circuit->addInputTerminal(std::move(input0));
    circuit->addInputTerminal(std::move(input1));
    circuit->addInputTerminal(std::move(input2));

    circuit->addOutputTerminal(std::move(output));
    
    circuit->addLogicGate(std::move(and_gate));
    circuit->addLogicGate(std::move(or_gate));
    
    auto circuit_node = std::make_unique<ElectronicCircuitNode>(Transform());

    circuit_node->setContent(circuit.get());

    renderer.getScene()->addNode(circuit_node.get());
    renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "circuit.svg");

    renderer.write(TestUtils::getTestOutputDir(__FILE__) / "circuit.png");
}
