@inject IJSRuntime JSRuntime
@implements IDisposable

<g visibility="@Visibility">
    <path d="@EdgeData" />
    <line x1="@X1" y1="@Y1" x2="@CX1" y2="@CY1"/>
    <line x1="@CX1" y1="@CY1" x2="@X2" y2="@Y2" />
    <circle @ref="CP1Ref" cx="@CX1" cy="@CY1" />
</g>

<g visibility="@ControlPoint2Visibility">
    <line x1="@X1" y1="@Y1" x2="@CX2" y2="@CY2" />
    <line x1="@CX2" y1="@CY2" x2="@X2" y2="@Y2" />
    <circle @ref="CP2Ref" cx="@CX2" cy="@CY2" />
</g>

@code {
    private ElementReference CP1Ref;
    private ElementReference CP2Ref;
    private DotNetObjectReference<EdgeControlPoint> DotNetObj = null!;

    private double X1;
    private double Y1;
    private double CX1;
    private double CY1;
    private double CX2;
    private double CY2;
    private double X2;
    private double Y2;
    private string EdgeData = "";
    private EdgeModel? Model;
    private string Visibility = "hidden";

    private string ControlPoint2Visibility = "hidden";

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);
        if (!firstRender) return;

        DotNetObj = DotNetObjectReference.Create(this);
        await JSRuntime.InvokeVoidAsync("AddMouseDownEventListener", DotNetObj, CP1Ref, nameof(OnMouseDown1), false);
        await JSRuntime.InvokeVoidAsync("AddMouseDownEventListener", DotNetObj, CP2Ref, nameof(OnMouseDown2), false);
    }

    public void SetControl(EdgeModel? model)
    {
        if (Model != null)
        {
            Model.StartNodePositionChanged -= CaculatePath;
            Model.EndNodePositionChanged -= CaculatePath;
            Model.ControlPoint1PositionChanged -= CaculatePath;
            Model.ControlPoint2PositionChanged -= CaculatePath;
        }

        Model = model;
        if (Model != null)
        {
            Visibility = "visible";
            if (Model.TrajectoryDegree == TrajectoryDegree.Three) ControlPoint2Visibility = "visible";
            CaculatePath();

            Model.StartNodePositionChanged += CaculatePath;
            Model.EndNodePositionChanged += CaculatePath;
            Model.ControlPoint1PositionChanged += CaculatePath;
            Model.ControlPoint2PositionChanged += CaculatePath;
            if (Model.TrajectoryDegree == TrajectoryDegree.Three) ControlPoint2Visibility = "visible";
            else ControlPoint2Visibility = "hidden";
            Visibility = "visible";
        }
        else
        {
            Visibility = "hidden";
            ControlPoint2Visibility = "hidden";
        }
        StateHasChanged();
    }

    private Task CaculatePath()
    {
        if (Model == null) return Task.CompletedTask;

        X1 = Model.X1;
        Y1 = Model.Y1;
        X2 = Model.X2;
        Y2 = Model.Y2;
        CX1 = Model.ControlPoint1X;
        CY1 = Model.ControlPoint1Y;
        CX2 = Model.ControlPoint2X;
        CY2 = Model.ControlPoint2Y;
        StateHasChanged();
        return Task.CompletedTask;
    }

    [JSInvokable]
    public void OnMouseDown1(int button, bool altKey, bool ctrlKey, bool shiftKey)
    {
        if (Model != null)
        {
            Model.ActivedControlPoint1 = true;
            Model.ActivedControlPoint2 = false;
        }
    }

    [JSInvokable]
    public void OnMouseDown2(int button, bool altKey, bool ctrlKey, bool shiftKey)
    {
        if (Model != null)
        {
            Model.ActivedControlPoint2 = true;
            Model.ActivedControlPoint1 = false;
        }
    }

    public void Dispose()
    {
        if (Model != null)
        {
            Model.StartNodePositionChanged -= CaculatePath;
            Model.EndNodePositionChanged -= CaculatePath;
            Model.ControlPoint1PositionChanged -= CaculatePath;
            Model.ControlPoint2PositionChanged -= CaculatePath;
            Model = null;
        }

        GC.SuppressFinalize(this);
    }
}
