// @private Default font-size for all browsers
$browser-default-font-size: 16px;

// Base font size in pixels, if not already defined.
// Should be the same as the font-size of the html element.
$base-font-size: 16px !default;

// Whether to output fallback values in px when outputting rems.
$rem-with-px-fallback: true !default;

// Convert any CSS <length> or <percentage> value to any another.
//
// @param $length
//   A css <length> or <percentage> value
//
// @param $to-unit
//   String matching a css unit keyword, e.g. 'em', '%', etc.
//
// @param $from-context
//   When converting from relative units, the absolute length (in px) to
//   which $length refers (e.g. for $lengths in em units, would normally be the
//   font-size of the current element).
//
// @param $to-context
//   For converting to relative units, the absolute length in px to which the
//   output value will refer. Defaults to the same as $from-context, since it is
//   rarely needed.
@function convert-length(
  $length,
  $to-unit,
  $from-context: $base-font-size,
  $to-context: $from-context
) {

  $from-unit: unit($length);

  // Optimize for cases where `from` and `to` units are accidentally the same.
  @if $from-unit == $to-unit { @return $length; }

  // Context values must be in px so we can determine a conversion ratio for
  // relative units.
  @if unit($from-context) != 'px' { @warn "Paremeter $from-context must resolve to a value in pixel units."; }
  @if unit($to-context) != 'px' { @warn "Parameter $to-context must resolve to a value in pixel units."; }

  // Convert input length to pixels
  $px-length: $length;

  @if $from-unit != 'px' {
    // Convert relative units using the from-context parameter.
    @if      $from-unit == 'em'  { $px-length: $length * $from-context / 1em }
    @else if $from-unit == 'rem' { $px-length: $length * $base-font-size / 1rem }
    @else if $from-unit == '%'   { $px-length: $length * $from-context / 100% }
    @else if $from-unit == 'ex'  { $px-length: $length * $from-context / 2ex }
    // Convert absolute units using Sass' conversion table.
    @else if $from-unit == 'in'  or
             $from-unit == 'mm'  or
             $from-unit == 'cm'  or
             $from-unit == 'pt'  or
             $from-unit == 'pc'  { $px-length: 0px + $length }
    // Certain units can't be converted.
    @else if $from-unit == 'ch'  or
             $from-unit == 'vw'  or
             $from-unit == 'vh'  or
             $from-unit == 'vmin' {
      @warn "#{$from-unit} units can't be reliably converted; Returning original value.";
      @return $length;
    }
    @else {
      @warn "#{$from-unit} is an unknown length unit. Returning original value.";
      @return $length;
    }
  }

  // Convert length in pixels to the output unit
  $output-length: $px-length;
  @if $to-unit != 'px' {
    // Relative units
    @if      $to-unit == 'em'  { $output-length: $px-length * 1em / $to-context }
    @else if $to-unit == 'rem' { $output-length: $px-length * 1rem / $base-font-size }
    @else if $to-unit == '%'   { $output-length: $px-length * 100% / $to-context }
    @else if $to-unit == 'ex'  { $output-length: $px-length * 2ex / $to-context }
    // Absolute units
    @else if $to-unit == 'in'  { $output-length: 0in + $px-length }
    @else if $to-unit == 'mm'  { $output-length: 0mm + $px-length }
    @else if $to-unit == 'cm'  { $output-length: 0cm + $px-length }
    @else if $to-unit == 'pt'  { $output-length: 0pt + $px-length }
    @else if $to-unit == 'pc'  { $output-length: 0pc + $px-length }
    // Non-convertible units
    @else if $to-unit == 'ch'  or
             $to-unit == 'vw'  or
             $to-unit == 'vh'  or
             $to-unit == 'vmin' {
      @warn "#{$to-unit} units can't be reliably converted; Returning original value.";
      @return $length;
    }
    @else {
      @warn "#{$to-unit} is an unknown length unit. Returning original value.";
      @return $length;
    }
  }

  @return $output-length;
}


// Output a given style rule containing rem values along with an (optional)
// fallback rule for older browsers (with rem values converted to px).
//
// @param $property
//   The css property name.
//
// @param $values
//   The value (or space-separated list of values) for the property.
//
// @param $use-px-fallback
//   [ true | false ]
//
@mixin rem($property, $values, $use-px-fallback: $rem-with-px-fallback) {
  // Create a couple of empty lists as output buffers.
  $px-values: ();
  $rem-values: ();

  // Loop through the $values list
  @each $value in $values {
    // For each property value, if it's in rem or px, derive both rem and
    // px values for it and add those to the end of the appropriate buffer.
    // Ensure all pixel values are rounded to the nearest pixel.
    @if type-of($value) == number and not unitless($value) and (unit($value) == px or unit($value) == rem) {
      @if unit($value) == px {
        $px-values: join($px-values, round($value));
        $rem-values: join($rem-values, convert-length($value, rem));
      }
      @else {
        $px-values: join($px-values, round(convert-length($value, px)));
        $rem-values: join($rem-values, $value);
      }
    }
    @else {
      $px-values: join($px-values, $value);
      $rem-values: join($rem-values, $value);
    }
  }

  // Use pixel fallback for browsers that don't understand rem units.
  @if $use-px-fallback {
    #{$property}: $px-values;
  }

  // Use rem values for everyone else (overrides pixel values).
  #{$property}: $rem-values;
}

@mixin if-rem($property, $values, $use-px-fallback: $rem-with-px-fallback) {
  $has-rem: false;
  @each $value in $values { $has-rem: if(unit($value) == 'rem', true, $has-rem); }
  @if $has-rem { @include rem($property, $values, $use-px-fallback); }
  @else { #{$property}: $values; }
}

