// SASSY MODULAR-SCALE
// https://github.com/scottkellum/modular-scale

// Defaults
$ratio: golden_ratio() !default;
$base-size: 16px !default;
$round-pixels: true !default;

// Modular Scale function
@function modular-scale($multiple, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
  
  // return the $base-size if $multiple is zero
  @if $multiple == 0 {
    @if type-of($base-size) == "list" {
      $base-size: sort_list($base-size);
      @return nth($base-size, 1);
    }
    
    // return just the simple $base-size value if it's not a list
    @return $base-size;
  }
  
  // if multiple base-sizes are passed in as a list
  // and multiple ratios are passed in as a list
  // calculate values in using each base-size / ratio combination
  @if type-of($base-size) == "list" and type-of($ratio) == "list" {
    @if unit(ms-multibase-multiratio($multiple, $base-size, $ratio)) == "px" and $round-pixels == true {
      @return round(ms-multibase-multiratio($multiple, $base-size, $ratio));
    }
    @return ms-multibase-multiratio($multiple, $base-size, $ratio);
  }
  
  // if multiple base-sizes are passed in as a list
  // calculate values in using each base-size
  @if type-of($base-size) == "list" and type-of($ratio) == "number" {
    @if unit(ms-multibase($multiple, $base-size, $ratio)) == "px" and $round-pixels == true {
      @return round(ms-multibase($multiple, $base-size, $ratio));
    }
    @return ms-multibase($multiple, $base-size, $ratio);
  }
  
  // if multiple ratios are passed in as a list
  // calculate values in using each ratio
  @if type-of($base-size) == "number" and type-of($ratio) == "list" {
    @if unit(ms-multiratio($multiple, $base-size, $ratio)) == "px" and $round-pixels == true {
      @return round(ms-multiratio($multiple, $base-size, $ratio));
    }
    @return ms-multiratio($multiple, $base-size, $ratio);
  }
  
  // If there are no lists just run the simple function
  @if unit(power($ratio, $multiple) * $base-size) == "px" and $round-pixels == true {
    @return round(power($ratio, $multiple) * $base-size);
  }
  @return power($ratio, $multiple) * $base-size;
}

// calculate values in using each base-size / ratio combination
@function ms-multibase-multiratio($multiple, $base-size: $base-size, $ratio: $ratio) {
  
  // start with an empty list to place all values in
  $scale-values: ();
  
  // make sure base sizes are in ascending order
  $base-size: sort_list($base-size);
  
  // take each base-size in turn
  $k: 1;
  @while $k <= length($base-size) {
    
    // add each $base-size to the list except the first
    @if $k > 1 {
      $scale-values: append($scale-values, nth($base-size, $k));
    }
    
    // take each ratio in turn
    $j: 1;
    @while $j <= length($ratio) {
      
      // reset $modular-scale for each set
      $modular-scale: nth($base-size, $k);
      
      // do the scale for each base-size using this ratio
      @if $multiple > 0 {
        
        // up $multiple times
        // and add the result to $scale-values
        @for $i from 1 through $multiple {
          $modular-scale: power(nth($ratio, $j), $i) * nth($base-size, $k);
          $scale-values: append($scale-values, $modular-scale);
        }
        
        // and down until the value is lower than the lowest $base-size
        // and add the result to $scale-values
        $i: -1;
        $modular-scale: nth($base-size, $k);
        @while $modular-scale >= nth($base-size, 1) {
          $modular-scale: power(nth($ratio, $j), $i) * nth($base-size, $k);
          $scale-values: append($scale-values, $modular-scale);
          $i: $i - 1;
        }
      }
      @if $multiple < 0 {
        
        // do the scale down for each set to below 1px
        $i: 0;
        $modular-scale: nth($base-size, $k);
        @while $i >= $multiple {
          $modular-scale: power(nth($ratio, $j), $i) * nth($base-size, $k);
          $scale-values: append($scale-values, $modular-scale);
          $i: $i - 1;
        }
      }
      $j: $j + 1;
    }
    $k: $k + 1;
  }
  
  // return trimmed and sorted final list
  @return trim-sort($multiple, $scale-values, $base-size);
}

