@namespace Connected.Components
@inherits UIComponent
@typeparam T
@using Connected.Utilities

<CascadingValue IsFixed="true" Value="this">@Columns</CascadingValue>

<CascadingValue IsFixed="true" Value="this">
    <div @attributes="CustomAttributes" class="@_classname" style="@_style">
        @if (Items != null || ServerData != null)
        {
            @if (ToolBarContent != null)
            {
                <ToolBar Class="table-toolbar">
                    @ToolBarContent
                    @if (ShowMenuIcon)
                    {
                        @ToolbarMenu(this)   
                    }
                </ToolBar>
            }
            else
            {
                @if (ShowMenuIcon)
                {
                    @*Add the default toolbar.*@
                    <ToolBar Class="table-toolbar">
                    <Spacer />
                    @ToolbarMenu(this) 
                    </ToolBar>
                 }
            }
            <div @ref=_gridElement class="@_tableClass" style="@_tableStyle">
                <table class="table-root">
                    @if (ColGroup != null)
                    {
                        <colgroup>
                            @ColGroup
                        </colgroup>
                    }
                    <thead class="@_headClassname">
                        <CascadingValue Name="IsOnlyHeader" IsFixed="true" Value="true">
                            @Header
                        </CascadingValue>
                        <tr class="table-row">
                            @foreach (var column in RenderedColumns)
                            {
                                <HeaderCell SortDirection="@(GetColumnSortDirection(column.Field))" T="T" Column="@column"></HeaderCell>
                            }
                        </tr>
                        @if (_filtersMenuVisible && FilterMode == DataGridFilterMode.Simple)
                        {
                            <Overlay Visible="true" OnClick="@(() => _filtersMenuVisible = false)"></Overlay>
                            <Paper Class="pa-2 filters-panel" Style="position:absolute;width:auto;min-width:700px;z-index:var(--mud-zindex-drawer)" Elevation="4">
                                @if (FilterTemplate == null)
                                { 
                                    <Grid Spacing="0">
                                        @foreach (var f in FilterDefinitions)
                                        {
                                            @Filter(f, null)
                                        }
                                    </Grid>
                           <Button Class="mt-2" StartIcon="@Icons.Material.Filled.Add" Clicked="@AddFilter" Color="@ThemeColor.Primary">Add Filter</Button>
                                    @if (ServerData != null)
                                    {
                                        <Button Class="mt-2" StartIcon="@Icons.Material.Filled.Add" OnClick="@ApplyFilters" Color="@ThemeColor.Primary">Apply</Button>
                                    }
                                    <Button Class="mt-2" StartIcon="@Icons.Material.Filled.Remove" OnClick="@ClearFilters" Color="@ThemeColor.Primary">Clear</Button>
                                }
                                else
                                {
                                    @FilterTemplate(FilterDefinitions)
                                }
                            </Paper>
                        }
                        @if (_columnsPanelVisible)
                        {
                            <Overlay  Visible="true" OnClick="@(() => _columnsPanelVisible = false)"></Overlay>
                            <Paper Class="pa-2 columns-panel" Style="position:absolute;max-width:450px;z-index:var(--mud-zindex-drawer)" Elevation="4">
                                <Grid Spacing="0">
                                    @foreach (var column in RenderedColumns)
                                    {
                                        <Item xs="12">
                                            <Switch T="bool" Disabled="@(!(column.Hideable ?? false))" Checked="@column.Hidden" CheckedChanged="@column.ToggleAsync" Converter="_oppositeBoolConverter" Color="ThemeColor.Primary" Label="@(column.Title ?? @column.Field)" />
                                        </Item>
                                    }
                                    <Item xs="6">
                                        <Button OnClick="@HideAllColumnsAsync" Color="@ThemeColor.Primary">Hide All</Button>
                                    </Item>
                                    <Item xs="6" Class="d-flex justify-end">
                                        <Button OnClick="@ShowAllColumnsAsync" Color="@ThemeColor.Primary">Show All</Button>
                                    </Item>
                                </Grid>
                                
                            </Paper>
                        }
                        @if (Filterable && FilterMode == DataGridFilterMode.ColumnFilterRow)
                        {
                            <tr class="table-row">
                                @foreach (var column in RenderedColumns)
                                {
                                    <FilterHeaderCell T="T" Column="@column" />
                                }
                            </tr>
                        }
                    </thead>
                    <tbody class="table-body">
                        @if (Loading)
                        {
                            <tr>
                                <td colspan="1000" class="table-loading">
                                    <ProgressLinear Color="@LoadingProgressColor" Class="table-loading-progress" Indeterminate="true" />
                                </td>
                            </tr>
                        }

                        @{var resolvedPageItems = CurrentPageItems.ToList();}
                        @if (resolvedPageItems != null && resolvedPageItems.Count > 0)
                        {
                            if (GroupedColumn != null)
                            {
                                foreach (var g in _groups)
                                {
                                    <tr class="table-row">
                                        @{ var groupClass = new CssBuilder(GroupClass).AddClass(GroupClassFunc?.Invoke(g)).Build(); }
                                        @{ var groupStyle = new StyleBuilder().AddStyle(GroupStyle).AddStyle(GroupStyleFunc?.Invoke(g)).Build(); }

                                        <td class="table-cell @groupClass" colspan="1000" style="background-color:var(--mud-palette-background-grey);@groupStyle">
                                            <IconButton 
                                                Class="table-row-expander" 
                                                Icon="@(g.IsExpanded ? Icons.Material.Filled.ExpandMore : Icons.Material.Filled.ChevronRight)" 
                                                OnClick="@(() => ToggleGroupExpansion(g))" />

                                            @if (GroupedColumn.GroupTemplate == null)
                                            {
                                                <span style="font-weight:bold">@GroupedColumn.computedTitle: @g.Grouping.Key</span>
                                            }
                                            else
                                            {
                                                @GroupedColumn.GroupTemplate(@g)
                                            }
                                        </td>
                                    </tr>
                                    var rowIndex = 0;

                                    @if (g.IsExpanded)
                                    {
                                        <Virtualize IsEnabled="@Virtualize" Items="@g.Grouping.ToList()" OverscanCount=@OverscanCount Context="item">
                                            @{ var rowClass = new CssBuilder(RowClass).AddClass(RowClassFunc?.Invoke(item, rowIndex)).Build(); }
                                            @{ var rowStyle = new StyleBuilder().AddStyle(RowStyle).AddStyle(RowStyleFunc?.Invoke(item, rowIndex)).Build(); }
                                            @{ var tmpRowIndex = rowIndex; }
                                            <tr class="table-row @rowClass" Style="@rowStyle" @key="item" @onclick="@((args) => OnRowClickedAsync(args, item, tmpRowIndex))">  
                                                <CascadingValue Value="@Validator" IsFixed="true">
                                                @foreach (var column in RenderedColumns)
                                                {
                                                    if (!column.Hidden)
                                                    {
                                                        @Cell(column, item)
                                                    }
                                                }                                     
                                                </CascadingValue>
                                            </tr>                                   
                                            @if (ChildRowContent != null && (_openHierarchies.Contains(item) || !hasHierarchyColumn))
                                            {
                                                <tr class="table-row">
                                                    <td class="table-cell" colspan="1000">
                                                        @ChildRowContent(new CellContext<T>(this, item))
                                                    </td>
                                                </tr>
                                            }                                       
                                            @{ rowIndex++; }
                                        </Virtualize>
                                        @*Group Footer*@
                                        <tr class="table-row">
                                            @FooterCells(g.Grouping.ToList())
                                        </tr>
                                    }
                                }
                            }
                            else
                            {
                                var rowIndex = 0;
                                <Virtualize IsEnabled="@Virtualize" Items="@resolvedPageItems" OverscanCount=@OverscanCount Context="item">
                                    @{ var rowClass = new CssBuilder(RowClass).AddClass(RowClassFunc?.Invoke(item, rowIndex)).Build(); }
                                    @{ var rowStyle = new StyleBuilder().AddStyle(RowStyle).AddStyle(RowStyleFunc?.Invoke(item, rowIndex)).Build(); }
                                    @{ var tmpRowIndex = rowIndex; }
                                    <tr class="table-row @rowClass" Style="@rowStyle" @key="item" @onclick="@((args) => OnRowClickedAsync(args, item, tmpRowIndex))">  
                                        <CascadingValue Value="@Validator" IsFixed="true">
                                        @foreach (var column in RenderedColumns)
                                        {
                                            if (!column.Hidden)
                                            {
                                                @Cell(column, item)
                                            }
                                        }                                       
                                        </CascadingValue>
                                    </tr>                                   
                                    @if (ChildRowContent != null && (_openHierarchies.Contains(item) || !hasHierarchyColumn))
                                    {
                                        <tr class="table-row">
                                            <td class="table-cell" colspan="1000">
                                                @ChildRowContent(new CellContext<T>(this, item))
                                            </td>
                                        </tr>
                                    }                                        
                                    @{ rowIndex++; }
                                </Virtualize>
                            }
                        }
                        else if(Loading ? LoadingContent != null : NoRecordsContent != null)
                        {
                            <tr>
                                <th colspan="1000" class="table-empty-row">
                                    <div Class="my-3">
                                        @if(Loading)
                                        {
                                            @LoadingContent
                                        }
                                        else
                                        {
                                            @NoRecordsContent
                                        }
                                    </div>
                                </th>
                            </tr>
                        }
                    </tbody>
                    <tfoot class="@_footClassname">
                        <tr class="table-row">
                            @FooterCells(resolvedPageItems)
                        </tr>
                    </tfoot>
                </table>
            </div>
            @if (PagerContent != null)
            {
                <div class="table-pagination">
                    @PagerContent
                </div>
            }
        }
    </div>
    <Dialog @bind-IsVisible="isEditFormOpen" Options="EditDialogOptions">
        <TitleContent>
            <Text Typo="Typo.h6">
                Edit
            </Text>
        </TitleContent>
        <DialogContent>
            <Form FieldChanged="FormFieldChanged">
                @foreach (var column in RenderedColumns)
                {
                    var cell = new Cell<T>(this, column, _editingItem);

                    if (column.EditTemplate != null)
                    {
                        @column.EditTemplate(cell.cellContext)
                    }
                    else
                    {
                        if (column.dataType == typeof(string))
                        {
                            <TextField T="string" Label="@column.computedTitle" Value="@cell.valueString" ValueChanged="@cell.StringValueChangedAsync" Margin="@Margin.Dense"
                                Required="true" Variant="@Variant.Outlined" Disabled="@(!column.IsEditable || ReadOnly)" Class="mt-4" />
                        }
                        else if (column.isNumber)
                        {
                            <NumericField T="double?" Label="@column.computedTitle" Value="@cell.valueNumber" ValueChanged="@cell.NumberValueChangedAsync" Margin="@Margin.Dense"
                                Required="true" Variant="@Variant.Outlined" Disabled="@(!column.IsEditable || ReadOnly)" Class="mt-4" />
                        }
                    }
                }
            </Form>
        </DialogContent>
        <DialogActions>
            <Button Variant="Variant.Filled" Color="ThemeColor.Default" Clicked="@CancelEditingItemAsync" Class="px-10">Cancel</Button>
         <Button Variant="Variant.Filled" Color="ThemeColor.Primary" Clicked="@CommitItemChangesAsync" Class="px-10">Save</Button>
        </DialogActions>
    </Dialog>
