////////////////////////////// // Import Parser Pieces ////////////////////////////// @import “parsers/query”; @import “parsers/single”; @import “parsers/double”; @import “parsers/triple”; @import “parsers/resolution”;

$Memo-Exists: function-exists(memo-get) and function-exists(memo-set);

////////////////////////////// // Breakpoint Function ////////////////////////////// @function breakpoint($query, $contexts…) {

$run: true;
$return: ();

// Grab the Memo Output if Memoization can be a thing
@if $Memo-Exists {
  $return: memo-get(breakpoint, breakpoint $query $contexts);

  @if $return != null {
    $run: false;
  }
}

@if not $Memo-Exists or $run {
  // Internal Variables
  $query-string: '';
  $query-fallback: false;
  $return: ();

  // Reserve Global Private Breakpoint Context
  $holder-context: $private-breakpoint-context-holder;
  $holder-query-count: $private-breakpoint-query-count;

  // Reset Global Private Breakpoint Context
  $private-breakpoint-context-holder: () !global;
  $private-breakpoint-query-count: 0 !global;

  // Test to see if it's a comma-separated list
  $or-list: if(list-separator($query) == 'comma', true, false);

  @if ($or-list == false and breakpoint-get('legacy syntax') == false) {
    $query-string: breakpoint-parse($query);
  }
  @else {
    $length: length($query);

    $last: nth($query, $length);
    $query-fallback: breakpoint-no-query($last);

    @if ($query-fallback != false) {
      $length: $length - 1;
    }

    @if (breakpoint-get('legacy syntax') == true) {
      $mq: ();

      @for $i from 1 through $length {
        $mq: append($mq, nth($query, $i), comma);
      }

      $query-string: breakpoint-parse($mq);
    }
    @else {
      $query-string: '';
      @for $i from 1 through $length {
        $query-string: $query-string + if($i == 1, '', ', ') + breakpoint-parse(nth($query, $i));
      }
    }
  }

  $return: ('query': $query-string,
      'fallback': $query-fallback,
      'context holder': $private-breakpoint-context-holder,
      'query count': $private-breakpoint-query-count
  );
  @if length($contexts) > 0 and nth($contexts, 1) != false {
    @if $query-fallback != false {
      $context-setter: private-breakpoint-set-context('no-query', $query-fallback);
    }
    $context-map: ();
    @each $context in $contexts {
      $context-map: map-merge($context-map, ($context: breakpoint-get-context($context)));
    }
    $return: map-merge($return, (context: $context-map));
  }

  // Reset Global Private Breakpoint Context
  $private-breakpoint-context-holder: () !global;
  $private-breakpoint-query-count: 0 !global;

  @if $Memo-Exists {
    $holder: memo-set(breakpoint, breakpoint $query $contexts, $return);
  }
}

@return $return;

}

////////////////////////////// // General Breakpoint Parser ////////////////////////////// @function breakpoint-parse($query) {

// Increase number of 'and' queries
$private-breakpoint-query-count: $private-breakpoint-query-count + 1 !global;

// Set up Media Type
$query-print: '';

$force-all: ((breakpoint-get('force all media type') == true) and (breakpoint-get('default media') == 'all'));
$empty-media: true;
@if ($force-all == true) or (breakpoint-get('default media') != 'all') {
  // Force the print of the default media type if (force all is true and default media type is all) or (default media type is not all)
  $query-print: breakpoint-get('default media');
  $empty-media: false;
}

$query-resolution: false;

$query-holder: breakpoint-parse-query($query);

// Loop over each parsed out query and write it to $query-print
$first: true;

@each $feature in $query-holder {
  $length: length($feature);

  // Parse a single feature
  @if ($length == 1) {
    // Feature is currently a list, grab the actual value
    $feature: nth($feature, 1);

    // Media Type must by convention be the first item, so it's safe to flat override $query-print, which right now should only be the default media type
    @if (breakpoint-is-media($feature)) {
      @if ($force-all == true) or ($feature != 'all') {
        // Force the print of the default media type if (force all is true and default media type is all) or (default media type is not all)
        $query-print: $feature;
        $empty-media: false;

        // Set Context
        $context-setter: private-breakpoint-set-context(media, $query-print);
      }
    }
    @else {
      $parsed: breakpoint-parse-single($feature, $empty-media, $first);
      $query-print: '#{$query-print} #{$parsed}';
      $first: false;
    }
  }
  // Parse a double feature
  @else if ($length == 2) {
    @if (breakpoint-is-resolution($feature) != false) {
      $query-resolution: $feature;
    }
    @else {
      $parsed: null;
      // If it's a string/number pair,
      // we check to see if one is a single-string value,
      // then we parse it as a normal double
      $alpha: nth($feature, 1);
      $beta: nth($feature, 2);
      @if breakpoint-single-string($alpha) or breakpoint-single-string($beta) {
        $parsed: breakpoint-parse-single($alpha, $empty-media, $first);
        $query-print: '#{$query-print} #{$parsed}';
        $first: false;
        $parsed: breakpoint-parse-single($beta, $empty-media, $first);
        $query-print: '#{$query-print} #{$parsed}';
      }
      @else {
        $parsed: breakpoint-parse-double($feature, $empty-media, $first);
        $query-print: '#{$query-print} #{$parsed}';
        $first: false;
      }
    }
  }
  // Parse a triple feature
  @else if ($length == 3) {
    $parsed: breakpoint-parse-triple($feature, $empty-media, $first);
    $query-print: '#{$query-print} #{$parsed}';
    $first: false;
  }

}

@if ($query-resolution != false) {
  $query-print: breakpoint-build-resolution($query-print, $query-resolution, $empty-media, $first);
}

// Loop through each feature that's been detected so far and append 'false' to the the value list to increment their counters
@each $f, $v in $private-breakpoint-context-holder {
  $v-holder: $v;
  $length: length($v-holder);
  @if length($v-holder) < $private-breakpoint-query-count {
    @for $i from $length to $private-breakpoint-query-count {
      @if $f == 'media' {
        $v-holder: append($v-holder, breakpoint-get('default media'));
      }
      @else {
        $v-holder: append($v-holder, false);
      }
    }
  }
  $private-breakpoint-context-holder: map-merge($private-breakpoint-context-holder, ($f: $v-holder)) !global;
}

@return $query-print;

}