// calculate values in using each base-size
@function ms-multibase($multiple, $base-size: $base-size, $ratio: $ratio) {
  
  // start with an empty list to place all values in
  $scale-values: ();
  
  // make sure base sizes are in ascending order
  $base-size: sort_list($base-size);
  
  // take each base-size in turn
  $k: 1;
  @while $k <= length($base-size) {
    
    // add each $base-size to the list except the first
    @if $k > 1 {
      $scale-values: append($scale-values, nth($base-size, $k));
    }
    
    // reset $modular-scale for each set
    $modular-scale: nth($base-size, $k);
    
    // do the scale for each base-size using this ratio
    @if $multiple > 0 {
      
      // up $multiple times
      // and add the result to $scale-values
      @for $i from 1 through $multiple {
        $modular-scale: power($ratio, $i) * nth($base-size, $k);
        $scale-values: append($scale-values, $modular-scale);
      }
      
      // and down until the value is lower than the lowest $base-size
      // and add the result to $scale-values
      $i: -1;
      $modular-scale: nth($base-size, $k);
      @while $modular-scale >= nth($base-size, 1) {
        $modular-scale: power($ratio, $i) * nth($base-size, $k);
        $scale-values: append($scale-values, $modular-scale);
        $i: $i - 1;
      }
    }
    @if $multiple < 0 {
      
      // do the scale down for each set to below 1px
      $i: 0;
      $modular-scale: nth($base-size, $k);
      @while $i >= $multiple {
        $modular-scale: power($ratio, $i) * nth($base-size, $k);
        $scale-values: append($scale-values, $modular-scale);
        $i: $i - 1;
      }
    }
    $k: $k + 1;
  }
  
  // return trimmed and sorted final list
  @return trim-sort($multiple, $scale-values, $base-size);
}

// calculate values in using each ratio
@function ms-multiratio($multiple, $base-size: $base-size, $ratio: $ratio) {
  
  // start with an empty list to place all values in
  $scale-values: ();
  
  // If $multiple is a positive integer (up the scale)
  @if $multiple > 0 {
    
    // take each ratio in turn
    $j: 1;
    @while $j <= length($ratio) {
      
      // reset $modular-scale for each set
      $modular-scale: $base-size;
      
      // do the scale using this ratio thru the multiple, and add the result to $scale-values
      @for $i from 1 through $multiple {
        $modular-scale: power(nth($ratio, $j), $i) * $base-size;
        $scale-values: append($scale-values, $modular-scale);
      }
      $j: $j + 1;
    }
    
    // sort acsending
    $scale-values: sort_list($scale-values);
    
    // return the final value using the laced list
    @return nth($scale-values, $multiple);
  }
  
  // If $multiple is a negative integer (down the scale)
  @if $multiple < 0 {
    
    // take each ratio in turn
    $j: 1;
    @while $j <= length($ratio) {
      
      // reset $modular-scale for each set
      $modular-scale: $base-size;
      
      // do the scale using this ratio thru the multiple, and add the result to $scale-values
      @for $i from 1 through $multiple * -1 {
        $modular-scale: power(nth($ratio, $j), -$i) * $base-size;
        $scale-values: append($scale-values, $modular-scale);
      }
      $j: $j + 1;
    }
    
    // sort decending
    $scale-values: reverse_list(sort_list($scale-values));
    
    // return the final value using the laced list
    @return nth($scale-values, $multiple * -1);
  }
}

// trim and sort the final list
@function trim-sort($multiple, $scale-values: $scale-values, $base-size: $base-size) {
  @if $multiple > 0 {
    
    // trim list so we can count from the lowest $base-size
    $scale-values: trim_list($scale-values, nth($base-size, 1), true);
    
    // sort acsending
    $scale-values: sort_list($scale-values);
    
    // return the final value using the laced list
    @return nth($scale-values, $multiple);
  }
  @else {
    
    // trim list so we can count from the lowest $base-size
    $scale-values: trim_list($scale-values, nth($base-size, 1), false);
    
    // sort acsending
    $scale-values: reverse_list(sort_list($scale-values));
    
    // return the final value using the laced list
    @return nth($scale-values, -$multiple);
  }
}

/////////////////////////////////////////////////////////////////////////

// alias for golden_ratio()
@function golden() {
  @return golden_ratio();
}

// Shortcut
@function ms($multiple, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
  // Return the value from the Modular Scale function
  @return modular-scale($multiple, $base-size, $ratio, $round-pixels);
}

// Write Modular Scale List
@function modular-scale-list($start: 0, $finish: 20, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
  $ms-list: unquote("MS-LIST:");
  @for $i from $start through $finish {
    $ms-list: append($ms-list, ms($i, $base-size, $ratio, $round-pixels));
  }
  @return $ms-list;
}

@function ms-list($start: 0, $finish: 20, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
  @return modular-scale-list($start, $finish, $base-size, $ratio, $round-pixels);
}

@mixin modular-scale-list($start: 0, $finish: 20, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
  @debug modular-scale-list($start, $finish, $base-size, $ratio, $round-pixels);
}

@mixin ms-list($start: 0, $finish: 20, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
  @debug modular-scale-list($start, $finish, $base-size, $ratio, $round-pixels);
}

@mixin modular-scale-list-output($start: 0, $finish: 20, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
    MODULAR-SCALE-LIST {
      ms-list: modular-scale-list($start, $finish, $base-size, $ratio, $round-pixels);
    }
  }

@mixin ms-list-output($start: 0, $finish: 20, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
  @include modular-scale-list-output($start, $finish, $base-size, $ratio, $round-pixels);
}

// Other libraries can easily query if this function is avalible
$modular-scale-loaded: true;