//
// Copyright IBM Corp. 2018, 2018
//
// This source code is licensed under the Apache-2.0 license found in the
// LICENSE file in the root directory of this source tree.
//

@use 'config' as *;
@use 'breakpoint' as *;

// -----------------------------------------------------------------------------
// Columns
// -----------------------------------------------------------------------------

/// Used to initialize the default properties for a column class, most notably
/// for setting width and default gutters when a column's breakpoint has not been
/// hit yet.
/// @param {Number} $gutter [$grid-gutter] - The gutter for the grid system
/// @param {Number} $collapsed-gutter [$grid-gutter--condensed] - The condensed mode gutter
/// @access private
/// @group @carbon/grid
@mixin -make-col-ready(
  $gutter: $grid-gutter,
  $condensed-gutter: $grid-gutter--condensed
) {
  // Prevent columns from becoming too narrow when at smaller grid tiers by
  // always setting `width: 100%;`. This works because we use `flex` values
  // later on to override this initial width.
  width: 100%;
  padding-right: ($gutter / 2);
  padding-left: ($gutter / 2);

  // For our condensed use-case, our gutters collapse to 2px solid, 1px on each
  // side.
  .#{$prefix}--row--condensed &,
  .#{$prefix}--grid--condensed & {
    padding-right: ($condensed-gutter / 2);
    padding-left: ($condensed-gutter / 2);
  }

  // For our narrow use-case, our container hangs 16px into the gutter
  .#{$prefix}--row--narrow &,
  .#{$prefix}--grid--narrow & {
    padding-right: ($gutter / 2);
    padding-left: 0;
  }
}

/// Define the width of the column for a given span and column count.
/// A width of 0 will hide the column entirely.
/// @param {Number} $span - The number of columns covered
/// @param {Number} $columns - The total number of columns available
/// @access private
/// @group @carbon/grid
@mixin -make-col($span, $columns) {
  @if $span == 0 {
    display: none;
  } @else {
    // Explicitly include `display: block` to override
    display: block;
    flex: 0 0 percentage($span / $columns);
    // Add a `max-width` to ensure content within each column does not blow out
    // the width of the column. Applies to IE10+ and Firefox. Chrome and Safari
    // do not appear to require this.
    max-width: percentage($span / $columns);
  }
}

/// Create a column offset for a given span and column count.
/// @param {Number} $span - The number of columns the offset should cover
/// @param {Number} $columns - The total number of columns available
/// @access private
/// @group @carbon/grid
@mixin -make-col-offset($span, $columns) {
  $offset: $span / $columns;
  @if $offset == 0 {
    margin-left: 0;
  } @else {
    margin-left: percentage($offset);
  }
}

/// Output the CSS required for all the columns in a given grid system.
/// @param {Map} $breakpoints [$grid-breakpoints] - The breakpoints in the grid system
/// @param {Number} $gutter [$grid-gutter] - The gutter for the grid system
/// @access private
/// @group @carbon/grid
@mixin -make-grid-columns(
  $breakpoints: $grid-breakpoints,
  $gutter: $grid-gutter
) {
  .#{$prefix}--col {
    @include -make-col-ready($gutter);
  }

  @each $breakpoint in map-keys($breakpoints) {
    $infix: breakpoint-infix($breakpoint);
    $columns: map-get(map-get($breakpoints, $breakpoint), columns);

    // Allow columns to stretch full width below their breakpoints
    @for $i from 0 through $columns {
      .#{$prefix}--col#{$infix}-#{$i} {
        @include -make-col-ready($gutter);
      }
    }

    .#{$prefix}--col#{$infix},
    .#{$prefix}--col#{$infix}--auto {
      @include -make-col-ready($gutter);
    }

    @include breakpoint($breakpoint, $breakpoints) {
      // Provide basic `.col-{bp}` classes for equal-width flexbox columns
      .#{$prefix}--col,
      .#{$prefix}--col#{$infix} {
        flex-basis: 0;
        flex-grow: 1;
        max-width: 100%;
      }

      .#{$prefix}--col--auto,
      .#{$prefix}--col#{$infix}--auto {
        flex: 1 0 0%;
        width: auto;
        // Reset earlier grid tiers
        max-width: 100%;
      }

      @for $i from 0 through $columns {
        .#{$prefix}--col#{$infix}-#{$i} {
          @include -make-col($i, $columns);
        }
      }

      @for $i from 0 through ($columns - 1) {
        @if not($infix == '') {
          .#{$prefix}--offset#{$infix}-#{$i} {
            @include -make-col-offset($i, $columns);
          }
        }
      }
    }
  }
}

// -----------------------------------------------------------------------------
// Rows
// -----------------------------------------------------------------------------

/// Define the properties for a selector assigned to a row in the grid system.
/// @param {Number} $gutter [$grid-gutter] - The gutter in the grid system
/// @access private
/// @group @carbon/grid
@mixin make-row($gutter: $grid-gutter) {
  display: flex;
  flex-wrap: wrap;
  margin-right: -1 * $gutter / 2;
  margin-left: -1 * $gutter / 2;
}

// -----------------------------------------------------------------------------
// No gutter
// -----------------------------------------------------------------------------

