using C1.C1Report;
using C1.Web.Wijmo.Controls.C1GridView;
using C1.Web.Wijmo.Controls.C1ReportViewer;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace GridView_Pagination
{
    public partial class _Default : Page
    {
        private const string SESSION_DATA_SOURCE = "DATA_SOURCE";

        private HashSet<string> GetSelectedIds()
        {
            return new HashSet<string>(
                HSelected.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                               .Select(s => s.Trim()),
                StringComparer.OrdinalIgnoreCase);
        }

        private void SaveSelectedIds(HashSet<string> selected)
        {
            var allIds = HAllItems.Value
                                  .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                                  .Select(s => s.Trim())
                                  .ToList();

            HSelected.Value = string.Join(",", allIds.Where(id => selected.Contains(id)));
            HUnselected.Value = string.Join(",", allIds.Where(id => !selected.Contains(id)));
            HSelectionAll.Value = (selected.Count > 0 && allIds.All(id => selected.Contains(id)))
                                  ? "true" : "false";
        }

        protected void Page_Init(object sender, EventArgs e)
        {
            BuildColumns();
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                var dt = BuildDataSource();
                Session[SESSION_DATA_SOURCE] = dt;

                string allIds = string.Join(",",
                    dt.AsEnumerable().Select(r => r["ID"].ToString()));

                HSelectionAll.Value = "false";
                HSelected.Value = "";
                HUnselected.Value = allIds;
                HAllItems.Value = allIds;

                BindGrid(dt);
            }
        }

        private void BuildColumns()
        {
            C1GridView1.Columns.Clear();

            C1GridView1.Columns.Add(new C1TemplateField
            {
                Width = 60,
                HeaderTemplate = new HeaderButtonTemplate(CheckAll_Click),
                ItemTemplate = new CheckBoxTemplate()
            });

            C1GridView1.Columns.Add(new C1BoundField
            {
                DataField = "ID",
                HeaderText = "ID",
                SortExpression = "ID"
            });

            C1GridView1.Columns.Add(new C1BoundField
            {
                DataField = "Name",
                HeaderText = "Name",
                SortExpression = "Name"
            });

            C1GridView1.Columns.Add(new C1CheckBoxField
            {
                DataField = "IsActive",
                HeaderText = "Active",
                Width = 100,
                ReadOnly = true
            });

            C1GridView1.Columns.Add(new C1ButtonField
            {
                Text = "ShowReport",
                ButtonType = ButtonType.Button,
                CommandName = "ShowReport",
                Width = 150
            });
        }

        private static DataTable BuildDataSource()
        {
            var dt = new DataTable();
            dt.Columns.Add("ID", typeof(int));
            dt.Columns.Add("Name", typeof(string));
            dt.Columns.Add("IsActive", typeof(bool));
            dt.Columns.Add("BtnName", typeof(string));

            for (int i = 1; i <= 30; i++)
                dt.Rows.Add(i, "Customer " + i, i % 2 == 0, $"btn-{i}");

            dt.Rows[0]["BtnName"] = "ShowReport";
            return dt;
        }

        private void BindGrid(DataTable dt)
        {
            C1GridView1.DataSource = dt;
            C1GridView1.DataBind();
        }

        protected void C1GridView1_RowDataBound(object sender, C1GridViewRowEventArgs e)
        {
            if (e.Row.RowType != C1GridViewRowType.DataRow)
                return;

            var cb = e.Row.FindControl("chk") as CheckBox;
            if (cb == null)
                return;

            string rowId = GetRowId(C1GridView1, e.Row);
            cb.Checked = GetSelectedIds().Contains(rowId);
            cb.Attributes["onclick"] = string.Format("ChangeSelection(this, {0});", rowId);
        }

        protected void C1GridView1_PageIndexChanging(object sender, C1GridViewPageEventArgs e)
        {
            C1GridView1.PageIndex = e.NewPageIndex;
            var dt = Session[SESSION_DATA_SOURCE] as DataTable ?? BuildDataSource();
            BindGrid(dt);
        }

        protected void C1GridView1_RowCommand(object sender, C1GridViewCommandEventArgs e)
        {
            if (e.CommandName == "ShowReport")
            {
                string rowId = e.CommandArgument.ToString();

                if (int.TryParse(rowId, out int idx))
                    C1GridView1.SelectedIndex = GetRowIndexById(rowId + 1);

                var x = C1ReportViewer.IsDocumentRegistered("RowReport");
                var y = C1ReportViewer.HasCachedDocument("RowReport", "SampleReport");
                C1ReportViewer.UnRegisterDocument("RowReport");
                C1ReportViewer.ClearCachedDocument("RowReport", "SampleReport");
                var report = BuildReport(idx);
                //C1ReportViewer.RegisterDocument($"RowReport", () => report);
                C1ReportViewer.RegisterDocument($"RowReport-{rowId}", () => report);

                ReportViewer.ReportName = "SampleReport";
                ReportViewer.ReportsFolderPath = "~/_Reports/Temp";
                //ReportViewer.FileName = $"RowReport";
                ReportViewer.FileName = $"RowReport-{rowId}";
                ReportDialog.ShowOnLoad = true;
                UpdatePanelGrid.Update();
            }
        }

        internal void CheckAll_Click(object sender, ImageClickEventArgs e)
        {
            var selectedIds = GetSelectedIds();

            var allIds = HAllItems.Value
                                  .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                                  .Select(s => s.Trim())
                                  .Where(s => !string.IsNullOrWhiteSpace(s))
                                  .ToList();

            bool allChecked = allIds.Count > 0 && allIds.All(id => selectedIds.Contains(id));
            bool newState = !allChecked;

            if (newState)
                allIds.ForEach(id => selectedIds.Add(id));
            else
                selectedIds.Clear();

            SaveSelectedIds(selectedIds);

            var dt = Session[SESSION_DATA_SOURCE] as DataTable ?? BuildDataSource();
            BindGrid(dt);
            UpdatePanelGrid.Update();
        }

        private static string GetRowId(C1GridView grid, C1GridViewRow row)
        {
            try
            {
                if (grid.DataKeys != null
                    && row.RowIndex >= 0
                    && row.RowIndex < grid.DataKeys.Count)
                {
                    var val = grid.DataKeys[row.RowIndex].Value;
                    if (val != null) return Convert.ToString(val);
                }
            }
            catch { /* fall through */ }

            return "ROW_" + row.RowIndex;
        }

        private int GetRowIndexById(string rowId)
        {
            foreach (C1GridViewRow row in C1GridView1.Rows)
            {
                if (GetRowId(C1GridView1, row) == rowId)
                    return row.RowIndex;
            }
            return -1;
        }

        /// <summary>
        /// Returns C1Report (not object) so Session["CurrentReport"] as C1Report
        /// in the Page_Load RegisterDocument lambda resolves correctly.
        /// </summary>
        public static C1Report BuildReport(int id)
        {
            var report = C1ReportViewer.CreateC1Report();
            report.Load(
                System.Web.HttpContext.Current.Server.MapPath("~/SampleReport.xml"),
                "SampleReport");

            var data = new DataTable();
            data.Columns.Add("id", typeof(int));
            data.Columns.Add("col", typeof(string));
            data.Columns.Add("val", typeof(int));

            var rnd = new Random();
            for (int i = 0; i < 10; i++)
                data.Rows.Add(id, $"col-{i}", rnd.Next(1, 100));

            report.DataSource.DataProvider = DataProvider.Auto;
            report.DataSource.Recordset = data;

            return report;
        }
    }
}