using System.ComponentModel;
using C1.Silverlight.FlexGrid;
using C1.Silverlight.FlexGridExcel;
using System.Collections.Generic;

namespace ExcelGrid
{
    /// <summary>
    /// Undoable action which records the values of a cell range.
    /// </summary>
    public class CellRangeEditAction : IUndoableAction
    {
        //-------------------------------------------------------------------------
        #region ** fields

        C1FlexGrid _flex;
        object[,] _oldCellValues, _newCellValues;
        CellRange _oldSelection, _newSelection;
        int _oldTopRow, _oldLeftCol, _newTopRow, _newLeftCol;


        #endregion

        //-------------------------------------------------------------------------
        #region ** object model

        public void RecordUndoState(CellRange range)
        {
            _oldTopRow = _flex.Selection.TopRow;
            _oldLeftCol = _flex.Selection.LeftColumn;
            _oldSelection = range;
            RecordState(ref _oldCellValues, range);
        }

        public void RecordRedoState(CellRange range)
        {
            _newTopRow = _flex.Selection.TopRow;
            _newLeftCol = _flex.Selection.LeftColumn;
            _newSelection = range;
            RecordState(ref _newCellValues, range);
        }

        #endregion

        //-------------------------------------------------------------------------
        #region ** ctor

        /// <summary>
        /// Initializes a new instance of an <see cref="CellRangeEditAction"/>.
        /// <param name="sender"><see cref="C1FlexGrid"/> that owns the action.</param>
        /// </summary>
        public CellRangeEditAction(object sender)
        {
            _flex = sender as C1FlexGrid;
        }

        #endregion

        //-------------------------------------------------------------------------
        #region ** IUndoableAction

        public void Undo()
        {
            SetValues(_oldTopRow, _oldLeftCol, _oldCellValues);
            _flex.Selection = _oldSelection;
        }
        public void Redo()
        {
            SetValues(_newTopRow, _newLeftCol, _newCellValues);
            _flex.Selection = _newSelection;
        }

        #endregion

        //-------------------------------------------------------------------------
        #region ** implementation

        /// <summary>
        /// Records the values of all the cells within the current selection of the <see cref="C1FlexGrid"/>.
        /// </summary>
        /// <param name="values">The multidimensional array where to store the values.</param>
        /// /// <param name="range">The range of cells whose values will be stored.</param>
        void RecordState(ref object[,] values, CellRange range)
        {
            values = new object[range.BottomRow - range.TopRow + 1, range.RightColumn - range.LeftColumn + 1];
            for (int r = range.TopRow; r <= range.BottomRow; r++)
            {
                // skip rows that are not selected
                if (_flex.SelectionMode == SelectionMode.ListBox && !_flex.Rows[r].Selected)
                {
                    continue;
                }
                for (int c = range.LeftColumn; c <= range.RightColumn; c++)
                {
                    values[r - range.TopRow, c - range.LeftColumn] = _flex[r, c];
                }
            }
        }

        private void SetValues(int topRow, int leftCol, object[,] values)
        {
            for (int i = 0; i < values.GetLength(0); i++)
            {
                for (int j = 0; j < values.GetLength(1); j++)
                {
                    _flex[i + topRow, j + leftCol] = values[i, j];
                }
            }
        }

        #endregion
    }
}