@using RadzenBlazorDemos.Models

@*
    Similar to DataGrid in-cell editing: click a cell to edit it,
    and changes are saved when you move to another cell.
*@

<RadzenGantt @ref="gantt"
             TItem="GanttTask"
             Data="@tasks"
             IdProperty="@nameof(GanttTask.Id)"
             ParentIdProperty="@nameof(GanttTask.ParentId)"
             TextProperty="@nameof(GanttTask.Name)"
             StartProperty="@nameof(GanttTask.Start)"
             EndProperty="@nameof(GanttTask.End)"
             ProgressProperty="@nameof(GanttTask.Progress)"
             EditMode="DataGridEditMode.Single"
             AllowFiltering="true"
             AllowPaging="true"
             PageSize="5"
             AllowSorting="true"
             CellClick="@OnCellClick"
             Sort="@(args => Reset())"
             Filter="@(args => Reset())"
             RowUpdate="@OnUpdateRow"
             RowHeightPx="42"
             Style="width: 100%; height: 520px;">
    <Columns>
        <RadzenGanttColumn Property="@nameof(GanttTask.Id)" Title="ID" Width="140px" Frozen="true" Filterable="false" />

        <RadzenGanttColumn TItem="GanttTask" Property="@nameof(GanttTask.Name)" Title="Task" Width="260px" IsInEditMode="@IsEditing">
            <Template Context="task">
                <RadzenText Text="@task.Name" />
            </Template>
            <EditTemplate Context="task">
                <RadzenTextBox @ref="editor" Change="@(args => Update())" @bind-Value="task.Name" Style="width:100%" aria-label="Edit task name" />
            </EditTemplate>
        </RadzenGanttColumn>

        <RadzenGanttColumn TItem="GanttTask" Property="@nameof(GanttTask.Start)" Title="Start" Width="160px" IsInEditMode="@IsEditing">
            <Template Context="task">
                <RadzenText Text="@(String.Format("{0:d}", task.Start))" />
            </Template>
            <EditTemplate Context="task">
                <RadzenDatePicker @ref="editor" Change="@(args => Update())" @bind-Value="task.Start" Style="width:100%" aria-label="Edit start date" />
            </EditTemplate>
        </RadzenGanttColumn>

        <RadzenGanttColumn TItem="GanttTask" Property="@nameof(GanttTask.End)" Title="End" Width="160px" IsInEditMode="@IsEditing">
            <Template Context="task">
                <RadzenText Text="@(String.Format("{0:d}", task.End))" />
            </Template>
            <EditTemplate Context="task">
                <RadzenDatePicker @ref="editor" Change="@(args => Update())" @bind-Value="task.End" Style="width:100%" aria-label="Edit end date" />
            </EditTemplate>
        </RadzenGanttColumn>

        <RadzenGanttColumn TItem="GanttTask" Property="@nameof(GanttTask.Progress)" Title="Progress" Width="140px" IsInEditMode="@IsEditing" CalculatedCssClass="@IsEdited">
            <Template Context="task">
                <RadzenText Text="@(String.Format("{0:P0}", (task.Progress ?? 0) / 100))" />
            </Template>
            <EditTemplate Context="task">
                <RadzenNumeric @ref="editor" Change="@((double? args) => Update())" @bind-Value="task.Progress" Min="0" Max="100" Step="5" Style="width:100%" aria-label="Edit progress" />
            </EditTemplate>
        </RadzenGanttColumn>
    </Columns>
</RadzenGantt>

<style>
    .table-cell-edited {
        position: relative;
    }

    .table-cell-edited::after {
        content: "";
        position: absolute;
        top: 0;
        right: 0;
        width: 0;
        height: 0;
        border-top: 10px solid red;
        border-left: 10px solid transparent;
    }
</style>

