@use "sass:list";

/// Replaces characters in a string
///
/// @param {string} $string
///   String where the replace happens
/// @param {string} $search
///   Portion of string to find and replace
/// @param {string} $replace
///   Replacement. Default is ''.
/// @return {string} string with characters replaced.
@function str-replace($string, $search, $replace: '') {
    $index: str-index($string, $search);
    @return if($index,
        str-slice($string, 1, $index - 1) + $replace +
        str-replace(str-slice($string, $index +
        str-length($search)), $search, $replace),
        $string);
}

/// Encodes an inline svg. Original source code: http://codepen.io/jakob-e/pen/doMoML
///
/// @param {string} $svg
///   Inline svg to encode
/// @return {string} encoded svg.
@function svg-encode($svg){
    // Chunk up string in order to avoid "stack level too deep" error
    $encoded:'';
    $slice: 2000;
    $index: 0;
    $loops: ceil(divide(str-length($svg), $slice));
    @for $i from 1 through $loops {
        $chunk: str-slice($svg, $index, $index + $slice - 1);
        // Encode
        $chunk: str-replace($chunk, '"', '\'');
        $chunk: str-replace($chunk, '%', '%25');
        $chunk: str-replace($chunk, '#', '%23');
        $chunk: str-replace($chunk, '{', '%7B');
        $chunk: str-replace($chunk, '}', '%7D');
        $chunk: str-replace($chunk, '<', '%3C');
        $chunk: str-replace($chunk, '>', '%3E');

        $encoded: #{$encoded}#{$chunk};
        $index: $index + $slice;
    }
    @return "data:image/svg+xml,#{$encoded}";
}

/// Appends a list of variables to $whitelist and return a new whitelist.
///
/// @param {...} $variables
///   Variables to whitelist
/// @return {list} new whitelist.
///
/// Example (in components/_radio.scss)
/// $whitelist: add-to-whitelist('radio-active-background-color','radio-focus-sibiling-box-shadow');
@function add-to-whitelist($variables...) {
    @return list.join($whitelist, $variables);
}

/// Checks if a variable is in $whitelist.
///
/// @param {string} $variable
///   Variable to check if present in whitelist
/// @return {boolean} true if $variable is in $whitelist, else false.
@function is-in-whitelist($variable) {
    @return list.index($whitelist, $variable) != null;
}

/// Checks if $whitelist is empty
///
/// @return {boolean} true if $whitelist is empty, else false.
@function is-empty-whitelist() {
    @return list.length($whitelist) == 0;
}

/// Returns a variable.
///
/// @param {string} $name
///   Variable name
/// @param {string} $value
///   Variable value
/// @param {string} $forceval
///   By default is `false`, if `true` it allows to bypass whitelist and set the value
/// @return {string} the variable or null if not in whitelist when $css-vars == false.
@function variable($name, $value, $forceval: false) {
    @if $css-vars == true {
        @if is-empty-whitelist() or is-in-whitelist($name) {
            @return var(#{$variable-prefix}#{$name}, #{$value});
        }
    } @else if $sass-vars == true {
        @if is-empty-whitelist() or is-in-whitelist($name) {
            @return #{$value};
        }
    } @else if $forceval == true {
        @return #{$value};
    }
    @return null;
}

/// Returns a pair of `(key,value)` to pass to `evariable` function.
///
/// @param {string} $key
///   Key of the parameter
/// @param {string} $value
///   Value of the parameter
/// @return {list} list of two elements representing an `eparam` `(key, value)`.
@function eparam($key, $value) {
    @return $key, $value;
}

/// Assigns a specific expression to an attribute
///
/// @param {string} $attribute
///   The attribute we want to include
/// @param {string} $expression
///   The body of the function we want to write (e.g. `calc($width/$height)`)
/// @param {...} $parameters
///   List of `eparam` to apply to the function
@mixin evariable($attribute, $expression, $parameters...) {
    $is_valid: true;
    @each $parameter in $parameters {
        @if list.nth($parameter, 2) == null {
            $is_valid: false;
        }
        @if str-slice(list.nth($parameter, 1), 0, 1) != "$" {
            @error "Parameter #{list.nth($parameter, 1)} should start with $.";
        }
        $expression: str-replace($expression, list.nth($parameter, 1), list.nth($parameter, 2));
    }
    @if $is_valid {
        #{$attribute}: #{$expression};
    }
}

/// Assigns a specific variable to an attribute
///
/// @param {string} $attribute
///   The attribute we want to include
/// @param {string} $name
///   Variable name
/// @param {string} $value
///   Variable value
@mixin avariable($attribute, $name, $value) {
    $variable: variable($name, $value);
    @if $variable != null {
        #{$attribute}: $variable;
    }
}

@mixin unselectable {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

@mixin side-flex-gap ($gap) {
    //flex-wrap: wrap;
    margin-left: -$gap;
    margin-right: -$gap;

    & > * {
        margin-left: $gap;
        margin-right: $gap;
    }
}

// Custom divide function by @mdo from https://github.com/twbs/bootstrap/pull/34245
// Replaces old slash division deprecated in Dart Sass
@function divide($dividend, $divisor, $precision: 10) {
  $sign: if($dividend > 0 and $divisor > 0, 1, -1);
  $dividend: abs($dividend);
  $divisor: abs($divisor);
  $quotient: 0;
  $remainder: $dividend;
  @if $dividend == 0 {
    @return 0;
  }
  @if $divisor == 0 {
    @error "Cannot divide by 0";
  }
  @if $divisor == 1 {
    @return $dividend;
  }
  @while $remainder >= $divisor {
    $quotient: $quotient + 1;
    $remainder: $remainder - $divisor;
  }
  @if $remainder > 0 and $precision > 0 {
    $remainder: divide($remainder * 10, $divisor, $precision - 1) * .1;
  }
  @return ($quotient + $remainder) * $sign;
}
