@use 'sass:list';
@use 'sass:meta';
@use 'sass:string';
////
/// @group utils.strings
////

/// Ensures that that provided value is a string.

@function to-str($str) {
    @if (meta.type-of($str) == 'string') {
        @return $str;
    }
    @return '' + $str;
}

/// Replace all instances of a string within another string
///
/// @example str-replace('test test test', 'test', 'pass') // => 'pass pass pass'

@function str-replace($string, $search, $replace: '') {
    $index: string.index($string, $search);
    @if $index {
        @return string.slice($string, 1, $index - 1) + $replace +
            str-replace(string.slice($string, $index + string.length($search)), $search, $replace);
    }
    @return $string;
}

/// Url encode a string (used primarily for encoding inline svg)
/// @example url-encode('pixellab') // => "www.thinkpixellab.com%25";

@function url-encode($string) {
    $map: (
        '%': '%25',
        '<': '%3C',
        '>': '%3E',
        ' ': '%20',
        '!': '%21',
        '*': '%2A',
        "'": '%27',
        '"': '%22',
        '(': '%28',
        ')': '%29',
        ';': '%3B',
        ':': '%3A',
        '@': '%40',
        '&': '%26',
        '=': '%3D',
        '+': '%2B',
        '$': '%24',
        ',': '%2C',
        '/': '%2F',
        '?': '%3F',
        '#': '%23',
        '[': '%5B',
        ']': '%5D',
    );

    $new: $string;

    @each $search, $replace in $map {
        $new: str-replace($new, $search, $replace);
    }

    @return $new;
}

/// Encode an svg string for use as an inline svg (like a background image).
///
/// @example
/// background-image: inline-svg('<svg>...</svg>'); // => background-image: url('data:image/svg+xml, ... ');

@function inline-svg($string, $replacements: null) {
    @if ($replacements) {
        @each $search, $replace in $replacements {
            $string: str-replace($string, $search, $replace);
        }
    }
    @return url('data:image/svg+xml,#{url-encode($string)}');
}

/// Split a string into an array of strings based on a separator.
/// @param {String} $string - the string to split
/// @param {String} $separator - the character to split the string on
/// @example str-split('you are here', 'a') // => "you " "re here"

@function str-split($string, $separator) {
    // empty array/list
    $split-arr: ();
    // first index of separator in string
    $index: string.index($string, $separator);
    // loop through string
    @while $index != null {
        // get the substring from the first character to the separator
        $item: string.slice($string, 1, $index - 1);
        // push item to array
        $split-arr: list.append($split-arr, $item);
        // remove item and separator from string
        $string: string.slice($string, $index + 1);
        // find new index of separator
        $index: string.index($string, $separator);
    }
    // add the remaining string to list (the last item)
    $split-arr: list.append($split-arr, $string);

    @return $split-arr;
}

/// Creates and returns a new string by concatenating all of the elements in a
/// list separated by $separator. Similiar to Javascript Array.join JavaScript
///
/// @param {List} $list The list to be joined
/// @param {String} $separator The separator character
///
/// @example list-join('a' 'b' 'c', ':') // => 'a:b:c'

@function list-join($list, $separator) {
    @if (list.length($list) == 0) {
        @return '';
    }

    $str: '';

    @for $i from 1 through list.length($list) {
        $s: list.nth($list, $i);
        $str: $str + $s + if(sass($i != list.length($list)): $separator; else: '');
    }
    @return $str;
}

/// Returns true if a string begins withs another string. Returns false if $str is null or 0 length.
///
/// @param {String} $str A string that will be tested for the $start string
/// @param {String} $start A string that $str must start with
///
/// @example starts-with('abc', 'a') // => true

@function starts-with($str, $start) {
    @if ($str and string.length($str)) {
        @return string.index($str, $start) == 1;
    }
    @return false;
}

/// Returns true if a string ends withs another string. Returns false if $str is null or 0 length.
///
/// @param {String} $str A string that will be tested for the $start string
/// @param {String} $start A string that $str must start with
///
/// @example starts-with('abc', 'a') // => true

@function ends-with($str, $end) {
    @if ($str and string.length($str)) {
        @return string.slice($str, string.length($str) - string.length($end) + 1) == $end;
    }
    @return false;
}

// private function that trims the start/left of the string:
@function -trimStart($str) {
    @if (string.slice($str, 1, 1) == ' ') {
        @return -trimStart(string.slice($str, 2));
    } @else {
        @return $str;
    }
}

// private function that trims the end/right of the string:
@function -trimEnd($str) {
    @if (string.slice($str, string.length($str), -1) == ' ') {
        @return -trimEnd(string.slice($str, 1, -2));
    } @else {
        @return $str;
    }
}

/// Trims whitespace from the beinning and end of a string
/// @param {String} $string - the string to trim
/// @example trim('  abc ') => 'abc'

@function trim($str) {
    @return -trimStart(-trimEnd($str));
}
