@use 'sass-mq/mq';
@use 'gel-sass-tools/sass-tools';
@use 'settings';
@use 'sass:map';
@use 'sass:math';
@use 'sass:meta';
@use 'sass:string';

///*------------------------------------*\
//    # GEL TYPOGRAPHY - TOOL
//\*------------------------------------*/

// If larger font sizes enable, merge them with gel-type-settings
@if settings.$gel-type-enable--larger-type-sizes {
  settings.$gel-type-settings: map.merge(
    settings.$gel-type-settings,
    settings.$gel-larger-font-sizes
  );
}

// Replace `$search` with `$replace` in `$string`
//
// @param {String} $string - Initial string
// @param {String} $search - Substring to replace
// @param {String} $replace ('') - New value
//
// @access private
//
// @return {String} - Updated string
//
// @author Hugo Giraudel
// @link http://bit.ly/1Khge01
//
@function _gel-str-replace($string, $search, $replace: '') {
  $index: string.index($string, $search);

  @if $index {
    @return string.slice($string, 1, $index - 1) + $replace +
      _gel-str-replace(string.slice($string, $index + string.length($search)), $search, $replace);
  }

  @return $string;
}

// Combine the the value of two Sass maps
//
// @param {Map} $source - The orignal Sass map
// @param {Map} $map - Sass map containing the new values to be combined
//
// @access private
//
// @return {Map} - New map consistenting of the values of both supplied maps
//
// @author Hugo Giraudel
// @link http://bit.ly/1PPIoj4
//
@function _gel-map-combine($source, $map) {
  @each $key, $value in $map {
    $new: (
      $key: $value,
    );

    @if map.has-key($source, $key) {
      $current: map.get($source, $key);
      $new: (
        $key: map.merge($current, $value),
      );
    }

    $source: map.merge($source, $new);
  }

  @return $source;
}

// Return the type settings for the requested type class/type group. If a bold variant is
// requested the bold type values will be combined with the type values of the non-bold
// variant.
//
// @param {String} $type-class - name of the type class you want the settings for (e.g. pica)
// @param {String} $type-group (all) - which type group you want the values for (e.g. group-a)
//
// @returns {Map} - a map of the type settings for the requested type class/type group
//
// @author Shaun Bent
// @author Adam Bulmer
//
@function gel-typography($type-class, $type-group: 'all') {
  $type-settings: map.get(settings.$gel-type-settings, $type-class);

  @if (string.index($type-class, '-bold')) {
    $root-type-group: map.get(settings.$gel-type-settings, _gel-str-replace($type-class, '-bold'));
    $type-settings: _gel-map-combine($root-type-group, $type-settings);
  }

  @if ($type-group != 'all') {
    @return map.get($type-settings, $type-group);
  }

  @return $type-settings;
}

// Output the type values for the requested type class (e.g pica). This will return all required media
// queries and no-touch fallbacks
//
// @param {String} $type-class - name of the type class to output the values for
//
// @author Shaun Bent
// @author Adam Bulmer
//
@mixin gel-typography($type-class) {
  $groupA: gel-typography($type-class, 'group-a');
  @include _gel-output-type-values($groupA);
  @include reith-letter-spacing($groupA);

  @include mq.mq($from: gel-bp-type-b) {
    $groupB: gel-typography($type-class, 'group-b');
    @include _gel-output-type-values($groupB);
    @include reith-letter-spacing($groupB);
  }

  @include mq.mq($from: gel-bp-type-c) {
    $groupC: gel-typography($type-class, 'group-c');
    @include _gel-output-type-values($groupC);
    @include reith-letter-spacing($groupC);

    .#{settings.$gel-type-touch-class} & {
      $groupNoTouch: gel-typography($type-class, settings.$gel-type-no-touch-group);
      @include _gel-output-type-values($groupNoTouch);
      @include reith-letter-spacing($groupNoTouch);
    }
  }
}

// Loop through a supplied Sass map and return each key/value as CSS properties
// and values. Any `px` value will be automatically passed to the `toRem` tool
//
// @param {Map} $type-values - a map of CSS values in property: value format
//
// @access private
//
// @author Shaun Bent
// @author Adam Bulmer
//
@mixin _gel-output-type-values($type-values) {
  @each $property, $value in $type-values {
    @if (meta.type-of($value) == number and math.unit($value) == 'px') {
      @include sass-tools.toRem($property, $value);
    } @else {
      #{$property}: $value;
    }
  }
}

@mixin reith-letter-spacing($type-settings) {
  @if (meta.type-of($type-settings) == 'map') {
    @if map.has-key($type-settings, 'letter-spacing') {
      .b-reith-sans-loaded &,
      .b-reith-serif-loaded & {
        letter-spacing: normal;
      }
    }
  }
}

// Output the typography styles for the 4 groups
@if settings.$gel-type-enable--markup-output {
  @each $type-class, $type-values in settings.$gel-type-settings {
    .#{settings.$gel-type-namespace}#{$type-class},
    %#{settings.$gel-type-namespace}#{$type-class} {
      @include gel-typography($type-class);
    }
  }
}

@if settings.$gel-type-enable--font-family {
  // Barlesque will set the correct font-family on the <body> tag but if you're working on a project
  // without Barlesque you might want to enable this flag
  //
  body {
    font-family: Helvetica, Arial, freesans, sans-serif;
  }
}

@if settings.$gel-type-enable--base-elements {
  // Map the GEL Typography classes to the relevant HTML elements
  //
  h1 {
    @extend %#{settings.$gel-type-namespace}trafalgar;
  }
  h2 {
    @extend %#{settings.$gel-type-namespace}double-pica;
  }
  h3 {
    @extend %#{settings.$gel-type-namespace}great-primer;
  }
  h4 {
    @extend %#{settings.$gel-type-namespace}pica;
  }
}
