using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Controls;
using InABox.Core;

namespace InABox.DynamicGrid;


public abstract class DynamicColumnBase : BaseObject, IDynamicColumnBase
{
    public void DoEntityChanged(string columnname, Dictionary<string,object?> changes)
    {
        EntityChanged?.Invoke(this, new DynamicColumnEntityChangedEventArgs(columnname, changes));
    }

    public event DynamicColumnEntityChangedEvent? EntityChanged;
    
    public object? Tag { get; set;
		}
}

public enum DynamicGridOption
{
    AddRows,
    EditRows,
    DeleteRows,
    FilterRows,
    SelectColumns,
    ExportData,
    ImportData,
    MultiSelect,
    DragSource,
    DragTarget,
    DirectEdit,
    ShowHelp,
    Print,
    RecordCount,
    HideDatabaseFilters,
    HideDirectEditButton
}
public class DynamicGridOptions
{
    public event Action? OnChanged;

    private int _enabled = 0;
    private bool _changed = false;

    public bool Enabled
    {
        get => _enabled == 0;
        set
        {
            if (value)
                EndUpdate();
            else
                BeginUpdate();
        }
    }

    public DynamicGridOptions Clear()
    {
		BeginUpdate();
        AddRows = false;
        EditRows = false;
        DeleteRows = false;
        FilterRows = false;
        SelectColumns = false;
        ExportData = false;
        ImportData = false;
        MultiSelect = false;
        DragSource = false;
        DragTarget = false;
        DirectEdit = false;
        ShowHelp = false;
        Print = false;
        RecordCount = false;
        HideDatabaseFilters = false;
        HideDirectEditButton = false;
        return EndUpdate();
    }

    public DynamicGridOptions BeginUpdate()
    {
        ++_enabled;
        return this;
    }

    private DynamicGridOptions Changed()
    {
        if (_enabled == 0)
        {
            _changed = false;
            OnChanged?.Invoke();
        }
        else
        {
            _changed = true;
        }
        return this;
    }

    public DynamicGridOptions EndUpdate()
    {
        --_enabled;
        if(_changed)
        {
            Changed();
        }
        return this;
    }

    private bool _addRows;
    public bool AddRows
	{
		get => _addRows;
		set
		{
			if(_addRows != value)
			{
				_addRows = value;
				Changed();
			}
		}
	}
    private bool _editRows;
    public bool EditRows
	{
		get => _editRows;
		set
		{
			if(_editRows != value)
			{
				_editRows = value;
				Changed();
			}
		}
	}
    private bool _deleteRows;
    public bool DeleteRows
	{
		get => _deleteRows;
		set
		{
			if(_deleteRows != value)
			{
				_deleteRows = value;
				Changed();
			}
		}
	}
    private bool _filterRows;
    public bool FilterRows
	{
		get => _filterRows;
		set
		{
			if(_filterRows != value)
			{
				_filterRows = value;
				Changed();
			}
		}
	}
    private bool _selectColumns;
    public bool SelectColumns
	{
		get => _selectColumns;
		set
		{
			if(_selectColumns != value)
			{
				_selectColumns = value;
				Changed();
			}
		}
	}
    private bool _exportData;
    public bool ExportData
	{
		get => _exportData;
		set
		{
			if(_exportData != value)
			{
				_exportData = value;
				Changed();
			}
		}
	}
    private bool _importData;
    public bool ImportData
	{
		get => _importData;
		set
		{
			if(_importData != value)
			{
				_importData = value;
				Changed();
			}
		}
	}
    private bool _multiSelect;
    public bool MultiSelect
	{
		get => _multiSelect;
		set
		{
			if(_multiSelect != value)
			{
				_multiSelect = value;
				Changed();
			}
		}
	}
    private bool _dragSource;
    public bool DragSource
	{
		get => _dragSource;
		set
		{
			if(_dragSource != value)
			{
				_dragSource = value;
				Changed();
			}
		}
	}
    private bool _dragTarget;
    public bool DragTarget
	{
		get => _dragTarget;
		set
		{
			if(_dragTarget != value)
			{
				_dragTarget = value;
				Changed();
			}
		}
	}
    private bool _directEdit;
    public bool DirectEdit
	{
		get => _directEdit;
		set
		{
			if(_directEdit != value)
			{
				_directEdit = value;
				Changed();
			}
		}
	}
    private bool _showHelp;
    public bool ShowHelp
	{
		get => _showHelp;
		set
		{
			if(_showHelp != value)
			{
				_showHelp = value;
				Changed();
			}
		}
	}
    private bool _print;
    public bool Print
	{
		get => _print;
		set
		{
			if(_print != value)
			{
				_print = value;
				Changed();
			}
		}
	}
    private bool _recordCount;
    public bool RecordCount
	{
		get => _recordCount;
		set
		{
			if(_recordCount != value)
			{
				_recordCount = value;
				Changed();
			}
		}
	}
    private bool _hideDatabaseFilters;
    public bool HideDatabaseFilters
	{
		get => _hideDatabaseFilters;
		set
		{
			if(_hideDatabaseFilters != value)
			{
				_hideDatabaseFilters = value;
				Changed();
			}
		}
	}
    private bool _hideDirectEditButton;
    public bool HideDirectEditButton
	{
		get => _hideDirectEditButton;
		set
		{
			if(_hideDirectEditButton != value)
			{
				_hideDirectEditButton = value;
				Changed();
			}
		}
	}
}

