//------------------------------------------------------------------------------
// <copyright file=”*.cs” company=”EhLib Team”>
//     Copyright (c) 2017 Dmitry V. Bolshakov   
// </copyright>
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;

namespace EhLib
{
  public partial class CustomizeDataGridColumnsDialog : BaseCustomizePropBarsDialog
  {

    #region internal types
    public enum SetVisibleState { Show, Hide };

    [Obfuscation(Feature = "renaming", Exclude = true, ApplyToMembers = false)] 
    public class DataGridColumnDataRow : AxisGridPropDataRow
    {
      public Nullable<int> Width { get; set; }
      public DataGridTitleNode TitleNode { get; set; }
      public bool HidenState { get; set; }
      public DataGridColumn Column { get { return PropBar as DataGridColumn; } }
      public DataGridColumnSetupTreeNode SetupNode { get; set; }
    }

    public class DataGridColumnSetupTreeNode : BaseTreeNode
    {
      private DataGridColumnDataRow dataRow;

      public DataGridColumnSetupTreeNode()
      {
        dataRow = new DataGridColumnDataRow();
      }

      public DataGridColumnDataRow DataRow { get { return dataRow; } }

      public new DataGridColumnSetupTreeNode Parent { get { return (DataGridColumnSetupTreeNode)base.Parent; } }

      public override string ToString()
      {
        return DataRow.Name;
      }
    }
    #endregion

    #region privates
    private DataGridTextColumn visGridWidthColumn = new DataGridTextColumn();
    private TreeListGeneric<DataGridColumnSetupTreeNode> multiTitleSetupTreeList = new TreeListGeneric<DataGridColumnSetupTreeNode>();
    #endregion

    #region constructor
    public CustomizeDataGridColumnsDialog()
    {
      InitializeComponent();


      this.VisGridNameColumn.DataCellClientAreaNeeded += new System.EventHandler<EhLib.DataGridDataCellClientAreaNeededEventArgs>(VisGridNameColumn_DataCellClientAreaNeeded);
      this.VisGridNameColumn.DataCellPaintCustomArea += new System.EventHandler<EhLib.DataGridDataCellPaintEventArgs>(VisGridNameColumn_DataCellPaintCustomArea);

      this.HidGridNameColumn.DataCellClientAreaNeeded += new System.EventHandler<EhLib.DataGridDataCellClientAreaNeededEventArgs>(VisGridNameColumn_DataCellClientAreaNeeded);
      this.HidGridNameColumn.DataCellPaintCustomArea += new System.EventHandler<EhLib.DataGridDataCellPaintEventArgs>(VisGridNameColumn_DataCellPaintCustomArea);

      this.visGridWidthColumn.DataPropertyName = "Width";
      this.visGridWidthColumn.FillWeight = 69F;
      this.visGridWidthColumn.Name = "dataGridTextColumn5";
      this.visGridWidthColumn.Title.Text = "Width";
      this.visGridWidthColumn.Title.ToolTipText = null;
      this.visGridWidthColumn.Width = 69;
      VisiblePropBarsGrid.StaticColumns.AddRange(new PropertyAxisBar[] {
            this.visGridWidthColumn});

    }
    #endregion

    #region properties
    public new DataGridEh DataGrid { get { return (DataGridEh)base.DataGrid; } }
    #endregion

    #region methods
    public static bool ShowCustomizeColumnsDialog(DataGridEh grid)
    {
      CustomizeDataGridColumnsDialog dialog = new CustomizeDataGridColumnsDialog();
      return dialog.ShowDialog(grid);
    }

    protected override List<AxisGridPropDataRow> CreateDataViewVisiblePropsList()
    {
      return new DynaTypedList<AxisGridPropDataRow>(typeof(DataGridColumnDataRow));
    }

    protected override List<AxisGridPropDataRow> CreateDataViewHidenPropsList()
    {
      return new DynaTypedList<AxisGridPropDataRow>(typeof(DataGridColumnDataRow));
    }

    protected override void InitData()
    {
      base.InitData();
      bSetWidth.Visible = true;
      //if (DataGrid.Title.MultiTitle.Active)
      //  DataViewHidenProps.RowFilter = "HidenState = true";
    }

