@import "../settings/settings.globalVars";

// TODO: Convert px to rem!
// Breakpoint values from the "global-vars" map
@function get-breakpoint-map($settings) {
  @if map-has-key($settings, "breakpoints") {
    @each $property, $values in $settings {
      @if length($values) != 0 {
        @return $values;
      } @else {
        @error 'No breakpoint value available.';
      }
    }
  } @else {
    @error 'No property with key "breakpoints" available.';
  }
}

// Name of the next breakpoint, or null for the last breakpoint.
@function breakpoint-next(
  $name,
  $breakpoints: get-breakpoint-map($settings),
  $breakpoint-names: map-keys($breakpoints)
) {
  $n: index($breakpoint-names, $name);

  @return if($n != null and $n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);
}

// Minimum breakpoint width. Null for the smallest (first) breakpoint.
@function breakpoint-min($name, $breakpoints: get-breakpoint-map($settings)) {
  $min: map-get($breakpoints, $name);

  @return if($min != 0, $min, null);
}

// Maximum breakpoint width. Null for the largest (last) breakpoint.
@function breakpoint-max($name, $breakpoints: get-breakpoint-map($settings)) {
  $next: breakpoint-next($name, $breakpoints);

  @return if($next, breakpoint-min($next, $breakpoints) - 0.02, null);
}

// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.
@function breakpoint-infix($name, $breakpoints: get-breakpoint-map($settings)) {
  @return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}");
}

// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.
// Use: @include for-screen-up(lg) { ... }
@mixin for-screen-up($name, $breakpoints: get-breakpoint-map($settings)) {
  $min: breakpoint-min($name, $breakpoints);

  @if $min {
    @media (min-width: "#{$min}px") {
      @content;
    }
  } @else {
    @error "No breakpoint min available";
  }
}

// Media of at most the maximum breakpoint width. No query for the largest breakpoint.
// Use: @include for-screen-down(lg) { ... }
@mixin for-screen-down($name, $breakpoints: get-breakpoint-map($settings)) {
  $max: breakpoint-max($name, $breakpoints);

  @if $max {
    @media (max-width: "#{$max}px") {
      @content;
    }
  } @else {
    @error "No breakpoint max available";
  }
}

// Media that spans multiple breakpoint widths.
// Use: @include for-screen-between(md, xl) { ... }
@mixin for-screen-between($lower, $upper, $breakpoints: get-breakpoint-map($settings)) {
  $min: breakpoint-min($lower, $breakpoints);
  $max: breakpoint-max($upper, $breakpoints);

  @if $min != null and $max != null {
    @media (min-width: "#{$min}px") and (max-width: "#{$max}px") {
      @content;
    }
  } @else if $max == null {
    @include for-screen-up($lower, $breakpoints) {
      @content;
    }
  } @else if $min == null {
    @include for-screen-down($upper, $breakpoints) {
      @content;
    }
  }
}

// Media between the breakpoint's minimum and maximum widths.
// Use: @include for-screen-only(xs) { ... }
@mixin for-screen-only($name, $breakpoints: get-breakpoint-map($settings)) {
  $min: breakpoint-min($name, $breakpoints);
  $max: breakpoint-max($name, $breakpoints);

  @if $min != null and $max != null {
    @media (min-width: "#{$min}px") and (max-width: "#{$max}px") {
      @content;
    }
  } @else if $max == null {
    @include for-screen-up($name, $breakpoints) {
      @content;
    }
  } @else if $min == null {
    @include for-screen-down($name, $breakpoints) {
      @content;
    }
  }
}