public delegate bool OnFilterRecord(CoreRow row);

public delegate void OnCreateItem(object sender, BaseObject item);

public delegate bool OnAfterCreateItem(object sender, BaseObject item);

public delegate T OnCreateItem<T>();

public delegate void OnDefineLookup(ILookupEditorControl editor);

public delegate void OnGridCustomiseEditor(DynamicEditorGrid sender, DynamicGridColumn column, BaseEditor editor);

public delegate void OnFormCustomiseEditor(IDynamicEditorForm sender, object[] items, DynamicGridColumn column, BaseEditor editor);

public delegate void ValidateEvent<T>(DynamicGrid<T> sender, T[] items, List<string> errors)
	where T : BaseObject, new();

/// <summary>
/// 
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sender"></param>
/// <param name="items">The array of items being edited; <see langword="null"/> is synonymous with an empty array.</param>
/// <param name="column"></param>
/// <param name="editor"></param>
public delegate void OnCustomiseEditor<T>(IDynamicEditorForm sender, T[]? items, DynamicGridColumn column, BaseEditor editor);

public delegate void OnLoadEditorButtons<T>(T item, DynamicEditorButtons buttons);

public delegate void OnReconfigureEditors(DynamicEditorGrid sender);

public class AfterEditorValueChangedArgs
{
    public string ColumnName { get; set; }

    public Dictionary<string, object?> ChangedValues { get; set; }

    public AfterEditorValueChangedArgs(string columnName, Dictionary<string, object?> changedValues)
    {
        ColumnName = columnName;
        ChangedValues = changedValues;
    }
}

public delegate Dictionary<string, object?>? OnAfterEditorValueChanged(DynamicEditorGrid sender, AfterEditorValueChangedArgs args);

//public delegate void OnGridChanged(IDynamicGrid sender);

public delegate void OnLoadPage(IDynamicEditorPage page);

public delegate void OnSelectPage(DynamicEditorGrid sender, BaseObject[]? items);

public delegate void OnUnloadPage(IDynamicEditorPage page, bool saved);

public delegate void OnCustomiseColumns(object sender, DynamicGridColumns columns);

public delegate BaseEditor? OnGetEditor(DynamicGridColumn column);

public delegate decimal OnGetEditorSequence(DynamicGridColumn column);

public delegate IFilter? OnDefineLookupFilter(Type type, string column);

public delegate IFilter? OnDefineFilter(Type type);

public delegate IList<string>? OnValidateData(IDynamicEditorForm sender, BaseObject[] items);

public delegate void OnPrintData(object sender);

public delegate void EntitySaveEvent(IDynamicEditorForm editor, BaseObject[] items);

public delegate bool DynamicGridButtonClickEvent(Button button, CoreRow[] rows);

public delegate void OnContextMenuOpening(CoreTreeNode? node, ContextMenu menu);


public class DynamicGridSelectionEventArgs : CancelEventArgs
{
    public DynamicGridSelectionEventArgs(CoreRow[]? rows)
    {
        Rows = rows;
    }

    public CoreRow[]? Rows { get; }
}

public delegate void SelectItemHandler(object sender, DynamicGridSelectionEventArgs e);

public delegate void OnDoubleClick(object sender, HandledEventArgs args);

public class DynamicGridCellClickEventArgs : HandledEventArgs
{
    public CoreRow? Row { get; set; }

    public DynamicColumnBase? Column { get; set; }

    public DynamicGridCellClickEventArgs(CoreRow? row, DynamicColumnBase? column)
    {
        Row = row;
        Column = column;
    }
}

public delegate void OnCellDoubleClick(object sender, DynamicGridCellClickEventArgs args);

public class BeforeRefreshEventArgs : CancelEventArgs { }
public delegate void BeforeRefreshEventHandler(object sender, BeforeRefreshEventArgs args);

public class AfterRefreshEventArgs : EventArgs { }
public delegate void AfterRefreshEventHandler(object sender, AfterRefreshEventArgs args);