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

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

namespace EhLib
{

  [DesignerCategory("Code")]
  [ToolboxItem(false)]
  public class BaseGridCellManager : Component
  {
    #region privates
    private BaseGridControl grid;
    //private bool backRectHasMouse;

    internal bool CellContentMouseDown;
    #endregion privates

    public BaseGridCellManager()
    {

    }

    #region Properties
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public BaseGridControl Grid
    {
      get { return grid; }
      set { grid = value; }
    }

    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    public virtual Type EditType
    {
      get { return null; }
    }
    #endregion Properties

    #region Methods

    //Paint
    public virtual void ProcessPaint(BaseGridCellPaintEventArgs e)
    {
      HandlePaintEvent(e);
      if (!e.Handled)
        OnPaint(e);
    }

    protected internal virtual void HandlePaintEvent(BaseGridCellPaintEventArgs e)
    {
    }

    protected internal virtual void OnPaint(BaseGridCellPaintEventArgs e)
    {
      OnPaintBackground(e);
      OnPaintForeground(e);
    }

    protected internal virtual void OnPaintBackground(BaseGridCellPaintEventArgs e)
    {
      Color fillColor;

      if ((e.ColIndex >= Grid.FixedColCount - Grid.FrozenColCount) && (e.RowIndex >= Grid.FixedRowCount - Grid.FrozenRowCount))
        fillColor = SystemColors.Window;
      else
        fillColor = Color.LightBlue;

      using (
        SolidBrush fillBrush = new SolidBrush(fillColor))
      {
        if ((BasePaintCellStates.Selected & e.State) != 0)
        {
          if (Grid.IsActiveControl())
            fillBrush.Color = SystemColors.Highlight;
          else
            fillBrush.Color = SystemColors.ButtonShadow;
        }

        Grid.PaintingFillRectangle(e.Graphics, fillBrush, e.CellRect);
      }
    }

    protected internal virtual void OnPaintForeground(BaseGridCellPaintEventArgs e)
    {
      OnPaintClientForeground(e);
      OnPaintCustomArea(e);
    }

    protected internal virtual void OnPaintClientForeground(BaseGridCellPaintEventArgs e)
    {
      Color fForeColor;

      if ((BasePaintCellStates.Current & e.State) != 0)
        fForeColor = SystemColors.HighlightText;
      else
        fForeColor = Grid.ForeColor;

      string text = GetDisplayText(e.AreaColIndex, e.AreaRowIndex);
      if (text != null)
      {
        EhLibUtils.DrawText(e.Graphics, text, Grid.Font, e.CellRect, fForeColor, HorizontalAlignment.Left, VerticalAlignment.Top, TextFormatFlagsEh.None);
      }
    }

    //protected internal virtual Rectangle GetClientRect(int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect)
    //{
    //  return cellRect;
    //}

    protected internal virtual void OnPaintCustomArea(BaseGridCellPaintEventArgs e)
    {

    }

    protected internal virtual BaseGridCellPaintEventArgs GetCellPaintEmptyAreaEventArgs(
        Graphics graphics, int colIndex, int rowIndex, Rectangle paintRect, BasePaintCellStates state,
        int areaColIndex, int areaRowIndex, Point inCellMousePos
      )
    {
      return new BaseGridCellPaintEventArgs(this, graphics, colIndex, rowIndex, paintRect, state, areaColIndex, areaRowIndex, inCellMousePos);
    }

    protected internal virtual void OnPaintEmptyArea(BaseGridCellPaintEventArgs e)
    {
      if (Grid.Background.Visible) return;

      using (SolidBrush fillBrush = new SolidBrush(Grid.BackColor))
      {
        Grid.PaintingFillRectangle(e.Graphics, fillBrush, e.CellRect);
      }
    }

    //PaintParams
    public virtual BaseGridCellPaintEventArgs GetCellPaintParams(
        Graphics graphics, int colIndex, int rowIndex, Rectangle paintRect, BasePaintCellStates state,
        int areaColIndex, int areaRowIndex, Point inCellMousePos
      )
    {
      return new BaseGridCellPaintEventArgs(this, graphics, colIndex, rowIndex, paintRect, state, areaColIndex, areaRowIndex, inCellMousePos);
    }

