using System;
using System.Data;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using Telerik.WinControls;
using Telerik.WinControls.Enumerations;
using Telerik.WinControls.Keyboard;
using Telerik.WinControls.UI;
using static Telerik.WinControls.UI.ValueMapper;

namespace Telerik.Hierarchy.Example
{
    public partial class Form1 : Form
    {
        #region Variables

        //private BindingSource _bsParentData;

        //private BindingSource _bsChildData;

        private DataTable _dtParentData;

        private DataTable _dtChildData;

        #endregion

        #region Constructor

        public Form1()
        {
            InitializeComponent();
        }

        #endregion

        #region Events

        private void Form1_Load(object sender, EventArgs e)
        {
            FormatGrid();
            CreateDataTables();
        }

        private void radButton1_Click(object sender, EventArgs e)
        {
            FillGrid();
        }

        private void radButton2_Click(object sender, EventArgs e)
        {
            ClearGrid();
        }

        private void radGridView1_CellValueChanged(object sender, GridViewCellEventArgs e)
        {
            try
            {
                radGridView1.CellValueChanged -= radGridView1_CellValueChanged;
                radGridView1.HeaderCellToggleStateChanged -= radGridView1_HeaderCellToggleStateChanged;

                switch (true)
                {

                    case true when radGridView1.CurrentRow.ViewTemplate == radGridView1.MasterTemplate:
                        CellValueChangedParentRows(e);
                        break;

                    case true when radGridView1.CurrentRow.ViewTemplate == gridViewTemplate1:
                        CellValueChangedChildRows(e);
                        break;
                }
            }
            catch
            {
                throw;
            }
            finally
            {
                radGridView1.CellValueChanged -= radGridView1_CellValueChanged;
                radGridView1.CellValueChanged += radGridView1_CellValueChanged;

                radGridView1.HeaderCellToggleStateChanged -= radGridView1_HeaderCellToggleStateChanged;
                radGridView1.HeaderCellToggleStateChanged += radGridView1_HeaderCellToggleStateChanged;
            }

        }

        private void radGridView1_HeaderCellToggleStateChanged(object sender, GridViewHeaderCellEventArgs e)
        {
            bool check = e.State == ToggleState.On;

            // Checks/unchecks all parent rows.
            foreach (GridViewHierarchyRowInfo parentRow in this.radGridView1.Rows)
            {
                var dataRowItem = GetSelectedRow(parentRow);
                dataRowItem["Chk"] = check;

                // Checks/unchecks all corresponding child rows.
                foreach (DataRow childRow in _dtChildData.Select($"ParentId = '{dataRowItem["ParentId"]}'"))
                {
                    childRow["Chk"] = dataRowItem["Chk"];
                }

                // Cicles all the "child elements" updates it visually.
                foreach (object rowObject in this.radGridView1.TableElement.Children[0].Children[1].Children)
                {
                    var rowElement = rowObject as GridDetailViewRowElement;
                    if (rowElement != null)
                    {
                        var detailsRowInfo = rowElement.RowInfo as GridViewDetailsRowInfo;
                        if (detailsRowInfo.Owner == parentRow)
                        {
                            var tableElement = (rowElement.Children[1] as GridDetailViewCellElement).Children[0] as GridTableElement;

                            tableElement.Update(GridUINotifyAction.DataChanged);

                        }
                    }
                }
            }

            // Updates the main table element visually.
            radGridView1.TableElement.Update(GridUINotifyAction.DataChanged);
        }

        #endregion

        #region Methods

        private void CellValueChangedParentRows(GridViewCellEventArgs e)
        {
            DataRow selectedParentRow = GetSelectedRow(e.Row);

            //If the changed column is "Chk", checks or unchecks all child rows accordingly.
            if (selectedParentRow != null && e.Column.FieldName == "Chk")
            {
                //Checks the child rows of the selected parent row in the DataTable.
                foreach (DataRow childRow in _dtChildData.Select($"ParentId = '{selectedParentRow["ParentId"]}'"))
                {
                    childRow["Chk"] = selectedParentRow["Chk"];
                }

                // Updates the main table element visually.
                radGridView1.TableElement.Update(GridUINotifyAction.DataChanged);
            }
        }