</CascadingValue>

@code {
    internal RenderFragment ToolbarMenu(DataGrid<T> __this)
    {
        return
        @<text>
        <Menu Icon="@Icons.Material.Outlined.Settings" Size="Size.Small" AnchorOrigin="Origin.BottomCenter" Dense="true">
            <MenuItem OnClick="@__this.ShowColumnsPanel">Columns</MenuItem>
            @if (__this.Groupable)
            {
                <MenuItem OnClick="@__this.ExpandAllGroups">Expand All Groups</MenuItem>
                <MenuItem OnClick="@__this.CollapseAllGroups">Collapse All Groups</MenuItem>
            }
            @if(__this.ServerData != null)
            {
                <MenuItem OnClick="@__this.InvokeServerLoadFunc">Refresh Data</MenuItem>
            }
        </Menu>
        </text>;
    }

    internal RenderFragment FooterCells(IEnumerable<T> currentItems)
    {
        return
        @<text>
        @if (currentItems != null)
        {
            foreach (var column in RenderedColumns)
            {
                if (!column.Hidden)
                {
                    if (column.AggregateDefinition != null || column.FooterTemplate != null || hasFooter)
                    {
                        <FooterCell T="T" Column="@column" CurrentItems="@currentItems"></FooterCell>
                    }
                }
            }
        }
        </text>;
    }

    internal RenderFragment Cell(Column<T> column, T item)
    {
        return
        @<text>
        @{
            var cell = new Cell<T>(this, column, item);
        }
        <td data-label="@column.computedTitle" class="@cell.computedClass" style="@cell.computedStyle">
            @if (column.IsEditable && !ReadOnly && DataGridEditMode.Cell == EditMode)
            {
                if (column.EditTemplate != null)
                {
                    @column.EditTemplate(cell.cellContext)
                }
                else
                {
                    if (column.dataType == typeof(string))
                    {
                        <TextField T="string" Value="@cell.valueString" ValueChanged="@cell.StringValueChangedAsync" Margin="@Margin.Dense" Style="margin-top:0"
                            Required="true" Variant="@Variant.Text" />
                    }
                    else if (column.isNumber)
                    {
                        <NumericField T="double?" Value="@cell.valueNumber" ValueChanged="@cell.NumberValueChangedAsync" Margin="@Margin.Dense" Style="margin-top:0"
                            Required="true" Variant="@Variant.Text" Culture="@column.Culture" />
                    }
                }
            }
            else
            {
                if (column.CellTemplate != null)
                {
                    @column.CellTemplate(cell.cellContext)
                }
                else if (column.Culture != null && column.isNumber)
                {
                    @cell.valueNumber?.ToString(column.Culture)
                }
                else
                {
                    @cell.ComputedValue
                }
            }
        </td>
        </text>
    ;
    }

    internal RenderFragment Filter(FilterDefinition<T> f, Column<T> column)
    {
        return
        @<text>
        @{
            var filter = new Filter<T>(this, f, column);
        }
        @if (column == null)
        {
            <Item xs="1" Class="d-flex">
                <IconButton Class="remove-filter-button" Icon="@Icons.Material.Filled.Close" OnClick="@filter.RemoveFilter" Size="@Size.Small" Style="align-self:flex-end"></IconButton>
            </Item>
            <Item xs="4">
                <Select T="string" Value="@f.Field" ValueChanged="@filter.FieldChanged" FullWidth="true" Label="Column" Dense="true" Margin="@Margin.Dense"
                    Class="filter-field">
                    @foreach (var column in RenderedColumns ?? Enumerable.Empty<Column<T>>())
                    {
                        <SelectItem Value="@column.Field">@column.computedTitle</SelectItem>
                    }
                </Select>
            </Item>
            <Item xs="3">
                <Select @bind-Value="f.Operator" FullWidth="true" Label="Operator" Dense="true" Margin="@Margin.Dense"
                    Class="filter-operator">
                    @foreach (var o in FilterOperator.GetOperatorByDataType(filter.dataType))
                    {
                        <MudSelectItem Value="@o">@o</MudSelectItem>
                    }
                </Select>
            </Item>
            <Item xs="4">
                @if (filter.dataType == typeof(string) && !(f.Operator ?? "").EndsWith("empty"))
                {
                    <TextField T="string" Value="@filter._valueString" ValueChanged="@filter.StringValueChanged" FullWidth="true" Label="Value" Placeholder="Filter value" Margin="@Margin.Dense" 
                        Immediate="true" Class="filter-input" />
                }
                else if (filter.isNumber && !(f.Operator ?? "").EndsWith("empty"))
                {
                    <NumericField T="double?" Value="@filter._valueNumber" ValueChanged="@filter.NumberValueChanged" FullWidth="true" Label="Value" Placeholder="Filter value" Margin="@Margin.Dense" 
                    Immediate="true" Class="filter-input" Culture="@filter.filterColumn?.Culture" />
                }
                else if (filter.isEnum)
                {
                    <Select T="Enum" Value="@filter._valueEnum" ValueChanged="@filter.EnumValueChanged" FullWidth="true" Dense="true" Margin="@Margin.Dense"
                        Class="filter-input">
                        <SelectItem T="Enum" Value="@(null)"></SelectItem>
                        @foreach (var item in Enum.GetValues(filter.dataType))
                        {
                            <SelectItem T="Enum" Value="@((Enum)item)">@item</SelectItem>
                        }
                    </Select>
                }
                else if (filter.dataType == typeof(bool))
                {
                    <Select T="bool?" Value="@filter._valueBool" ValueChanged="@filter.BoolValueChanged" FullWidth="true" Dense="true" Margin="@Margin.Dense"
                        Class="filter-input">
                        <SelectItem T="bool?" Value="@(null)"></SelectItem>
                        <SelectItem T="bool?" Value="@(true)">true</SelectItem>
                        <SelectItem T="bool?" Value="@(false)">false</SelectItem>
                    </Select>
                }
                else if (filter.dataType == typeof(DateTime) && !(f.Operator ?? "").EndsWith("empty"))
                {
                    <Grid Spacing="0">
                        <Item xs="7">
                            <DatePicker Date="@filter._valueDate" DateChanged="@filter.DateValueChanged" Margin="@Margin.Dense" Class="filter-input-date" />
                        </Item>
                        <Item xs="5">
                            <TimePicker Time="@filter._valueTime" TimeChanged="@filter.TimeValueChanged" Margin="@Margin.Dense" Class="filter-input-time" />
                        </Item>
                    </Grid>
                }
                else if (filter.dataType == typeof(Guid))
                {
                    <TextField T="string" Value="@filter._valueString" ValueChanged="@filter.StringValueChanged" FullWidth="true" Label="Value" Placeholder="Filter value" Margin="@Margin.Dense" 
                        Immediate="true" Class="filter-input" />
                }
            </Item>
        }
        else 
        {
            <Item xs="12">
                <Select @bind-Value="f.Operator" FullWidth="true" Dense="true" Margin="@Margin.Dense"
                    Class="filter-operator">
                    @foreach (var o in FilterOperator.GetOperatorByDataType(filter.dataType))
                    {
                        <SelectItem Value="@o">@o</SelectItem>
                    }
                </Select>
            </Item>
            <Item xs="12">
                @if (filter.dataType == typeof(string) && !(f.Operator ?? "").EndsWith("empty"))
                {
                    <TextField T="string" Value="@filter._valueString" ValueChanged="@filter.StringValueChanged" FullWidth="true" Placeholder="Filter value" Margin="@Margin.Dense" 
                    Immediate="true" Class="filter-input" />
                }
                else if (filter.isNumber && !(f.Operator ?? "").EndsWith("empty"))
                {
                    <NumericField T="double?" Value="@filter._valueNumber" ValueChanged="@filter.NumberValueChanged" FullWidth="true" Placeholder="Filter value" Margin="@Margin.Dense" 
                        Immediate="true" Class="filter-input" Culture="@filter.filterColumn?.Culture" />
                }
                else if (filter.isEnum)
                {
                    <Select T="Enum" Value="@filter._valueEnum" ValueChanged="@filter.EnumValueChanged" FullWidth="true" Dense="true" Margin="@Margin.Dense"
                        Class="filter-input">
                        <SelectItem T="Enum" Value="@(null)"></SelectItem>
                        @foreach (var item in Enum.GetValues(filter.dataType))
                        {
                            <SelectItem T="Enum" Value="@((Enum)item)">@item</SelectItem>
                        }
                    </Select>
                }
                else if (filter.dataType == typeof(bool))
                {
                    <Select T="bool?" Value="@filter._valueBool" ValueChanged="@filter.BoolValueChanged" FullWidth="true" Dense="true" Margin="@Margin.Dense"
                        Class="filter-input">
                        <SelectItem T="bool?" Value="@(null)"></SelectItem>
                        <SelectItem T="bool?" Value="@(true)">true</SelectItem>
                        <SelectItem T="bool?" Value="@(false)">false</SelectItem>
                    </Select>
                }
                else if (filter.dataType == typeof(DateTime) && !(f.Operator ?? "").EndsWith("empty"))
                {
                    <Grid Spacing="0">
                        <Item xs="7">
                            <DatePicker Date="@filter._valueDate" DateChanged="@filter.DateValueChanged" Margin="@Margin.Dense" Class="filter-input-date" />
                        </Item>
                        <Item xs="5">
                            <TimePicker Time="@filter._valueTime" TimeChanged="@filter.TimeValueChanged" Margin="@Margin.Dense" Class="filter-input-time" />
                        </Item>
                    </Grid>
                }
                else if (filter.dataType == typeof(Guid))
                {
                    <TextField T="string" Value="@filter._valueString" ValueChanged="@filter.StringValueChanged" FullWidth="true" Label="Value" Placeholder="Filter value" Margin="@Margin.Dense" 
                        Immediate="true" Class="filter-input" />
                }
            </Item>
        }
        </text>
    ;
    }
}