    //Other
    protected internal virtual void PrintCell(
      PrintServiceEventArgs e, Rectangle paintRect, int areaColIndex, int areaRowIndex, PrintServiceEventArgs printContext)
    {
      //Font font = null;
      Font drawFont;

      Color fForeColor = Color.Black;

      string text = GetDisplayText(areaColIndex, areaRowIndex);
      if (text != null)
      {
        drawFont = Grid.Font;
        e.PrintText(text, drawFont, paintRect, fForeColor, HorizontalAlignment.Left, VerticalAlignment.Top, TextFormatFlagsEh.None);
      }
    }

    public virtual string GetDisplayText(int areaColIndex, int areaRowIndex)
    {
      return areaColIndex.ToString() + BaseGridControl.CharColonStr + areaRowIndex.ToString(); 
    }

    public virtual void OccupyEditControl(Control cellEditControl, int areaColIndex, int areaRowIndex, bool selectAll)
    {
      throw new InvalidOperationException("OccupyEditControl: Must be implemented in the inherited class");
    }

    public virtual void ReleaseEditControl(Control cellEditControl)
    {
    }

    public virtual bool IsCharToEnterEditMode(KeyPressEventArgs e)
    {
      return false;
    }

    protected internal virtual void OnGetCellBorderParams(BaseGridCellBorderEventArgs e)
    {
    }

    public virtual void GridCellPosToAreaCellPos(int gridColIndex, int gridRowIndex, out int areaColIndex, out int areaRowIndex)
    {
      areaColIndex = gridColIndex;
      areaRowIndex = gridRowIndex;
    }

    public virtual void AreaCellPosToGridCellPos(int areaColIndex, int areaRowIndex, out int gridColIndex, out int gridRowIndex)
    {
      gridColIndex = areaColIndex;
      gridRowIndex = areaRowIndex;
    }

    protected internal virtual void ProcessMouseDown(BaseGridCellMouseEventArgs e)
    {
      HandleMouseDownEvent(e);
      if (e.Handled) return;
      OnMouseDown(e);
    }

    protected internal virtual void HandleMouseDownEvent(BaseGridCellMouseEventArgs e)
    {
    }

    protected internal virtual void OnMouseDown(BaseGridCellMouseEventArgs e)
    {
      bool moveDrawn = false;
      CellContentMouseDown = true;

      GridCoord mouseDownCellPos = Grid.MouseDownCellCoord;

      if ((e.ColIndex >= Grid.FixedColCount - Grid.FrozenColCount) &&
            (mouseDownCellPos.Y >= Grid.FixedRowCount - Grid.FrozenRowCount) &&
            (e.ColIndex < Grid.ColCount) &&
            (mouseDownCellPos.Y < Grid.RowCount)
          )
      {
        if ((GridOptions.Editing & Grid.Options) != 0)
        {
          if ((e.ColIndex == Grid.Col) && 
              (mouseDownCellPos.Y == Grid.Row) &&
              ((GridOptions.Editing & Grid.Options) != 0) &&
              (e.Button == MouseButtons.Left && (Control.ModifierKeys & (Keys.Shift | Keys.Alt | Keys.Control)) == 0)
              )
            Grid.ShowEditor(true);
          else
          {
            if ((GridOptions.RangeSelect & Grid.Options) != 0)
            {
              Grid.GridState = BaseGridState.Selecting;
              Grid.SetGridTimer(true, 60);
              if (Control.ModifierKeys == Keys.Shift && e.Button == MouseButtons.Left)
                Grid.MoveAnchorCell(e.ColIndex, mouseDownCellPos.Y, true);
              else
                Grid.InteractiveFocusCell(e.ColIndex, mouseDownCellPos.Y, InteractiveActionSource.Mouse);
            }
            else
            {
              Grid.InteractiveFocusCell(e.ColIndex, mouseDownCellPos.Y, InteractiveActionSource.Mouse);
            }
            Grid.UpdateEdit();
          }
          //            Click();
        }
        else
        {
          if ((GridOptions.RangeSelect & Grid.Options) != 0)
            Grid.GridState = BaseGridState.Selecting;
          Grid.SetGridTimer(true, 60);
          if (Control.ModifierKeys == Keys.Shift && e.Button == MouseButtons.Left)
            Grid.MoveAnchorCell(e.ColIndex, mouseDownCellPos.Y, true);
          else
            Grid.InteractiveFocusCell(e.ColIndex, mouseDownCellPos.Y, InteractiveActionSource.Mouse);
        }
      }
      else if (((GridOptions.RowMoving & Grid.Options) != 0) &&
                (e.Button == MouseButtons.Left) &&
                (e.ColIndex >= 0) &&
                (e.ColIndex < Grid.FixedColCount) &&
                (mouseDownCellPos.Y >= Grid.FixedRowCount) &&
                (mouseDownCellPos.Y < Grid.RowCount)
              )
      {
        Grid.MoveFromIndex = mouseDownCellPos.Y;
        int moveFromIndex = Grid.MoveFromIndex;
        int moveToIndex = moveFromIndex;
        if (Grid.CheckBeginRowDrag(ref moveFromIndex, ref moveToIndex, new Point(e.GridMouseArgs.X, e.GridMouseArgs.Y)))
        {
          Grid.GridState = BaseGridState.RowMoving;
          Grid.Update();
          Grid.DrawMove();
          moveDrawn = true;
          Grid.SetGridTimer(true, 60);
        }
      }
      else if (((GridOptions.ColMoving & Grid.Options) != 0) &&
                (e.Button == MouseButtons.Left) &&
                (mouseDownCellPos.Y >= 0) &&
                (mouseDownCellPos.Y < Grid.FixedRowCount) &&
                (e.ColIndex >= Grid.FixedColCount) &&
                (e.ColIndex < Grid.ColCount)
              )
      {
        int moveFromIndex = e.ColIndex;
        int moveToIndex = e.ColIndex;
        if (Grid.CheckBeginColumnDrag(ref moveFromIndex, ref moveToIndex, new Point(e.GridMouseArgs.X, e.GridMouseArgs.Y)))
          Grid.StartColMoving(moveFromIndex, moveToIndex, e.GridMouseArgs.X, e.GridMouseArgs.Y);
      }

      if (moveDrawn)
        Grid.HideMove();
    }

