/// Shorthand Syntax Parser
/// =======================
/// The syntax parser converts [shorthand syntax][short]
/// into a map of settings that can be compared/merged with
/// other config maps and global setting.
///
/// [short]: api.html
///
/// @group _parser



// Parse
// -----
/// The `parse` function provides all the syntax-sugar in Susy,
/// converting user shorthand
/// into a usable map of keys and values
/// that can be normalized and passed to Su.
///
/// @group _parser
/// @see $susy
///
/// @param {list} $shorthand -
///   Shorthand expression to define the width of the span,
///   optionally containing:
///   - a count, length, or column-list span;
///   - `at $n`, `first`, or `last` location on asymmetrical grids;
///   - `narrow`, `wide`, or `wider` for optionally spreading
///     across adjacent gutters;
///   - `of $n <spread>` for available grid columns
///     and spread of the container
///     (span counts like `of 6` are only valid
///     in the context of symmetrical grids);
///   - and `set-gutters $n` to override global gutter settings
/// @param {bool} $context-only [false] -
///   Allow the parser to ignore span and span-spread values,
///   only parsing context and container-spread.
///   This makes it possible to accept spanless values,
///   like the `gutters()` syntax.
///   When parsing context-only,
///   the `of` indicator is optional.
///
/// @return {map} -
///   Map of span and grid settings
///   parsed from shorthand input –
///   including all the properties available globally –
///   `columns`, `gutters`, `spread`, `container-spread` –
///   along with the span-specific properties
///   `span`, and `location`.
///
/// @throw
///   when a shorthand value is not recognized
@function susy-parse(
  $shorthand,
  $context-only: false
) {
  $parse-error: 'Unknown shorthand property:';
  $options: (
    'first': 'location',
    'last': 'location',
    'alpha': 'location',
    'omega': 'location',
    'narrow': 'spread',
    'wide': 'spread',
    'wider': 'spread',
  );

  $return: ();
  $span: null;
  $columns: null;

  $of: null;
  $next: false;

  // Allow context-only shorthand, without span
  @if ($context-only) and (not index($shorthand, 'of')) {
    @if su-valid-columns($shorthand, 'fail-silent') {
      $shorthand: 'of' $shorthand;
    } @else {
      $shorthand: join('of', $shorthand);
    }
  }

  // loop through the shorthand list
  @for $i from 1 through length($shorthand) {
    $item: nth($shorthand, $i);
    $type: type-of($item);
    $error: false;
    $details: '[#{$type}] `#{$item}`';

    // if we know what's supposed to be coming next…
    @if $next {

      // Add to the return map
      $return: map-merge($return, ($next: $item));

      // Reset next to `false`
      $next: false;

    } @else { // If we don't know what's supposed to be coming…

      // Keywords…
      @if ($type == 'string') {
        // Check the map for keywords…
        @if map-has-key($options, $item) {
          $setting: map-get($options, $item);

          // Spread could be on the span or the container…
          @if ($setting == 'spread') and ($of) {
            $return: map-merge($return, ('container-spread': $item));
          } @else {
            $return: map-merge($return, ($setting: $item));
          }

        } @else if ($item == 'all') {
          // `All` is a span shortcut
          $span: 'all';
        } @else if ($item == 'at') {
          // Some keywords setup what's next…
          $next: 'location';
        } @else if ($item == 'set-gutters') {
          $next: 'gutters';
        } @else if ($item == 'of') {
          $of: true;
        } @else {
          $error: true;
        }

      } @else if ($type == 'number') or ($type == 'list') { // Numbers & lists…

        @if not ($span or $of) {
          // We don't have a span, and we're not expecting context…
          $span: $item;
        } @else if ($of) and (not $columns) {
          // We are expecting context…
          $columns: $item;
        } @else {
          $error: true;
        }

      } @else {
        $error: true;
      }
    }

    @if $error {
      @return _susy-error('#{$parse-error} #{$details}', 'susy-parse');
    }
  }

  // If we have span, merge it in
  @if $span {
    $return: map-merge($return, ('span': $span));
  }

  // If we have columns, merge them in
  @if $columns {
    $return: map-merge($return, ('columns': $columns));
  }

  // Return the map of settings…
  @return $return;
}