    protected override void WriteGridBarsData()
    {
      if (DataGrid.Title.MultiTitle.Active)
      {
        DataGrid.Columns.BeginUpdate();
        DataGrid.Title.MultiTitle.BeginUpdate();
        try
        {
          int i = 0;
          foreach (AxisGridPropDataRow propBarDataRow in PropsTable)
          {
            DataGridColumnDataRow colRow = propBarDataRow as DataGridColumnDataRow;
            DataGridTitleNode node = colRow.TitleNode;
            WriteTitleNodeFromTitleNodeDataRow(node, colRow, i);
            i++;
          }

          DataGridMultiTitleTreeList titleTree = DataGrid.Title.MultiTitle.TitleTree;
          WriteNodeOrders(titleTree.Root, multiTitleSetupTreeList.Root);
        }
        finally
        {
          DataGrid.Title.MultiTitle.EndUpdate();
          DataGrid.Columns.EndUpdate();
        }
      }
      else
      {
        base.WriteGridBarsData();
      }
    }

    protected virtual void WriteNodeOrders(DataGridTitleNode titleNode, DataGridColumnSetupTreeNode setupNode)
    {
      List<DataGridTitleNode> titleNodesOrders = new List<DataGridTitleNode>();

      foreach(DataGridColumnSetupTreeNode setupChildNode in setupNode.Items)
      {
        WriteNodeOrders(setupChildNode.DataRow.TitleNode, setupChildNode);
        titleNodesOrders.Add(setupChildNode.DataRow.TitleNode);
      }

      titleNode.SetItemsOrder(titleNodesOrders);
    }

    protected virtual void WriteTitleNodeFromTitleNodeDataRow(DataGridTitleNode node, DataGridColumnDataRow propBarDataRow, int i)
    {
      if (node.NodeType == DataGridTitleNodeType.SuperTitle)
      {
        node.SuperTitle.Visible = propBarDataRow.VisibleState;
      }
      else
      {
        node.ColumnTitle.Column.Visible = propBarDataRow.VisibleState;
        //propBar.DisplayIndex = index;
        node.ColumnTitle.Column.Width = propBarDataRow.Width.Value;
      }
    }

    protected override void WritePropBarFromPropBarDataRow(PropertyAxisBar propBar, AxisGridPropDataRow propBarDataRow, int index)
    {
      base.WritePropBarFromPropBarDataRow(propBar, propBarDataRow, index);
      (propBar as DataGridColumn).Width = (propBarDataRow as DataGridColumnDataRow).Width.Value;
    }

    protected override AxisGridPropDataRow CreateNewPropsDataRow(PropertyAxisBar propBar)
    {
      return new DataGridColumnDataRow();
    }

    protected override void InitNewPropDataRow(AxisGridPropDataRow dataTow, PropertyAxisBar propBar)
    {
      base.InitNewPropDataRow(dataTow, propBar);

      DataGridColumnDataRow colDataRow = dataTow as DataGridColumnDataRow;
      DataGridColumn col = propBar as DataGridColumn;

      colDataRow.Width = col.Width;
    }

    protected override void ReadPropBars()
    {
      if (DataGrid.Title.MultiTitle.Active)
      {
        DataGridMultiTitleTreeList titleTree = DataGrid.Title.MultiTitle.TitleTree;

        ReadMultiTitleNode(titleTree.Root, multiTitleSetupTreeList.Root);
        SetupTreeListToFlatPropsTable();

        foreach (DataGridColumnDataRow row in PropsTable)
        {
          bool visibleState = row.VisibleState;
          if (!visibleState)
            CheckSetStateParent(row.TitleNode, SetVisibleState.Hide);
        }

        RefreshScreenLists();
      }
      else
      {
        base.ReadPropBars();
      }
    }

    protected virtual void ReadMultiTitleNode(DataGridTitleNode titleNode, DataGridColumnSetupTreeNode colSetupNode)
    {
      foreach (DataGridTitleNode childTitleNode in titleNode.Items)
      {
        DataGridColumnSetupTreeNode colSetupChildNode = new DataGridColumnSetupTreeNode();

        InitPropsMultiTitleTableRow(colSetupChildNode.DataRow, childTitleNode, colSetupChildNode);
        colSetupNode.Items.Add(colSetupChildNode);

        if (childTitleNode.Items.Count > 0)
          ReadMultiTitleNode(childTitleNode, colSetupChildNode);
      }
    }

