// =Functions

// breakpoint
@function breakpoint($name) {
    @return map-get(scale(breakpoint), $name);
}

// type size
@function type-size($section, $name, $breakpoint: std) {
    @return type(1, $section, $name, $breakpoint);
}

// type line
@function type-line($section, $name, $breakpoint: std) {
    @return type(2, $section, $name, $breakpoint);
}

// type line alt
@function type-line-alt($section, $name, $breakpoint: std) {
    @return type(3, $section, $name, $breakpoint);
}

// type
@function type($index, $section, $name, $breakpoint) {
    $map: scale(type);

    @if ($breakpoint == sm) { $map: scale(type-sm); }
    @else if ($breakpoint == md) { $map: scale(type-md); }
    @else if ($breakpoint == lg) { $map: scale(type-lg); }

    $val: map-deep-get($map, $section, $name);

    @return nth($val, $index);
}

// color
@function color($keys...) {
    @return map-deep-get($colors, $keys...);
}

@function color-dark-theme($keys...) {
    @return map-deep-get($colors-dark, $keys...);
}

// palette
@function palette($keys...) {
    @return map-deep-get($palette, $keys...);
}

// scale
@function scale($keys...) {
    @return map-deep-get($scales, $keys...);
}

// shadow
@function shadow($name, $type, $color) {
    $shadow: scale(shadow, to-number($type));

    @if type-of($shadow) == 'map' {
        $map: ();
        @each $key, $val in $shadow {
            $strcolor: map-get($color, $key);
            $str: $val $strcolor;
            $map: map-merge($map, ($key: $str));
        }

        @return map-values($map);
    }

    @return $shadow $color;
}

// String
// --------------------------------
@function str-replace($string, $search, $replace: '') {
    $index: str-index($string, $search);

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

    @return $string;
}

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

    @return $split-arr;
}

@function ends-with($string, $find) {
    @return str-slice($string, (str-length($string) - str-length($find) + 1)) == $find;
}

@function to-number($value) {
  @if type-of($value) == 'number' {
    @return $value;
  } @else if type-of($value) != 'string' {
    @error 'Value for `to-number` should be a number or a string.';
  }

  $result: 0;
  $digits: 0;
  $minus: str-slice($value, 1, 1) == '-';
  $numbers: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9);

  @for $i from if($minus, 2, 1) through str-length($value) {
    $character: str-slice($value, $i, $i);

    @if (index(map-keys($numbers), $character) or $character == '.') {
      @if $character == '.' {
        $digits: 1;
      } @else if $digits == 0 {
        $result: $result * 10 + map-get($numbers, $character);
      } @else {
        $digits: $digits * 10;
        $result: $result + map-get($numbers, $character) / $digits;
      }
    }
  }

  @return if($minus, -$result, $result);;
}

// Map
// --------------------------------

// map deep get
// https://www.sitepoint.com/extra-map-functions-sass/
@function map-deep-get($map, $keys...) {
    @each $key in $keys {
        $map: map-get($map, $key);
    }

    @return $map;
}

// change map values instead of extend
@function map-change($map, $keys-and-value...) {
    $keys-and-value-length: length($keys-and-value);
    $value: nth($keys-and-value, $keys-and-value-length);
    $value-is-map: type-of($value) == 'map';
    $value: map-merge($map, if($value-is-map or length($value) == 0, $value, ($value: ())));

    @return $value;
}

// map deep extend
@function map-extend($map, $maps...) {
    $last: nth($maps, -1);
    $max: length($maps);

    // Loop through all maps in $maps...
    @for $i from 1 through $max {
        // Store current map
        $current: nth($maps, $i);

        // If in deep mode, loop through all tuples in current map
        @each $key, $value in $current {
            // If value is a nested map and same key from map is a nested map as well
            @if type-of($value) == "map" and type-of(map-get($map, $key)) == "map" {
                // Recursive extend
                $value: map-extend(map-get($map, $key), $value);
            }

            // Merge current tuple with map
            $map: map-merge($map, ($key: $value));

        }
    }

    @return $map;
}

// https://github.com/lunelson/sass-maps-plus
@function __str-times($str, $n: 1) {
  $output: '';
  @while $n > 0 {
    $output: $output + $str;
    $n: $n - 1;
  }
  @return $output;
}

@function map-stringify($map, $tab: '  ', $level: 1) {
  @if type-of($map) != 'map' { @return '#{inspect($map)}'; }
  $length: length(map-keys($map));
  $indent: __str-times($tab, $level);
  $output: '(\A' + $indent;
  $i: 1;
  @each $key, $value in $map {
    @if type-of($value) == 'map' {
      $output: $output + $key + ': ' + map-stringify($value, $tab, $level + 1);
    } @else {
      $output: $output + $key + ': ' + $value;
    }
    @if $i < $length {
      $output: $output + ',\A' + $indent;
    }
    $i: $i + 1;
  }
  $outdent: __str-times($tab, $level - 1);
  @return unquote($output + '\A' + $outdent + ')');
}

// List
// --------------------------------

// remove item by index
@function remove-nth($list, $index) {
  $result: null;

  @if type-of($index) != number {
    @warn "$index: #{quote($index)} is not a number for `remove-nth`.";
  } @else if $index == 0 {
    @warn "List index 0 must be a non-zero integer for `remove-nth`.";
  } @else if abs($index) > length($list) {
    @warn "List index is #{$index} but list is only #{length($list)} item long for `remove-nth`.";
  } @else {
    $result: ();
    $index: if($index < 0, length($list) + $index + 1, $index);

    @for $i from 1 through length($list) {
      @if $i != $index {
        $result: append($result, nth($list, $i));
      }
    }
  }

  @return $result;
}

// list to string
@function to-string($list, $glue: '', $is-nested: false) {
  $result: null;

  @for $i from 1 through length($list) {
    $e: nth($list, $i);

    @if type-of($e) == list {
      $result: $result#{to-string($e, $glue, true)};
    } @else {
      $result: if($i != length($list) or $is-nested, #{$result}#{$e}#{$glue}, #{$result}#{$e});
    }
  }

  @return $result;
}