    protected internal virtual void ProcessMouseMove(BaseGridCellMouseEventArgs e)
    {
      HandleMouseMoveEvent(e);
      if (e.Handled) return;
      OnMouseMove(e);
    }

    protected internal virtual void HandleMouseMoveEvent(BaseGridCellMouseEventArgs e)
    {
    }

    protected internal virtual void OnMouseMove(BaseGridCellMouseEventArgs e)
    {
      //var brnEvArg = new BaseGridCellBackgroundRectNeededEventArgs(e.ColIndex, e.RowIndex, e.AreaColIndex, e.AreaRowIndex, e.CellRect);
      //ProcessBackgroundRectNeeded(brnEvArg);
      //bool backRectHasMouse = brnEvArg.BackgroundRect.Contains(e.GridMouseArgs.Location);
      //if (this.backRectHasMouse != backRectHasMouse)
      //{
      //  this.backRectHasMouse = backRectHasMouse;
      //  Grid.InvalidateCell(e.ColIndex, e.RowIndex);
      //}
    }

    protected internal virtual void ProcessMouseUp(BaseGridCellMouseEventArgs e)
    {
      HandleMouseUpEvent(e);
      if (e.Handled) return;
      OnMouseUp(e);
    }

    protected internal virtual void HandleMouseUpEvent(BaseGridCellMouseEventArgs e)
    {
    }

    protected internal virtual void OnMouseUp(BaseGridCellMouseEventArgs e)
    {
      CellContentMouseDown = false;
    }

    protected internal virtual void ProcessMouseClick(BaseGridCellMouseEventArgs e)
    {
      HandleMouseClickEvent(e);
      if (e.Handled) return;
      OnMouseClick(e);
    }

    protected internal virtual void HandleMouseClickEvent(BaseGridCellMouseEventArgs e)
    {
    }

    protected internal virtual void OnMouseClick(BaseGridCellMouseEventArgs e)
    {
    }

    protected internal virtual void ProcessMouseDoubleClick(BaseGridCellMouseEventArgs e)
    {
      HandleMouseDoubleClickEvent(e);
      if (e.Handled) return;
      OnMouseDoubleClick(e);
    }

    protected internal virtual void HandleMouseDoubleClickEvent(BaseGridCellMouseEventArgs e)
    {
    }

    protected internal virtual void OnMouseDoubleClick(BaseGridCellMouseEventArgs e)
    {
    }

    protected internal virtual void OnMouseCaptureCanceled()
    {
    }

    protected internal virtual void ProcessMouseEnter(BaseGridCellEnterEventArgs e)
    {
      HandleMouseEnterEvent(e);
      OnMouseEnter(e);
    }

    protected virtual void HandleMouseEnterEvent(BaseGridCellEnterEventArgs e)
    {
    }

    protected internal virtual void OnMouseEnter(BaseGridCellEnterEventArgs e)
    {
      //this.backRectHasMouse = true;
    }