    protected virtual void SetupTreeListToFlatPropsTable()
    {
      PropsTable.Clear();

      DataGridColumnSetupTreeNode node = multiTitleSetupTreeList.GetFirst();
      while (node != null)
      {
        PropsTable.Add(node.DataRow);
        node = multiTitleSetupTreeList.GetNext(node);
      }

      SetSetupTreeListItemsVisibleState();
    }

    private void SetSetupTreeListItemsVisibleState()
    {
      DataGridColumnSetupTreeNode node = multiTitleSetupTreeList.GetFirst();
      while (node != null)
      {
        node.Visible = GetColumnSetupNodeVisibleState(node);
        node = multiTitleSetupTreeList.GetNext(node);
      }
    }

    private bool GetColumnSetupNodeVisibleState(DataGridColumnSetupTreeNode node)
    {
      bool result = node.DataRow.VisibleState;
      if (node.Parent != null && node.Parent != node.TreeList.Root)
        result = result && GetColumnSetupNodeVisibleState(node.Parent);
      return result;
    }

    protected virtual void InitPropsMultiTitleTableRow(DataGridColumnDataRow row, DataGridTitleNode titleNode, DataGridColumnSetupTreeNode setupNode)
    {
      if (titleNode.NodeType == DataGridTitleNodeType.ColumnTitle)
      {
        DataGridColumn col = titleNode.ColumnTitle.Column;

        row.PropBar = col;
        row.VisibleState = col.Visible;
        row.Name = col.Title.Text;
        row.Width = col.Width;
        row.TitleNode = titleNode;
        row.HidenState = !col.Visible;
        row.SetupNode = setupNode;
      }
      else
      {
        DataGridSuperTitle superTitle = titleNode.SuperTitle;

        row.PropBar = null;
        row.VisibleState = superTitle.Visible;
        row.Name = superTitle.Text;
        row.Width = null;
        row.TitleNode = titleNode;
        row.HidenState = !superTitle.Visible;
        row.SetupNode = setupNode;
      }
    }

    protected override void HideSelectedPropBars()
    {
      if (DataGrid.Title.MultiTitle.Active)
        SetMultiTileColumnVisibleState(SetVisibleState.Hide);
      else
        base.HideSelectedPropBars();
    }

    protected override bool IsPropRowInHidenList(AxisGridPropDataRow propBarDataRow)
    {
      if (DataGrid.Title.MultiTitle.Active)
        return (propBarDataRow as DataGridColumnDataRow).HidenState;
      else
        return base.IsPropRowInHidenList(propBarDataRow);
    }

    protected override void ShowSelectedPropBars()
    {
      if (DataGrid.Title.MultiTitle.Active)
        SetMultiTileColumnVisibleState(SetVisibleState.Show);
      else
        base.ShowSelectedPropBars();
    }

    protected virtual void SetMultiTileColumnVisibleState(SetVisibleState setState)
    {
      DataGridEh stateGrid;
      if (setState == SetVisibleState.Hide)
        stateGrid = VisiblePropBarsGrid;
      else
        stateGrid = HidenPropBarsGrid;

      if (stateGrid.CurrentRow == null) return;

      DataGridColumnDataRow curRow = (stateGrid.CurrentRow.SourceItem as DataGridColumnDataRow);
      DataGridTitleNode curNode = curRow.TitleNode;

      List<DataGridColumnDataRow> listForChangeState = new List<DataGridColumnDataRow>();
      listForChangeState.Add(curRow);

      if (curNode.NodeType == DataGridTitleNodeType.SuperTitle)
      {
        GetChildList(curNode, listForChangeState, true);
      }

      foreach (DataGridColumnDataRow row in listForChangeState)
      {
        if (setState == SetVisibleState.Hide)
        {
          row.VisibleState = false;
          row.HidenState = true;
        }
        else
        {
          row.VisibleState = true;
          row.HidenState = false;
        }
      }

      CheckSetStateParent(curNode, setState);
      SetSetupTreeListItemsVisibleState();
      RefreshScreenLists();
    }