/// Add `no-gutter` and `no-gutter--{start,end}` classes to the output CSS. These
/// classes are useful for dropping the gutter in fluid situations.
/// @access private
/// @group @carbon/grid
@mixin -no-gutter {
  .#{$prefix}--no-gutter,
  .#{$prefix}--row.#{$prefix}--no-gutter [class*='#{$prefix}--col'] {
    padding-right: 0;
    padding-left: 0;
  }

  .#{$prefix}--no-gutter--start,
  .#{$prefix}--row.#{$prefix}--no-gutter--start [class*='#{$prefix}--col'] {
    padding-left: 0;
  }

  .#{$prefix}--no-gutter--end,
  .#{$prefix}--row.#{$prefix}--no-gutter--end [class*='#{$prefix}--col'] {
    padding-right: 0;
  }

  // Deprecated ☠️
  .#{$prefix}--no-gutter--left,
  .#{$prefix}--row.#{$prefix}--no-gutter--left [class*='#{$prefix}--col'] {
    padding-left: 0;
  }

  .#{$prefix}--no-gutter--right,
  .#{$prefix}--row.#{$prefix}--no-gutter--right [class*='#{$prefix}--col'] {
    padding-right: 0;
  }
}

// -----------------------------------------------------------------------------
// Hang
// -----------------------------------------------------------------------------

/// Add `hang--start` and `hang--end` classes for a given gutter. These classes are
/// used alongside `no-gutter--start` and `no-gutter--end` to "hang" type.
/// @param {Number} $gutter [$grid-gutter] - The gutter in the grid system
/// @access private
/// @group @carbon/grid
@mixin -hang($gutter: $grid-gutter) {
  .#{$prefix}--hang--start {
    padding-left: ($gutter / 2);
  }

  .#{$prefix}--hang--end {
    padding-right: ($gutter / 2);
  }

  // Deprecated ☠️
  .#{$prefix}--hang--left {
    padding-left: ($gutter / 2);
  }

  .#{$prefix}--hang--right {
    padding-right: ($gutter / 2);
  }
}

// -----------------------------------------------------------------------------
// Grid
// -----------------------------------------------------------------------------

/// Create the container for a grid. Will cause full-bleed for the grid unless
/// max-width properties are added with `-make-container-max-widths`
/// @param {Map} $breakpoints [$grid-breakpoints] - A map of breakpoints where the key is the name
/// @access private
/// @group @carbon/grid
@mixin -make-container($breakpoints: $grid-breakpoints) {
  margin-right: auto;
  margin-left: auto;

  @include -set-largest-breakpoint();

  @each $name, $value in $breakpoints {
    $prev-breakpoint: map-get($breakpoints, breakpoint-prev($name));
    $margin: map-get($value, margin);

    @if $prev-breakpoint {
      $prev-margin: map-get($prev-breakpoint, margin);
      @if $prev-margin != $margin {
        @include breakpoint($name) {
          padding-right: #{($grid-gutter / 2) + $margin};
          padding-left: #{($grid-gutter / 2) + $margin};
        }
      }
    } @else {
      @include breakpoint($name) {
        padding-right: #{($grid-gutter / 2) + $margin};
        padding-left: #{($grid-gutter / 2) + $margin};
      }
    }
  }
}

/// Get the last breakpoint width and set max-width to its value
/// @param {Map} $breakpoints [$grid-breakpoints] - A map of breakpoints where the key is the name
/// @access private
/// @group @carbon/grid
@mixin -set-largest-breakpoint($breakpoints: $grid-breakpoints) {
  $largest-breakpoint: last-map-item($breakpoints);

  max-width: map-get($largest-breakpoint, 'width');
}

/// Add in the max-widths for each breakpoint to the container
/// @param {Map} $breakpoints [$grid-breakpoints] - A map of breakpoints where the key is the name
/// @access private
/// @group @carbon/grid
@mixin -make-container-max-widths($breakpoints: $grid-breakpoints) {
  @each $name, $value in $breakpoints {
    @include breakpoint($name) {
      max-width: map-get($value, width);
    }
  }
}

/// Generate the CSS for a grid for the given breakpoints and gutters
/// @param {Map} $breakpoints [$grid-breakpoints] - The default breakpoints
/// @param {Number} $grid-gutter [$grid-gutter] - The default gutters
/// @param {Number} $condensed-gutter [$grid-gutter--condensed] - The condensed mode gutter
/// @access public
/// @group @carbon/grid
@mixin grid(
  $breakpoints: $grid-breakpoints,
  $grid-gutter: $grid-gutter,
  $condensed-gutter: $grid-gutter--condensed
) {
  .#{$prefix}--grid {
    @include -make-container($breakpoints);
  }

  @include largest-breakpoint($breakpoints) {
    .#{$prefix}--grid--full-width {
      max-width: 100%;
    }
  }

  .#{$prefix}--row {
    @include make-row();
  }

  .#{$prefix}--row-padding [class*='#{$prefix}--col'],
  .#{$prefix}--col-padding {
    padding-top: $grid-gutter / 2;
    padding-bottom: $grid-gutter / 2;
  }

  .#{$prefix}--grid--condensed [class*='#{$prefix}--col'] {
    padding-top: $condensed-gutter / 2;
    padding-bottom: $condensed-gutter / 2;
  }

  @include -make-grid-columns($breakpoints, $grid-gutter);
  @include -no-gutter();
  @include -hang($grid-gutter);
}