    protected internal virtual void ProcessMouseLeave(BaseGridCellLeaveEventArgs e)
    {
      HandleMouseLeaveEvent(e);
      OnMouseLeave(e);
    }

    protected virtual void HandleMouseLeaveEvent(BaseGridCellLeaveEventArgs e)
    {
    }

    protected internal virtual void OnMouseLeave(BaseGridCellLeaveEventArgs e)
    {
      //this.backRectHasMouse = false;
    }

    protected internal virtual void ProcessMouseHover(BaseGridCellMouseEventArgs e)
    {
      HandleMouseHoverEvent(e);
      if (e.Handled) return;
      OnMouseHover(e);
    }

    protected virtual void HandleMouseHoverEvent(BaseGridCellMouseEventArgs e)
    {
    }

    protected virtual void OnMouseHover(BaseGridCellMouseEventArgs e)
    {
    }

    protected internal virtual void CancelMode()
    {
      CellContentMouseDown = false;
    }

    protected internal virtual void OnKeyDown(KeyEventArgs e)
    {
    }

    protected internal virtual void OnKeyPress(KeyPressEventArgs e)
    {
    }

    protected internal virtual void OnKeyUp(KeyEventArgs e)
    {
    }

    protected internal virtual void SetCursor(BaseGridCellMouseEventArgs de, ref Cursor cursor)
    {
      var ce = new BaseGridCellQueryCursorEventArgs(
        this, de.ColIndex, de.RowIndex, de.AreaColIndex, de.AreaRowIndex, de.InCellX, de.InCellY, de.CellRect, de.GridMouseArgs);
      OnQueryCursor(ce);
      HandleQueryCursorEvent(ce);
      cursor = ce.Cursor;
    }

    protected internal virtual void HandleQueryCursorEvent(BaseGridCellQueryCursorEventArgs e)
    {
    }

    protected internal virtual void OnQueryCursor(BaseGridCellQueryCursorEventArgs e)
    {
    }

    protected internal virtual bool IsSelected(int areaColIndex, int areaRowIndex)
    {
      return false;
    }

    protected internal virtual void ProcessMouseContextMenuStripNeeded(BaseGridCellContextMenuStripNeededEventArgs e)
    {
      HandleMouseContextMenuStripNeededEvent(e);
      if (e.Handled)
        return;
      else
      {
        OnContextMenuStripNeeded(e);
      }
    }

    protected internal virtual void OnContextMenuStripNeeded(BaseGridCellContextMenuStripNeededEventArgs e)
    {
      e.ContextMenuStrip = Grid.ContextMenuStrip;
    }

    protected internal virtual void HandleMouseContextMenuStripNeededEvent(BaseGridCellContextMenuStripNeededEventArgs e)
    {
    }

    protected internal virtual BaseGridCellMouseEventArgs CreateMouseEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, int inCellX, int inCellY, Rectangle cellRect, MouseEventArgs gridMouseArgs)
    {
      var de = new BaseGridCellMouseEventArgs(this, colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY, cellRect, gridMouseArgs);
      return de;
    }

    protected internal virtual BaseGridCellEventArgs CreateCellEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect)
    {
      BaseGridCellEventArgs de = new BaseGridCellEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect);
      return de;
    }

    protected internal virtual BaseGridCellEnterEventArgs CreateCellEnterEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect, int leaveColIndex, int leaveRowIndex)
    {
      var de = new BaseGridCellEnterEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, leaveColIndex, leaveRowIndex);
      return de;
    }

    protected internal virtual BaseGridCellLeaveEventArgs CreateCellLeaveEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, Rectangle cellRect, int enterColIndex, int enterRowIndex)
    {
      var de = new BaseGridCellLeaveEventArgs(colIndex, rowIndex, areaColIndex, areaRowIndex, cellRect, enterColIndex, enterRowIndex);
      return de;
    }

    protected internal virtual BaseGridCellContextMenuStripNeededEventArgs CreateCellContextMenuStripNeededEventArgs(
      int colIndex, int rowIndex, int areaColIndex, int areaRowIndex, int inCellX, int inCellY,
      Rectangle cellRect, int MousePosX, int MousePosY)
    {
      var de = new BaseGridCellContextMenuStripNeededEventArgs(this, colIndex, rowIndex, areaColIndex, areaRowIndex, inCellX, inCellY, cellRect, MousePosX, MousePosY);
      return de;
    }

    protected internal void InvalidateGrid()
    {
      if (Grid != null)
        Grid.InvalidateGrid();
    }
    #endregion
  }
}