    private void CheckSetStateParent(DataGridTitleNode node, SetVisibleState setState)
    {
      if (node.Parent != node.TreeList.Root && node.Parent != null)
      {
        SetVisibleState getState;
        DataGridColumnDataRow parentRow = GetDataRowByNode(node.Parent);
        //parentRow.BeginEdit();

        if (setState == SetVisibleState.Hide)
        {
          parentRow.HidenState = true;
          getState = SetVisibleState.Show;
        }
        else
        {
          parentRow.VisibleState = true;
          getState = SetVisibleState.Hide;
        }

        int visibleChildren = GetStatedChildren(node.Parent, getState);
        if (visibleChildren == 0)
        {
          if (setState == SetVisibleState.Hide)
            parentRow.VisibleState = false;
          else
            parentRow.HidenState = false;
        }

        //parentRow.EndEdit();

        CheckSetStateParent(node.Parent, setState);
      }
    }

    private int GetStatedChildren(DataGridTitleNode parent, SetVisibleState getState)
    {
      int result = 0;
      foreach (DataGridTitleNode childNode in parent.Items)
      {
        DataGridColumnDataRow childRow = GetDataRowByNode(childNode);
        if (getState == SetVisibleState.Show)
        {
          if (childRow.VisibleState == true)
            result = result + 1;
        }
        else
        {
          if (childRow.HidenState == true)
            result = result + 1;
        }
      }
      return result;
    }

    private void GetChildList(DataGridTitleNode node, List<DataGridColumnDataRow> rowsList, bool childRecursion)
    {
      foreach (DataGridTitleNode childNode in node.Items)
      {
        DataGridColumnDataRow childRow = GetDataRowByNode(childNode);
        rowsList.Add(childRow);

        if (childRecursion && (childNode.NodeType == DataGridTitleNodeType.SuperTitle))
        {
          GetChildList(childRow.TitleNode, rowsList, childRecursion);
        }
      }
    }

    private DataGridColumnDataRow GetDataRowByNode(DataGridTitleNode childNode)
    {
      foreach (DataGridColumnDataRow row in PropsTable)
      {
        DataGridTitleNode node = row.TitleNode;
        if (node == childNode)
          return row;
      }
      return null;
    }

    protected override void MovePropBarsUpDown(bool isMoveUp)
    {
      if (DataGrid.Title.MultiTitle.Active)
      {
        if (VisiblePropBarsGrid.VisibleRows.Count == 0) return;

        DataGridRow gridRow = VisiblePropBarsGrid.CurrentRow;
        DataGridColumnDataRow dataRow = gridRow.SourceItem as DataGridColumnDataRow;
        DataGridColumnSetupTreeNode setupNode = dataRow.SetupNode;
        int setupNodeVisibleIndex = setupNode.VisibleIndex;
        DataGridColumnSetupTreeNode parentSetupNode = dataRow.SetupNode.Parent;

        List<DataGridColumnSetupTreeNode> orderdList = new List<DataGridColumnSetupTreeNode>();

        foreach (DataGridColumnSetupTreeNode node in parentSetupNode.Items)
          orderdList.Add(node);

        if (isMoveUp)
        {
          if (setupNodeVisibleIndex == 0) return;
          setupNodeVisibleIndex--;
          int modeToNodeIndex = parentSetupNode.VisibleItems[setupNodeVisibleIndex].Index;
          orderdList.Remove(setupNode);
          orderdList.Insert(modeToNodeIndex, setupNode);
          //VisiblePropBarsGrid.CurrentRowIndex = VisiblePropBarsGrid.CurrentRowIndex - 1;
        }
        else
        {
          if (setupNodeVisibleIndex == parentSetupNode.VisibleItems.Count - 1) return;
          setupNodeVisibleIndex++;
          int modeToNodeIndex = parentSetupNode.VisibleItems[setupNodeVisibleIndex].Index;
          orderdList.Remove(setupNode);
          orderdList.Insert(modeToNodeIndex, setupNode);
          //VisiblePropBarsGrid.CurrentRowIndex = VisiblePropBarsGrid.CurrentRowIndex + 1;
        }

        dataRow.SetupNode.Parent.SetItemsOrder(orderdList);

        SetupTreeListToFlatPropsTable();
        RefreshScreenLists();

        VisiblePropBarsGrid.CurrentRowIndex = VisiblePropBarsGridIndexOfSetupNode(setupNode);
      }
      else
      {
        base.MovePropBarsUpDown(isMoveUp);
      }
    }

