#region (c)2010-2042 Hawkynt

// This file is part of Hawkynt's .NET Framework extensions.
// 
// Hawkynt's .NET Framework extensions are free software:
// you can redistribute and/or modify it under the terms
// given in the LICENSE file.
// 
// Hawkynt's .NET Framework extensions is distributed in the hope that
// it will be useful, but WITHOUT ANY WARRANTY without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the LICENSE file for more details.
// 
// You should have received a copy of the License along with Hawkynt's
// .NET Framework extensions. If not, see
// <https://github.com/Hawkynt/C--FrameworkExtensions/blob/master/LICENSE>.

#endregion

namespace System.Windows.Forms;

/// <summary>
/// Specifies the height of a row in a <see cref="System.Windows.Forms.DataGridView"/> with various conditions.
/// </summary>
/// <example>
/// <code>
/// // Define a custom class for the data grid view rows
/// [DataGridViewRowHeight(rowHeightProperty: nameof(RowHeight), rowHeightEnabledProperty: nameof(IsCustomHeightEnabled))]
/// public class DataRow
/// {
///     public int Id { get; set; }
///     public string Name { get; set; }
///     public int RowHeight { get; set; }
///     public bool IsCustomHeightEnabled { get; set; }
/// }
///
/// // Create an array of DataRow instances
/// var dataRows = new[]
/// {
///     new DataRow { Id = 1, Name = "Row 1", RowHeight = 50, IsCustomHeightEnabled = true },
///     new DataRow { Id = 2, Name = "Row 2", RowHeight = 60, IsCustomHeightEnabled = false }
/// };
///
/// // Create a DataGridView and set its data source
/// var dataGridView = new DataGridView
/// {
///     DataSource = dataRows
/// };
///
/// // Enable extended attributes to recognize the custom attributes
/// dataGridView.EnableExtendedAttributes();
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)]
public sealed class DataGridViewRowHeightAttribute : Attribute {

  private readonly Action<DataGridViewRow, object> _applier;

  /// <summary>
  /// Initializes a new instance of the <see cref="DataGridViewRowHeightAttribute"/> class with a fixed height.
  /// </summary>
  /// <param name="heightInPixel">The fixed height in pixels for the row.</param>
  public DataGridViewRowHeightAttribute(int heightInPixel) 
    => this._applier = (row, _) => {
      row.MinimumHeight = heightInPixel;
      row.Height = heightInPixel;
    };

  /// <summary>
  /// Initializes a new instance of the <see cref="DataGridViewRowHeightAttribute"/> class with a conditional height.
  /// </summary>
  /// <param name="heightInPixel">The fixed height in pixels for the row.</param>
  /// <param name="rowHeightEnabledProperty">The name of a boolean property that enables or disables the height setting. When this property is <see langword="true"/>, the height is applied.</param>
  public DataGridViewRowHeightAttribute(int heightInPixel, string rowHeightEnabledProperty) 
    => this._applier = (row, rowData) => {
      if (!DataGridViewExtensions.GetPropertyValueOrDefault(
          rowData,
          rowHeightEnabledProperty,
          false,
          false,
          false,
          false
        ))
        return;

      row.MinimumHeight = heightInPixel;
      row.Height = heightInPixel;
    };

  /// <summary>
  /// Initializes a new instance of the <see cref="DataGridViewRowHeightAttribute"/> class with a property-based height.
  /// </summary>
  /// <param name="rowHeightProperty">The name of a property that provides the height for the row.</param>
  public DataGridViewRowHeightAttribute(string rowHeightProperty) 
    => this._applier = (row, rowData) => {
      var originalHeight = row.Height;
      var rowHeight = DataGridViewExtensions.GetPropertyValueOrDefault(
        rowData,
        rowHeightProperty,
        originalHeight,
        originalHeight,
        originalHeight,
        originalHeight
      );

      row.MinimumHeight = rowHeight;
      row.Height = rowHeight;
    };

  /// <summary>
  /// Initializes a new instance of the <see cref="DataGridViewRowHeightAttribute"/> class with a conditional property-based height.
  /// </summary>
  /// <param name="rowHeightProperty">The name of a property that provides the height for the row.</param>
  /// <param name="rowHeightEnabledProperty">The name of a boolean property that enables or disables the height setting. When this property is <see langword="true"/>, the height is applied.</param>
  public DataGridViewRowHeightAttribute(string rowHeightProperty, string rowHeightEnabledProperty) 
    => this._applier = (row, rowData) => {
      if (!DataGridViewExtensions.GetPropertyValueOrDefault(
          rowData,
          rowHeightEnabledProperty,
          false,
          false,
          false,
          false
        ))
        return;

      var originalHeight = row.Height;
      var rowHeight = DataGridViewExtensions.GetPropertyValueOrDefault(
        rowData,
        rowHeightProperty,
        originalHeight,
        originalHeight,
        originalHeight,
        originalHeight
      );

      row.MinimumHeight = rowHeight;
      row.Height = rowHeight;
    };

  /// <summary>
  /// Applies the row height settings to the specified <see cref="DataGridViewRow"/>.
  /// </summary>
  /// <param name="rowData">The data for the row.</param>
  /// <param name="row">The <see cref="DataGridViewRow"/> to apply the height settings to.</param>
  internal void ApplyTo(object rowData, DataGridViewRow row) => this._applier?.Invoke(row, rowData);

}
