
/**
 * Update a deeply nested key
 *
 * @function
 * @author Hugo Giraudel
 * @param {Map} $map - Map to update
 * @param {Arglist} $keys - Keys to access to value to update
 * @param {*} $value - New value (last member of `$keys`)
 * @return {Map} - Updated map
 */
@function map-deep-set($map, $keys.../*, $value */) {
    $map-list: ($map,);
    $result: null;

    @if length($keys) == 2 {
        @return map-merge($map, (nth($keys, 1): nth($keys, -1)));
    }

    @for $i from 1 through length($keys) - 2 {
        $map-list: append($map-list, map-get(nth($map-list, -1), nth($keys, $i)));
    }

    @for $i from length($map-list) through 1 {
        $result: map-merge(nth($map-list, $i), (nth($keys, $i): if($i == length($map-list), nth($keys, -1), $result)));
    }

    @return $result;
}


/**
 * Returns the item named $key from $map.
 * If $key is not found $default is returned.
 *
 * @function
 * @param {Map} $map
 * @param {String} $key
 * @param {*} $default
 * @returns {*}
 */
@function map-get-default($map, $key, $default) {
    @if ($map) {
        @if (map-has-key($map, $key)) {
            @return map-get($map, $key);
        }
    }
    @return $default;
}


/**
 * Creates a property list based of $map.
 * Each property name is prefixed with $prefix.
 * When $ignore is given every property found in the list will be ignored.
 *
 * @function
 * @param {Map} $map
 * @param {String} $prefix
 * @param {List} $ignore
 * @returns {void}
 */
@mixin map-as-properties($map, $prefix: '', $ignore: none, $include: all) {
    @if ($map) {
        @each $property, $value in $map {
            @if (($ignore == none or not index($ignore, $property)) and ($include == all or index($include, $property))) {
                #{$prefix}#{$property}: $value;
            }
        }
    }
}

/**
 * Define hover styles for screens >= $breakpoint-global-hover
 *
 * @function
 * @param {boolean} $include-focus
 * @param {breakpoint} $hover-breakpoint
 * @returns {void}
 */
@mixin hover($include-focus: true, $hover-breakpoint: $breakpoint-global-hover) {

    @if $include-focus == true {
        &:focus {
            @content;
        }
    }

    @include use-breakpoint($hover-breakpoint, above) {
        &:hover {
            @content;
        }
    }
}

/**
 * Define keyboardfocus state
 *
 * @function
 * @returns {void}
 */
@mixin keyboard-focus {
    &:focus {
        &.has-keyboardfocus {
            @content;
        }
    }
}


/**
 * Adds a before element that will guarantee the defined aspect ration on a block element
 *
 * @function
 * @param $width
 * @param $height
 */
@mixin maintain-aspect-ratio($width, $height) {

    &::before {
        content: '';
        display: block;
        padding-top: ($height / $width) * 100%;
        width: 100%;
    }
}


/**
 * clearfix
 */
@mixin clearfix {
    &::after {
        clear: both;
        content: '';
        display: table;
    }
}