    private int VisiblePropBarsGridIndexOfSetupNode(DataGridColumnSetupTreeNode setupNode)
    {
      int i = 0;
      foreach (DataGridRow gridRow in VisiblePropBarsGrid.VisibleRows)
      {
        DataGridColumnDataRow dataRow = gridRow.SourceItem as DataGridColumnDataRow;
        if (dataRow.SetupNode == setupNode)
          return i;
        i++;
      }
      return -1;
    }

    protected override void bSetWidth_Click(object sender, EventArgs e)
    {
      List<DataGridColumnDataRow> listForWidth = new List<DataGridColumnDataRow>();

      foreach (DataGridRow row in VisiblePropBarsGrid.Rows)
      {
        if (row.Selected)
          listForWidth.Add(row.SourceItem as DataGridColumnDataRow);
      }

      if (listForWidth.Count == 0 && VisiblePropBarsGrid.VisibleRows.Count > 0)
        listForWidth.Add(VisiblePropBarsGrid.CurrentRow.SourceItem as DataGridColumnDataRow);

      if (listForWidth.Count == 0) return;

      string colWidthStr = "64";
      colWidthStr = listForWidth[0].Width.ToString();

      if (EhLibUtils.InputBox("Set columns width", "Width", ref colWidthStr) != DialogResult.OK) return;

      int newColWidth;
      if (!int.TryParse(colWidthStr, out newColWidth))
      {
        MessageBox.Show("The input text is not a number", "Error", System.Windows.Forms.MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
      }

      foreach (DataGridColumnDataRow rowView in listForWidth)
      {
        if (DataGrid.Title.MultiTitle.Active == false
              ||
            (DataGrid.Title.MultiTitle.Active == true &&
             (rowView.TitleNode.NodeType == DataGridTitleNodeType.ColumnTitle))
           )
        {
          rowView.Width = newColWidth;
        }
      }

      RefreshScreenLists();
    }

    private void VisGridNameColumn_DataCellClientAreaNeeded(object sender, DataGridDataCellClientAreaNeededEventArgs e)
    {
      int custAreaWidth = 0;
      if (DataGrid.Title.MultiTitle.Active)
      {
        DataGridColumnDataRow row = e.Row.SourceItem as DataGridColumnDataRow;
        DataGridTitleNode node = row.TitleNode;
        custAreaWidth = e.CellRect.Height * node.Level;
      }
      e.CellClientRect = EhLib.EhLibUtils.ChangeRectangle(e.CellRect, custAreaWidth, 0, -custAreaWidth, 0);
    }

    private void VisGridNameColumn_DataCellPaintCustomArea(object sender, DataGridDataCellPaintEventArgs e)
    {
      if (!DataGrid.Title.MultiTitle.Active) return;

      Rectangle drawRect = e.CellClientRect;
      drawRect.X = e.CellRect.X;
      drawRect.Width = e.CellClientRect.X - e.CellRect.X;
      e.CellClientRect = drawRect;
      e.PaintBackground(e);

      DataGridColumnDataRow row = e.Row.SourceItem as DataGridColumnDataRow;
      DataGridTitleNode node = row.TitleNode;

      if (node.NodeType == DataGridTitleNodeType.SuperTitle)
      {
        Rectangle btnRect = drawRect;
        btnRect.X = drawRect.Right - drawRect.Height;
        btnRect.Width = drawRect.Height;

        Bitmap bmp = Properties.Resources.TreeViewSignExpandedTriangleBlack;

        Rectangle signRect = new Rectangle(0, 0, bmp.Width, bmp.Height);
        signRect = EhLibUtils.RectCenter(signRect, btnRect);

        e.Graphics.DrawImage(bmp, signRect);
      }
    }
    #endregion

  }
}
