#include "QuantumGateNode.h"

#include "RectangleNode.h"
#include "EquationNode.h"
#include "QuantumGate.h"

#include "LatexMathExpression.h"

QuantumGateNode::QuantumGateNode(const Transform& t)
    : QuantumCircuitElementNode(t)
{

}

QuantumGateNode::~QuantumGateNode()
{

}

void QuantumGateNode::setContent(QuantumGate* gate)
{
    mContent = gate;
    mContentDirty = true;
}

void QuantumGateNode::update(SceneInfo* sceneInfo)
{
    if (mContentDirty)
    {
        createOrUpdateGeometry(sceneInfo);
        mContentDirty = false;
    }
}

void QuantumGateNode::createOrUpdateGeometry(SceneInfo*)
{
    if (!mBody)
    {
        mBody = std::make_unique<RectangleNode>(Point(0, 0), mBodyWidth, mBodyHeight);
        addChild(mBody.get());
    }

    if (!mLabel)
    {
        mLabel = std::make_unique<EquationNode>(Point(mBodyWidth /3.0, mBodyHeight / 3.0));

        std::string label_content;
        if (mContent->getGateType() == QuantumGate::GateType::X)
        {
            label_content = "X";
        }
        else if (mContent->getGateType() == QuantumGate::GateType::Y)
        {
            label_content = "Y";
        }
        else if (mContent->getGateType() == QuantumGate::GateType::Z)
        {
            label_content = "Z";
        }
        else if (mContent->getGateType() == QuantumGate::GateType::H)
        {
            label_content = "H";
        }
        else
        {
            label_content = "U";
        }

        mLabelExpression = std::make_unique<LatexMathExpression>(label_content);
        mLabel->setContent(mLabelExpression.get());
        addChild(mLabel.get());
    }
}

Point QuantumGateNode::getConnectionLocation(AbstractQuantumWire* wire) const
{
    bool is_input{ false };
    //std::size_t connection_id{ 0 };

    for (std::size_t idx = 0; idx < mContent->getNumInputs(); idx++)
    {
        if (mContent->getInput(idx) == wire)
        {
            is_input = true;
            //connection_id = idx;
            break;
        }
    }

    for (std::size_t idx = 0; idx < mContent->getNumOutputs(); idx++)
    {
        if (mContent->getOutput(idx) == wire)
        {
            //connection_id = idx;
            break;
        }
    }

    Point loc;
    if (is_input)
    {
        loc = Point(0.0, mBodyHeight/2.0);
    }
    else
    {
        loc = Point(mBodyWidth, mBodyHeight / 2.0);
    }

    loc.move(mTransform.getLocation().getX(), mTransform.getLocation().getY());
    return loc;
}
