@use "sass:list";
@use "sass:string";
@use "sass:math";

/// Set grid row or column value using the fraction unit.
///
/// @param {Integer} $number - number of fractions that the grid row or column
///   needs to be divided into.
/// @returns {String} - the value
///
/// @example scss - Five fractions will return `1fr 1fr 1fr 1fr 1fr`.
///  .container {
///    grid-template-rows: fractions(5);
///  }
///
@function fractions($number) {
  $fractions: "1fr";

  @for $i from 1 to $number {
    $fractions: $fractions + " 1fr";
  }

  @return string.unquote($fractions);
}

/// Arrange items into columns
///
/// The items can flow from horizontally or vertically.
///
/// @param {Integer} $items - number of items that need to be arranged
/// @param {Integer} $columns - number of columns required
/// @param {String} $selector - (optional) the inner element to be targeted.
/// @param {String} $direction - (optional) the flow of the items in the grid:
///   * `row` goes from the left to right, top to bottom one row at a time
///   * `column` goes from the top to bottom, left to right one column at a time
///
/// @example scss - A 7 item 2 column layout going left to right, top to bottom.
///  .container {
///    @include columns($items: 7, $columns: 2);
///  }
///
/// @example scss - A 9 item 3 column layout that has `div`s as the inner
///   elements.
///  .container {
///    @include columns($items: 9, $columns: 3, $selector:"div");
///  }
///
/// @example scss - A 16 item 2 column layout going from top to bottom
///   elements.
///  .container {
///    @include columns($items: 9, $columns: 3, $flow:"column");
///  }
///
@mixin columns($items, $columns, $selector: "*", $flow: row) {
  $rows: math.ceil(calc($items / $columns));

  display: -ms-grid;
  display: grid;
  grid-auto-flow: $flow;
  -ms-grid-columns: fractions($columns);
  grid-template-columns: fractions($columns);
  -ms-grid-rows: fractions($rows);
  grid-template-rows: fractions($rows);

  // Internet Explorer 10-11 require each element to be placed in the grid -
  // the `grid-auto-flow` property isn't supported. This means that both the
  // column and row needs to be set for every child element.
  @if $flow == "row" {
    $grid: ();
    $counter: 0;

    @for $row from 1 through $rows {
      $this-row: ();

      @for $column from 1 through $columns {
        $counter: $counter + 1;

        // stylelint-disable max-nesting-depth
        @if $counter <= $items {
          $this-row: list.append($this-row, $counter);
        }
        // stylelint-enable max-nesting-depth
      }

      $grid: list.append($grid, $this-row, "comma");
    }

    @for $row-count from 1 through list.length($grid) {
      $this-column: list.nth($grid, $row-count);

      @for $item-index from 1 through list.length($this-column) {
        $this-item: list.nth($this-column, $item-index);

        & > #{$selector}:nth-child(#{$this-item}) {
          -ms-grid-column: $item-index;
          -ms-grid-row: $row-count;
        }
      }
    }
  }

  @if $flow == "column" {
    // This creates a list of lists to represent the columns and rows; for
    // example, a 7 item 2 column list would create this:
    //   [
    //     [1, 2, 3, 4 ] // column one
    //     [5, 6, 7] // column two
    //   ]
    $grid: ();
    $counter: 0;

    @for $column from 1 through $columns {
      $this-row: ();

      @for $row from 1 through $rows {
        $counter: $counter + 1;

        // stylelint-disable max-nesting-depth
        @if $counter <= $items {
          $this-row: list.append($this-row, $counter);
        }
        // stylelint-enable max-nesting-depth
      }

      $grid: list.append($grid, $this-row, "comma");
    }

    // Now we can loop through the list of lists to create the rules needed for
    // the older grid syntax; fist looping through the list to get the number
    // needed for the column, then looping again to get the number for the grid
    // row:
    @for $column_index from 1 through list.length($grid) {
      $this-row: list.nth($grid, $column_index);

      @for $item-index from 1 through list.length($this-row) {
        $this-item: list.nth($this-row, $item-index);

        & > #{$selector}:nth-child(#{$this-item}) {
          -ms-grid-column: $column_index;
          -ms-grid-row: $item-index;
        }
      }
    }
  }
}
