@implements IDisposable

@inject IJSRuntime JSRuntime

<polyline @ref="Ref" />


@code {
    [Parameter, EditorRequired]
    public EdgeModel Model { get; set; } = null!;

    private ElementReference Ref;

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

        await UpdatePathData();
        await UpdateMaker();
    }

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        bool updateLine = false;
        if (parameters.TryGetValue(nameof(Model), out EdgeModel? model))
        {
            if (((Model?.Id ?? Guid.Empty) != (model?.Id ?? Guid.Empty)))
            {
                if (Model != null)
                {
                    Model.StartNodePositionChanged -= UpdatePathData;
                    Model.EndNodePositionChanged -= UpdatePathData;
                    Model.ControlPoint1PositionChanged -= UpdatePathData;
                    Model.ControlPoint2PositionChanged -= UpdatePathData;
                    Model.DirectionChanged -= UpdateMaker;
                }

                if (model != null)
                {
                    model.StartNodePositionChanged += UpdatePathData;
                    model.EndNodePositionChanged += UpdatePathData;
                    model.ControlPoint1PositionChanged += UpdatePathData;
                    model.ControlPoint2PositionChanged += UpdatePathData;
                    model.DirectionChanged += UpdateMaker;
                    updateLine = true;
                }
            }
        }

        await base.SetParametersAsync(parameters);
        if (updateLine)
        {
            await UpdatePathData();
            await UpdateMaker();
        }
    }

    private async Task UpdatePathData()
    {
        string data = string.Empty;
        double sx = 0, sy = 0, mx = 0, my = 0, ex = 0, ey = 0;
        double sTime = 0.49, eTime = 0.5;


        if (Model.TrajectoryDegree == TrajectoryDegree.One)
        {
            sx = Model.X1;
            sy = Model.Y1;
            ex = Model.X2;
            ey = Model.Y2;
        }
        else if (Model.TrajectoryDegree == TrajectoryDegree.Two)
        {
            sx = (Model.X1 + Model.ControlPoint1X) / 2;
            sy = (Model.Y1 + Model.ControlPoint1Y) / 2;
            ex = (Model.X2 + Model.ControlPoint1X) / 2;
            ey = (Model.Y2 + Model.ControlPoint1Y) / 2;
        }
        else if (Model.TrajectoryDegree == TrajectoryDegree.Three)
        {
            sx = Math.Pow(1 - sTime, 3) * Model.X1 + 3 * Math.Pow(1 - sTime, 2) * sTime * Model.ControlPoint1X + 3 * Math.Pow(sTime, 2) * (1 - sTime) * Model.ControlPoint2X + Math.Pow(sTime, 3) * Model.X2;
            sy = Math.Pow(1 - sTime, 3) * Model.Y1 + 3 * Math.Pow(1 - sTime, 2) * sTime * Model.ControlPoint1Y + 3 * Math.Pow(sTime, 2) * (1 - sTime) * Model.ControlPoint2Y + Math.Pow(sTime, 3) * Model.Y2;

            ex = Math.Pow(1 - eTime, 3) * Model.X1 + 3 * Math.Pow(1 - eTime, 2) * eTime * Model.ControlPoint1X + 3 * Math.Pow(eTime, 2) * (1 - eTime) * Model.ControlPoint2X + Math.Pow(eTime, 3) * Model.X2;
            ey = Math.Pow(1 - eTime, 3) * Model.Y1 + 3 * Math.Pow(1 - eTime, 2) * eTime * Model.ControlPoint1Y + 3 * Math.Pow(eTime, 2) * (1 - eTime) * Model.ControlPoint2Y + Math.Pow(eTime, 3) * Model.Y2;
        }

        mx = (sx + ex) / 2;
        my = (sy + ey) / 2;

        await JSRuntime.InvokeVoidAsync("ElementSetAttribute", Ref, "points", $"{sx},{sy} {mx},{my} {ex},{ey}");
    }

    private async Task UpdateMaker()
    {
        if (Model == null) return;
        await JSRuntime.InvokeVoidAsync("ElementSetAttribute", Ref, "marker-mid", MapSvgDefs.GetMakerMid(Model.DirectionAllowed));
    }

    public void Dispose()
    {
        if (Model != null)
        {
            Model.StartNodePositionChanged -= UpdatePathData;
            Model.EndNodePositionChanged -= UpdatePathData;
            Model.ControlPoint1PositionChanged -= UpdatePathData;
            Model.ControlPoint2PositionChanged -= UpdatePathData;
            Model.DirectionChanged -= UpdateMaker;
        }
        GC.SuppressFinalize(this);
    }
}