        private void CellValueChangedChildRows(GridViewCellEventArgs e)
        {
            DataRow selectedChildRow = GetSelectedRow(e.Row);

            //If the changed column is "Chk", checks or unchecks the parent row accordingly.
            if (selectedChildRow != null && e.Column.FieldName == "Chk")
            {
                // If at least 1 child row was checked, checks the parent row as well.
                // If all the child rows end up unchecked, unchecks the parent row as well.
                if (Convert.ToBoolean(selectedChildRow["Chk"]) || _dtChildData.Select($"ParentId = '{selectedChildRow["ParentId"]}' AND Chk = True").Length == 0)
                {
                    foreach (DataRow linha in _dtParentData.Select($"ParentId = '{selectedChildRow["ParentId"]}'"))
                    {
                        linha["Chk"] = selectedChildRow["Chk"];
                    }
                }

                // Updates the main table element visually.
                radGridView1.TableElement.Update(GridUINotifyAction.DataChanged);
            }
        }

        private DataRow GetSelectedRow(GridViewRowInfo gridRow)
        {
            return (gridRow != null && (gridRow is GridViewDataRowInfo || gridRow is GridViewHierarchyRowInfo) && gridRow.DataBoundItem is DataRowView drv) ? drv.Row : null;
        }

        //private bool ProcessData()
        //{
        //    // Handle added and modified data rows
        //    foreach (DataRow row in _dtChildData.Select("Chk = True"))
        //    {
        //        switch (row.RowState)
        //        {
        //            case DataRowState.Added:
        //                // Process new parent rows
        //                break;
        //            case DataRowState.Modified:
        //                // Process modified parent rows
        //                break;
        //        }
        //    }

        //    // Handle deleted data rows
        //    foreach (DataRow row in _dtChildData.AsEnumerable().Where(r => r.RowState == DataRowState.Deleted))
        //    {
        //        // Process deleted child rows
        //    }
        //}

        private void FormatGrid()
        {
            radGridView1.Relations.Clear();

            var relation = new GridViewRelation(this.radGridView1.MasterTemplate);
            relation.RelationName = "ParentIdRelation";
            relation.ParentColumnNames.Add("ParentId");
            relation.ChildColumnNames.Add("ParentId");
            relation.ChildTemplate = gridViewTemplate1;
            this.radGridView1.Relations.Add(relation);

            var chk = new ExpressionFormattingObject("Chk", "Chk = True", true);
            chk.ApplyOnSelectedRows = false;
            chk.RowBackColor = Color.PeachPuff;
            radGridView1.Columns["Chk"].ConditionalFormattingObjectList.Add(chk);
            gridViewTemplate1.Columns["Chk"].ConditionalFormattingObjectList.Add(chk);
        }

        private void CreateDataTables()
        {
            _dtParentData = new DataTable();
            _dtParentData.Columns.Add("ParentId", typeof(Guid));
            _dtParentData.Columns.Add("Chk", typeof(bool));
            _dtParentData.Columns.Add("ParentColumn1", typeof(string));
            _dtParentData.Columns.Add("ParentColumn2", typeof(string));

            _dtChildData = new DataTable();
            _dtChildData.Columns.Add("ParentId", typeof(Guid));
            _dtChildData.Columns.Add("Chk", typeof(bool));
            _dtChildData.Columns.Add("ChildColumn1", typeof(string));
            _dtChildData.Columns.Add("ChildColumn2", typeof(string));
        }

        private void ClearGrid()
        {
            _dtParentData?.Clear();
            _dtChildData?.Clear();
        }

