// /*
//   inStyle (v1.6.1)
//   github.com/salsita/inStyle
//   2016 | MIT
//   ============================== */

// Configuration
$__inTagAppend: '<' !default
$__inTagInsert: '^' !default
$__inTagReplace: '@' !default

// String helpers
@function __trimString($string)
  $index: str-index($string, ' ')
  @if $index == 1
    @return __trimString(str-slice($string, $index + 1, -1))
  @else if $index == str-length($string)
    @return __trimString(str-slice($string, 1, $index - 1))
  @return $string

@function __stringToList($string, $delimiter: ',', $separator: comma)
  $list: ()
  $sum: str-length($string)
  @for $i from 1 through $sum
    $str: str-index($string, $delimiter)
    @if str-length($string) >= 1 and $str == null
      $list: append($list, unquote(__trimString($string)), $separator)
      $string: ''
    @if type-of($str) == number
      $each: str-slice($string, 0, ($str - 1))
      $list: append($list, unquote(__trimString($each)), $separator)
      $string: str-slice($string, ($str + 1), $sum)
  @return $list

// List helpers
@function __insertInList($list, $index, $value)
  $result: null
  @if $index > length($list)
    @warn "List index is #{$index} but list is only #{length($list)} items long for __insertInList()."
  @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 __removeFromList($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 __reverseList($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, __reverseList(nth($list, abs($i)), $recursive))
    @else
      $result: append($result, nth($list, abs($i)))
  @return $result

@function __listToString($list, $glue: '', $is-nested: false)
  $result: null
  @for $i from 1 through length($list)
    $e: nth($list, $i)
    @if type-of($e) == list
      $result: unquote("#{$result}#{to-string($e, $glue, true)}")
    @else
      $result: if($i != length($list) or $is-nested, unquote("#{$result}#{$e}#{$glue}"), unquote("#{$result}#{$e}"))
  @return $result

@function __removeDuplicatesFromList($list, $recursive: false, $separator: comma)
  $result: ()
  @each $item in $list
    @if not index($result, $item)
      @if length($item) > 1 and $recursive
        $result: append($result, __removeDuplicatesFromList($item, $recursive), $separator)
      @else
        $result: append($result, $item, $separator)
  @return $result

// Custom helpers
@function __tagIndex($string, $tag)
  $index: 0
  @if str-index($string, $tag) == 1
    $index: 1
    $sum: str-length($string)
    @for $i from 2 through $sum
      @if str-slice($string, $i, $i) == $tag
        $index: $index + 1
      @else
        @return $index
  @return $index

@function __getDepthMap($selector, $current)
  $depthMap: ()
  @each $parent in $current
    // Save maximum length of matched compound to compare relevancy
    $parentIndex: index($current, $parent)
    $depthMap: append($depthMap, 0, comma)
    @each $compound in $selector
      // Check only for specific compound
      @if max(__tagIndex($compound, $__inTagInsert), __tagIndex($compound, $__inTagAppend), __tagIndex($compound, $__inTagReplace)) == 0
        $simple: simple-selectors($compound)
        // Test all matches starting with full compound and reducing for each step
        @for $i from 1 through length($simple)
          @if $i > 1
            $simple: __removeFromList($simple, nth($simple, length($simple)))
          @if index($parent, __listToString($simple)) and length($simple) > nth($depthMap, $parentIndex)
            // Relevancy scoring
            $depthIndex: index(__reverseList($parent), __listToString($simple)) + (length($simple) / 1000)
            $depthMap: set-nth($depthMap, $parentIndex, $depthIndex)
  @return $depthMap

// In mixin
=in($selectors)
  $final: ()
  $current: &
  $selectors: __stringToList($selectors)
  $startIndex: 1 // Start indexing above current element
  $checkDupes: false

  @each $selector in $selectors
    // Trim all extra empty spaces
    $selector: __removeFromList(__stringToList($selector, ' ', space), '')
    // Render only best matching parents in multiselectors
    $depthMap: if(length($current) == 1, 0, __getDepthMap($selector, $current))
    @for $n from 1 through length($current)
      @if nth($depthMap, $n) == max($depthMap...)
        $parent: nth($current, $n)
        $newParent: __reverseList($parent)
        $insertQueue: () // Save insertions to process later

        // Process modifications RTL
        @each $compound in __reverseList($selector)
          $appendIndex: __tagIndex($compound, $__inTagAppend)
          $insertIndex: __tagIndex($compound, $__inTagInsert)
          $replaceIndex: __tagIndex($compound, $__inTagReplace)
          $changeIndex: max($appendIndex, $insertIndex, $replaceIndex) + $startIndex

          // OUT_OF_BOUNDS check
          @if $changeIndex > length($parent)
            @error 'OUT_OF_BOUNDS: \'#{$compound}\' modification outside of \'#{$parent} {}\' (#{$changeIndex} vs #{length($parent)}).'

          @if $insertIndex > 0
            // Add to insertion queue
            $insertQueue: append($insertQueue, $compound)

          @else if $replaceIndex > 0
            // Replace
            $validatedCompound: __listToString(simple-selectors(str-slice($compound, $replaceIndex + 1)))
            $newParent: set-nth($newParent, $startIndex + $replaceIndex, $validatedCompound)
            $checkDupes: true

          @else if $appendIndex > 0
            // Append with tag
            $validatedCompound: nth($newParent, $startIndex + $appendIndex) + __listToString(simple-selectors(str-slice($compound, $appendIndex + 1)))
            $newParent: set-nth($newParent, $startIndex + $appendIndex, $validatedCompound)

          @else
            // Append with selector
            $simple: simple-selectors($compound)
            $state: ()
            $matched: false
            // Loop compound variants
            @for $i from 1 through length($simple)
              @if $i > 1
                $state: join(nth($simple, length($simple)), $state)
                $simple: __removeFromList($simple, nth($simple, length($simple)))
              $trySimple: __listToString($simple)
              $tryState: if($i > 1, __listToString($state), '')
              // Match base to reversed parent list
              @for $n from ($startIndex + 1) through length($newParent)
                @if $n <= length($newParent) and $trySimple == nth($newParent, $n)
                  // Append to matched parent selector
                  $matched: true
                  $newParent: set-nth($newParent, $n, unquote($trySimple + $tryState))
            @if not $matched
              @error 'OUT_OF_BOUNDS: \'#{nth($simple, 1)}\' not found in \'#{$parent}\'.'

        // Process insertion queue
        @if length($insertQueue) > 0
          $insertIndexes: ()
          @each $insert in $insertQueue
            $insertIndex: __tagIndex($insert, $__inTagInsert)
            $validatedCompound: __listToString(simple-selectors(str-slice($insert, $insertIndex + 1)))
            // Find how many previous inserts were lower than current
            $addIndex: 0
            @each $index in $insertIndexes
              @if $insertIndex >= $index
                $addIndex: $addIndex + 1
            $insertIndexes: append($insertIndexes, $insertIndex)
            // Insert in selector
            $newIndex: $startIndex + $insertIndex + $addIndex
            $newParent: __insertInList($newParent, $newIndex, $validatedCompound)

        // Save modified selectors
        $final: append($final, __reverseList($newParent), comma)

  // Remove possible duplicates from multiselector replacement
  $final: if(length($final) > 1 and $checkDupes, __removeDuplicatesFromList($final), $final)
  // Render final selectors
  @at-root #{$final}
    @content