/**
 * Checks if a list contains a certain value.
 * 
 * @param {list} $list - the list to check
 * @param {value} $var - the value to search for
 * @param {bool} $recursive (false) - should any contained lists be checked for the value
 * 
 * @return {bool} true if the value is found from the list, false otherwise
 * 
 * @group lists
 */
@function contains($list, $value, $recursive: false) {
  @if $recursive == false {
    @return (false != index($list, $value));
  }

  $ret: false;
  @each $item in $list {
    @if type-of($item) == list and $recursive {
      @if contains($item, $value, true) {
        @return true;
      }
    } @else if $item == $value {
      @return true;
    }
  }

  @return false;
}


/**
 * Check whether a list contains nested lists.
 * 
 * @param {list} $list - the list to check
 * 
 * @return {bool} true of the list contains other nested lists, false otherwise
 * 
 * @group lists
 */
@function list-of-lists($list) {
  @each $part in $list {
    @if type-of($part) != list {
      @return false;
    }
  }
  @return true;
}


/**
 * Get the first color value from a list.
 * 
 * @param {list} $list - a list which should contain a color value
 * 
 * @return {color} The first color encountered in the list
 * 
 * @group lists
 */
@function first-color($list) {
  @return first-of-type($list, color);
}


/**
 * Get the first number value from a list.
 * 
 * @param {list} $list - a list which should contain a number value
 * 
 * @return {number} The first number encountered in the list
 * 
 * @group lists
 */
@function first-number($list) {
  @return first-of-type($list, number);
}


/**
 * Get the first string value from a list.
 * 
 * @param {list} $list - a list which should contain a string value
 * 
 * @return {string} The first string encountered in the list
 * 
 * @group lists
 */
@function first-string($list) {
  @return first-of-type($list, string);
}


/**
 * Get the first contained list from the list passed as the parameter.
 * 
 * @param {list} $list - a list which should contain a nested list
 * 
 * @return {list} The first list encountered in the list passed as the parameter
 * 
 * @group lists
 */
@function first-list($list) {
  @return first-of-type($list, list);
}


/**
 * Get the first value of a certain type from a list.
 * 
 * @param {list} $list - a list which should contain a value of the certain type
 * @param {string} $type - the type of value to search for
 * 
 * @return {value} The first item of the certain type encountered in the list
 * 
 * @group lists
 */
@function first-of-type($list, $type) {
  @each $item in $list {
    @if type-of($item) == $type {
      @return $item;
    } @else if type-of($item) == list {
      $ret: first-of-type($item, $type);
      @if $ret {
        @return $ret;
      }
    }
  }
  @return null;
}


/**
 * Flatten nested lists to one list, while maintaining the original list separators.
 * 
 * @param {list} $list - the list to flatten
 * 
 * @return {list} the same list with all nested lists flattened
 * 
 * @group lists
 */
@function flatten-list($list) {
  $ret: ();
  @each $item in $list {
    @if type-of($item) != list and $item != null {
      $ret: join($ret, $item);
    } @else if length($item) > 0 and $item != null {
      $t: flatten-list($item);
      @if length($t) > 0 {
        $ret: join($ret, $t);
      }
    }
  }
  @return $ret;
}




// Author: Hugo Giraudel
// Repository: https://github.com/Team-Sass/Sass-list-functions
// License: MIT


@function first($list) {
  @return nth($list, 1);
}


@function last($list) {
  @return nth($list, length($list));
}


@function last-index($list, $value) {
  @for $i from length($list)*-1 through -1 {
    @if nth($list, abs($i)) == $value {
      @return abs($i);
    }
  }

  @return null;
}


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


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


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

  @if type-of($index) != number {
    @warn "$index: #{quote($index)} is not a number for `insert-nth`.";
    @return $result;
  }

  @else if $index < 1 {
    @warn "List index 0 must be a non-zero integer for `insert-nth`";
    @return $result;
  }

  @else if $index > length($list) {
    @warn "List index is #{$index} but list is only #{length($list)} item long for `insert-nth'.";
    @return $result;
  }

  @else {
    $result: ();

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

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

  @return $result;
}


@function replace-nth($list, $index, $value) {
  $result: false;

  @if type-of($index) != number {
    @warn "$index: #{quote($index)} is not a number for `replace-nth`.";
    @return $result;
  }

  @else if $index == 0 {
    @warn "List index 0 must be a non-zero integer for `replace-nth`.";
    @return $result;
  }

  @else if abs($index) > length($list) {
    @warn "List index is #{$index} but list is only #{length($list)} item long for `replace-nth`.";
    @return $result;
  }

  @else {
    $result: ();
    $index: if($index < 0, length($list) + $index + 1, $index);

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

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

  @return $result;
}


@function replace($list, $old-value, $new-value, $recursive: false) {
  $result: ();

  @for $i from 1 through length($list) {
    @if type-of(nth($list, $i)) == list and $recursive {
      $result: append($result, replace(nth($list, $i), $old-value, $new-value, $recursive));
    }

    @else {
      @if nth($list, $i) == $old-value {
        $result: append($result, $new-value);
      }

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

  @return $result;
}


@function remove-nth($list, $index) {
  $result: false;

  @if type-of($index) != number {
    @warn "$index: #{quote($index)} is not a number for `remove-nth`.";
    @return $result;
  }

  @else if $index == 0 {
    @warn "List index 0 must be a non-zero integer for `remove-nth`.";
    @return $result;
  }

  @else if abs($index) > length($list) {
    @warn "List index is #{$index} but list is only #{length($list)} item long for `remove-nth`.";
    @return $result;
  }

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


@function remove($list, $value, $recursive: false) {
  $result: ();

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

    @else if nth($list, $i) != $value {
      $result: append($result, nth($list, $i));
    }
  }

  @return $result;
}


@function slice($list, $start: 1, $end: length($list)) {
  $result: false;

  @if type-of($start) != number or type-of($end) != number {
    @warn "Either $start or $end are not a number for `slice`.";
    @return $result;
  }

  @else if $start > $end {
    @warn "The start index has to be lesser than or equals to the end index for `slice`.";
    @return $result;
  }

  @else if $start < 1 or $end < 1 {
    @warn "List indexes must be non-zero integers for `slice`.";
    @return $result;
  }

  @else if $start > length($list) {
    @warn "List index is #{$start} but list is only #{length($list)} item long for `slice`.";
    @return $result;
  }

  @else if $end > length($list) {
    @warn "List index is #{$end} but list is only #{length($list)} item long for `slice`.";
    @return $result;
  }

  @else {
    $result: ();

    @for $i from $start through $end {
      $result: append($result, nth($list, $i));
    }
  }

  @return $result;
}


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


@function shift($list, $value: 1) {
  $result: ();

  @for $i from 0 to length($list) {
    $result: append($result, nth($list, ($i - $value) % length($list) + 1));
  }

  @return $result;
}