@code {
    RadzenGantt<GanttTask> gantt;
    string columnEditing;

    List<GanttTask> tasks = new();

    List<KeyValuePair<int, string>> editedFields = new();
    List<GanttTask> tasksToUpdate = new();

    protected override void OnInitialized()
    {
        base.OnInitialized();

        tasks = new()
        {
            new() { Id = 1, Name = "Project", Start = DateTime.Today.AddDays(-2), End = DateTime.Today.AddDays(30), Progress = 35 },
            new() { Id = 2, ParentId = 1, Name = "Discovery", Start = DateTime.Today.AddDays(-2), End = DateTime.Today.AddDays(5), Progress = 100 },
            new() { Id = 3, ParentId = 1, Name = "Implementation", Start = DateTime.Today.AddDays(6), End = DateTime.Today.AddDays(24), Progress = 25 },
            new() { Id = 4, ParentId = 3, Name = "API", Start = DateTime.Today.AddDays(6), End = DateTime.Today.AddDays(14), Progress = 60 },
            new() { Id = 5, ParentId = 3, Name = "UI", Start = DateTime.Today.AddDays(10), End = DateTime.Today.AddDays(22), Progress = 10 },
            new() { Id = 6, ParentId = 1, Name = "QA + Release", Start = DateTime.Today.AddDays(25), End = DateTime.Today.AddDays(30), Progress = 0 },
            new() { Id = 7, ParentId = 2, Name = "Stakeholder interviews", Start = DateTime.Today.AddDays(-2), End = DateTime.Today.AddDays(1), Progress = 100 },
            new() { Id = 8, ParentId = 2, Name = "Requirements", Start = DateTime.Today.AddDays(0), End = DateTime.Today.AddDays(4), Progress = 100 },
            new() { Id = 9, ParentId = 3, Name = "Architecture", Start = DateTime.Today.AddDays(6), End = DateTime.Today.AddDays(9), Progress = 40 },
            new() { Id = 10, ParentId = 4, Name = "Auth endpoints", Start = DateTime.Today.AddDays(6), End = DateTime.Today.AddDays(9), Progress = 80 },
            new() { Id = 11, ParentId = 4, Name = "Data contracts", Start = DateTime.Today.AddDays(8), End = DateTime.Today.AddDays(12), Progress = 50 },
            new() { Id = 12, ParentId = 4, Name = "Caching", Start = DateTime.Today.AddDays(11), End = DateTime.Today.AddDays(14), Progress = 20 },
            new() { Id = 13, ParentId = 5, Name = "Layout", Start = DateTime.Today.AddDays(10), End = DateTime.Today.AddDays(13), Progress = 60 },
            new() { Id = 14, ParentId = 5, Name = "Components", Start = DateTime.Today.AddDays(12), End = DateTime.Today.AddDays(18), Progress = 15 },
            new() { Id = 15, ParentId = 5, Name = "Theme polish", Start = DateTime.Today.AddDays(18), End = DateTime.Today.AddDays(22), Progress = 0 },
            new() { Id = 16, ParentId = 3, Name = "Integrations", Start = DateTime.Today.AddDays(14), End = DateTime.Today.AddDays(20), Progress = 10 },
            new() { Id = 17, ParentId = 16, Name = "Payments", Start = DateTime.Today.AddDays(14), End = DateTime.Today.AddDays(17), Progress = 5 },
            new() { Id = 18, ParentId = 16, Name = "Notifications", Start = DateTime.Today.AddDays(16), End = DateTime.Today.AddDays(20), Progress = 0 },
            new() { Id = 19, ParentId = 6, Name = "Test plan", Start = DateTime.Today.AddDays(25), End = DateTime.Today.AddDays(26), Progress = 0 },
            new() { Id = 20, ParentId = 6, Name = "Regression", Start = DateTime.Today.AddDays(26), End = DateTime.Today.AddDays(29), Progress = 0 },
            new() { Id = 21, ParentId = 6, Name = "Release", Start = DateTime.Today.AddDays(29), End = DateTime.Today.AddDays(30), Progress = 0 },
        };
    }

    bool IsEditing(string columnName, GanttTask task)
    {
        return columnEditing == columnName && tasksToUpdate.Contains(task);
    }

    string IsEdited(RadzenDataGridColumn<GanttTask> column, GanttTask task)
    {
        return editedFields.Any(c => c.Key == task.Id && c.Value == column.Property)
            ? "table-cell-edited"
            : string.Empty;
    }

    async Task OnCellClick(DataGridCellMouseEventArgs<GanttTask> args)
    {
        if (!gantt.IsValid ||
            (tasksToUpdate.Contains(args.Data) && columnEditing == args.Column.Property)) return;

        if (tasksToUpdate.Any())
        {
            await Update();
        }

        columnEditing = args.Column.Property;
        await EditRow(args.Data);
    }

    void Reset(GanttTask task = null)
    {
        editorFocused = false;

        if (task != null)
        {
            tasksToUpdate.Remove(task);
        }
        else
        {
            tasksToUpdate.Clear();
        }
    }

    async Task Update()
    {
        editorFocused = false;

        if (tasksToUpdate.Any())
        {
            editedFields.Add(new(tasksToUpdate.First().Id, columnEditing));
            await gantt.UpdateRow(tasksToUpdate.First());
        }
    }

    async Task EditRow(GanttTask task)
    {
        Reset();
        tasksToUpdate.Add(task);
        await gantt.EditRow(task);
    }

    void OnUpdateRow(GanttTask task)
    {
        Reset(task);
    }

    IRadzenFormComponent editor;
    bool editorFocused;

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

        if (firstRender)
        {
            await gantt.ExpandRows(tasks);
        }

        if (!editorFocused && editor != null)
        {
            editorFocused = true;

            try
            {
                await editor.FocusAsync();
            }
            catch
            {
                // ignore focus errors
            }
        }
    }
}
