/// List merge function
// --------------------------
/// Adds all items from list 2 to list 1 without creating doubles.
///
/// @access public
/// @group list utilities
///
/// @param {list} $list1
/// @param {list} $list2
///
/// @return {list}
///
@function list-merge($list1, $list2) {
  @each $item in $list2 {
    @if not list-contains($list1, $item) {
      $list1: append($list1, $item);
    }
  }
  @return $list1;
}

/// String to List function
// --------------------------
/// Converts a string into a list breaking it apart by the `separator`
///
/// @access public
/// @group list utilities
///
/// @param {string} $string
/// @param {string} $separator
/// @param {number} $startAt
///
/// @return {list}
///

@function str-to-list($string, $separator: ".", $startAt: 1) {
  $string: str-replace($string, "__", "."); //
  $string: str-replace($string, "--", "."); //
  $string: str-replace($string, "_", "."); //

  $workStr: str-slice($string, $startAt);
  $list: ();
  $indexOfFirstSpace: str-index($workStr, $separator);
  @if $indexOfFirstSpace == null {
    $list: ($workStr);
  } @else {
    $list: (str-slice($workStr, 1, $indexOfFirstSpace - 1)); //
    $list: join(
      $list,
      str-to-list($workStr, $separator, $startAt: $indexOfFirstSpace + 1)
    );
  }
  @return $list;
}

/// Prepend function
// --------------------------
/// Add a string value to a list.
///
/// @access public
/// @group list utilities
///
/// @param {list} $list
/// @param {string} $value
/// @param {string} $separator
///
/// @return {list}
///

@function prepend($list, $value, $seperator: space) {
  @return join($value, $list, $seperator);
}

/// To String function
// --------------------------
/// Converts a list to a string.
///
/// @access public
/// @group list utilities
///
/// @param {list} $list
/// @param {string} $glue
/// @param {boolean} $is-nested
///
/// @return {string}
///

@function simple-to-string($list, $glue) {
  $str: null;
  @for $i from 1 through length($list) {
    @if $i == 1 {
      $str: nth($list, $i);
    } @else {
      $str: unquote("#{$str}#{$glue}#{nth($list,$i)}");
    }
  }
  @return $str;
}

@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;
}

/// To List function
// --------------------------
/// Simple function to convert a value into a list.
///
/// @access public
/// @group list utilities
/// @param {string} $value
/// @return {string}
///
@function to-list($value) {
  @return if(type-of($value) != list, ($value), $value);
}

/// List length function
// --------------------------
/// Get the length of a list
///
/// @access public
/// @group list utilities
/// @param {list} $list
/// @return {number}
///
@function list-length($list) {
  $length: 0;
  @each $item in $list {
    $length: $length + 1;
  }
  @return $length;
}

// List to String function
// --------------------------
/// Converts a (multi dimensional) list to a string.
/// @access public
/// @group list utilities
///
/// @param {list} $list
/// @param {string} $separator
/// @param {boolean} $last
/// @output list
///

@function list-to-str($list, $separator: ", ", $last: true) {
  $string: "";
  @if list-length($list) > 0 {
    $string: nth($list, 1);

    @if list-length($list) > 1 {
      @for $i from 2 through list-length($list) {
        $item: nth($list, $i);
        @if $i == list-length($list) + 1 {
          $string: #{$string}#{$item};
        } @else {
          $string: #{$string}#{$separator}#{$item};
        }
      }
    }
  }

  @return $string;
}

// To Letter List function
// --------------------------
/// Returns a list with all letters of a string.
/// @access public
/// @group list utilities
///
/// @param {string} $string
/// @output list
///

@function to-letter-list($string) {
  $letters: ();
  @if type-of($string) == "string" {
    @for $i from 1 through str-length($string) {
      $letters: append($letters, str-slice($string, $i, $i));
    }
  } @else {
    @warn "#{$string} is not a string";
  }
  @return $letters;
}

// Shortests
// --------------------------
/// Returns the shortest list or string
/// @access public
/// @group list utilities
///
/// @param {list / string} $v1
/// @param {list / string}  $v2
/// @output list / string
///

@function shortest($v1, $v2) {
  @if type-of($v1) == type-of($v2) {
    @if type-of($v1) == "list" {
      @if length($v1) < length($v2) {
        @return $v1;
      } @else if length($v1) > length($v2) {
        @return $v2;
      } @else {
        @warn '#{$v1} (length #{length($v2)}) has the same length as #{$v2} (length #{length($v2)}), returned #{$v1}';
        @return $v1;
      }
    } @else if type-of($v1) == "string" {
      @if str-length($v1) < str-length($v2) {
        @return $v1;
      } @else if str-length($v1) > str-length($v2) {
        @return $v2;
      } @else {
        @warn '#{$v1} (length #{str-length($v2)}) has the same length as #{$v2} (length #{str-length($v2)}), returned #{$v1}';
        @return $v1;
      }
    }
  } @else {
    @warn 'Values do not have the same type.';
  }
}

// Remove Nth function
// --------------------------
/// Remove an item from a list at a certain index
/// @access public
/// @group list utilities
///
/// @param {list} $list
/// @param {number} $index
/// @output list
///

@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;
}

// Insert Nth function
// --------------------------
/// Inserts an item into a string at a certain index
/// @access public
/// @group list utilities
///
/// @param {list} $list
/// @param {number} $index
/// @param {string} $value
/// @output list
///

@function insert-nth($list, $index, $value) {
  $result: null;

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

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

      $result: append($result, nth($list, $i));
    }
  }
  @return $result;
}

// Key Index function
// --------------------------
/// Returns the index of a item in a list
/// @access public
/// @group list utilities
///
/// @param {list} $list
/// @param {string} $item
/// @output Boolean
///

@function key-index($list, $item) {
  $i: 0;
  @each $key, $value in $list {
    @if $key == $item {
      @return $i;
    }
    $i: $i + 1;
  }
  @return -1;
}

// List contains function
// --------------------------
/// Check if a list contains a value
/// @access public
/// @group list utilities
///
/// @param {list} $list
/// @param {string} $string
/// @output Boolean
///

@function list-contains($list, $string) {
  @each $value in $list {
    @if $value == $string {
      @return true;
    }
  }
  @return false;
}
// Reverse a list
// --------------------------
/// Reverse the lists order
/// @access public
/// @group list utilities
///
/// @param {list} $list
/// @param {recursive} boolean
/// @output $list
///

@function list-reverse($list, $recursive: false) {
  $result: ();

  @for $i from length($list) * -1 through -1 {
    @if type-of(nth($list, abs($i))) == list and $recursive {
      $result: append($result, reverse(nth($list, abs($i)), $recursive));
    } @else {
      $result: append($result, nth($list, abs($i)));
    }
  }

  @return $result;
}