        private void FillGrid()
        {
            ClearGrid();

            // Creates Parent 1 data and 3 child rows for it.
            DataRow drParent1 = _dtParentData.NewRow();
            drParent1["ParentId"] = Guid.NewGuid();
            drParent1["Chk"] = false;
            drParent1["ParentColumn1"] = "Parent 1 column 1";
            drParent1["ParentColumn2"] = "Parent 1 column 2";
            _dtParentData.Rows.Add(drParent1);

            DataRow drChildParent1 = _dtChildData.NewRow();
            drChildParent1["ParentId"] = drParent1["ParentId"];
            drChildParent1["Chk"] = false;
            drChildParent1["ChildColumn1"] = "Child 1 from Parent 1 column 1";
            drChildParent1["ChildColumn2"] = "Child 1 from Parent 1 column 2";
            _dtChildData.Rows.Add(drChildParent1);

            drChildParent1 = _dtChildData.NewRow();
            drChildParent1["ParentId"] = drParent1["ParentId"];
            drChildParent1["Chk"] = false;
            drChildParent1["ChildColumn1"] = "Child 2 from Parent 1 column 1";
            drChildParent1["ChildColumn2"] = "Child 2 from Parent 1 column 2";
            _dtChildData.Rows.Add(drChildParent1);

            drChildParent1 = _dtChildData.NewRow();
            drChildParent1["ParentId"] = drParent1["ParentId"];
            drChildParent1["Chk"] = false;
            drChildParent1["ChildColumn1"] = "Child 3 from Parent 1 column 1";
            drChildParent1["ChildColumn2"] = "Child 3 from Parent 1 column 2";
            _dtChildData.Rows.Add(drChildParent1);

            // Creates Parent 2 data and 2 child rows for it.
            DataRow drParent2 = _dtParentData.NewRow();
            drParent2["ParentId"] = Guid.NewGuid();
            drParent2["Chk"] = false;
            drParent2["ParentColumn1"] = "Parent 2 column 1";
            drParent2["ParentColumn2"] = "Parent 2 column 2";
            _dtParentData.Rows.Add(drParent2);

            DataRow drChildParent2 = _dtChildData.NewRow();
            drChildParent2["ParentId"] = drParent2["ParentId"];
            drChildParent2["Chk"] = false;
            drChildParent2["ChildColumn1"] = "Child 1 from Parent 2 column 1";
            drChildParent2["ChildColumn2"] = "Child 1 from Parent 2 column 2";
            _dtChildData.Rows.Add(drChildParent2);

            drChildParent2 = _dtChildData.NewRow();
            drChildParent2["ParentId"] = drParent2["ParentId"];
            drChildParent2["Chk"] = false;
            drChildParent2["ChildColumn1"] = "Child 2 from Parent 2 column 1";
            drChildParent2["ChildColumn2"] = "Child 2 from Parent 2 column 2";
            _dtChildData.Rows.Add(drChildParent2);

            // Creates Parent 3 data and 4 child rows for it.
            DataRow drParent3 = _dtParentData.NewRow();
            drParent3["ParentId"] = Guid.NewGuid();
            drParent3["Chk"] = false;
            drParent3["ParentColumn1"] = "Parent 3 column 1";
            drParent3["ParentColumn2"] = "Parent 3 column 2";
            _dtParentData.Rows.Add(drParent3);

            DataRow drChildParent3 = _dtChildData.NewRow();
            drChildParent3["ParentId"] = drParent3["ParentId"];
            drChildParent3["Chk"] = false;
            drChildParent3["ChildColumn1"] = "Child 1 from Parent 3 column 1";
            drChildParent3["ChildColumn2"] = "Child 1 from Parent 3 column 2";
            _dtChildData.Rows.Add(drChildParent3);

            drChildParent3 = _dtChildData.NewRow();
            drChildParent3["ParentId"] = drParent3["ParentId"];
            drChildParent3["Chk"] = false;
            drChildParent3["ChildColumn1"] = "Child 2 from Parent 3 column 1";
            drChildParent3["ChildColumn2"] = "Child 2 from Parent 3 column 2";
            _dtChildData.Rows.Add(drChildParent3);

            drChildParent3 = _dtChildData.NewRow();
            drChildParent3["ParentId"] = drParent3["ParentId"];
            drChildParent3["Chk"] = false;
            drChildParent3["ChildColumn1"] = "Child 3 from Parent 3 column 1";
            drChildParent3["ChildColumn2"] = "Child 3 from Parent 3 column 2";
            _dtChildData.Rows.Add(drChildParent3);

            drChildParent3 = _dtChildData.NewRow();
            drChildParent3["ParentId"] = drParent3["ParentId"];
            drChildParent3["Chk"] = false;
            drChildParent3["ChildColumn1"] = "Child 4 from Parent 3 column 1";
            drChildParent3["ChildColumn2"] = "Child 4 from Parent 3 column 2";
            _dtChildData.Rows.Add(drChildParent3);

            //Fills the data in the grid.
            _dtParentData.AcceptChanges();
            _dtChildData.AcceptChanges();

            radGridView1.MasterTemplate.DataSource = _dtParentData;
            gridViewTemplate1.DataSource = _dtChildData;
        }




        #endregion


    }
}
