/**
 * Outputs the selectors and properties for the Button component.
 *
 * @param {string} $primary-stylename (v-button) - the primary style name for the selectors
 * @param {bool} $include-additional-styles - should the mixin output all the different style variations of the component
 *
 * @group button
 */
@mixin valo-button ($primary-stylename: v-button, $include-additional-styles: contains($v-included-additional-styles, button)) {
  .#{$primary-stylename} {
    @include valo-button-static-style;
    @include valo-button-style;
  }


  @if $include-additional-styles {
    .#{$primary-stylename}-primary {
      @include valo-button-style($background-color: $v-selection-color);
      $padding-width: round($v-unit-size/2);
      padding: 0 $padding-width;
      font-weight: bold;
      $min-width: round($v-unit-size * 2.2);
      min-width: $min-width;
    }

    .#{$primary-stylename}-friendly {
      @include valo-button-style($background-color: $v-friendly-color);
    }

    .#{$primary-stylename}-danger {
      @include valo-button-style($background-color: $v-error-indicator-color);
    }

    .#{$primary-stylename}-borderless {
      @include valo-button-borderless-style;
    }

    .#{$primary-stylename}-borderless-colored {
      @include valo-button-borderless-style($font-color: $v-selection-color);
    }

    .#{$primary-stylename}-quiet {
      @include valo-button-quiet-style;
    }

    .#{$primary-stylename}-link {
      @include valo-button-borderless-style;
      @include valo-link-style;
    }

    .#{$primary-stylename}-tiny {
      @include valo-button-style($unit-size: $v-unit-size--tiny, $bevel: null, $shadow: null, $background-color: null, $font-size: $v-font-size--tiny, $font-weight: null);
    }

    .#{$primary-stylename}-small {
      @include valo-button-style($unit-size: $v-unit-size--small, $bevel: null, $shadow: null, $background-color: null, $font-size: $v-font-size--small, $font-weight: null);
    }

    .#{$primary-stylename}-large {
      @include valo-button-style($unit-size: $v-unit-size--large, $bevel: null, $shadow: null, $background-color: null, $font-size: $v-font-size--large, $font-weight: null);
    }

    .#{$primary-stylename}-huge {
      @include valo-button-style($unit-size: $v-unit-size--huge, $bevel: null, $shadow: null, $background-color: null, $font-size: $v-font-size--huge, $font-weight: null);
    }

    .#{$primary-stylename}-icon-align-right {
      @include valo-button-icon-align-right-style;
    }

    .#{$primary-stylename}-icon-align-top {
      @include valo-button-icon-align-top-style;
    }

    .#{$primary-stylename}-icon-only {
      width: $v-unit-size;
      padding: 0;

      &.#{$primary-stylename}-tiny {
        width: $v-unit-size--tiny;
      }

      &.#{$primary-stylename}-small {
        width: $v-unit-size--small;
      }

      &.#{$primary-stylename}-large {
        width: $v-unit-size--large;
      }

      &.#{$primary-stylename}-huge {
        width: $v-unit-size--huge;
      }

      .#{$primary-stylename}-caption {
        display: none;
      }
    }
  }
}


/**
 * Outputs the static styles (i.e. styles which don't differ between button variants) for a button.
 *
 * @param {list} $states (normal hover focus active disabled) - The button states for which to output corresponding static styles
 * @param {bool} $vertical-centering (true) - Should the output contain a vertical centering guide
 *
 * @group button
 */
@mixin valo-button-static-style ($states: (normal, hover, focus, active, disabled), $vertical-centering: true) {
  @if contains($states, normal) {
    position: relative;
    text-align: center;
    white-space: nowrap;
    outline: none;
    @include valo-tappable;
    @if $vertical-centering {
      @include valo-button-vertical-centering;
    }
  }

  @if contains($states, hover) or contains($states, focus) or contains($states, active) {
    // Generated element for :hover, :focus and :active styles
    &:after {
      content: "";
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      border-radius: inherit;
      @if $v-animations-enabled {
        @include transition(box-shadow 180ms, border 180ms);
      }
    }
  }

  @if contains($states, focus) {
    &:focus:after {
      @if $v-animations-enabled {
        @include transition(none);
      }
    }
  }

  @if contains($states, disabled) {
    &.v-disabled {
      @include opacity($v-disabled-opacity);

      &:after {
        display: none;
      }
    }
  }
}


/**
 * Outputs the styles for a button variant.
 *
 * @param {size} $unit-size ($v-unit-size) - The sizing of the button, which corresponds its height
 * @param {size | list} $padding (null) - The padding of the button. Computed from other parameters by default.
 * @param {color} $font-color (null) - The font color of the button. Computed from the $background-color by default.
 * @param {number} $font-weight ($v-font-weight + 100) - The font weight of the button
 * @param {size} $font-size (null) - The font size of the button. Inherited from the parent by default.
 * @param {string} $cursor (null) - The mouse cursor of the button
 * @param {color} $background-color ($v-background-color) - The background color of the button
 * @param {list} $border ($v-border) - The border of the button
 * @param {size} $border-radius ($v-border-radius) - The border-radius of the button
 * @param {list} $gradient ($v-gradient) - Valo specific gradient value. See the documentation for $v-gradient.
 * @param {list} $bevel ($v-bevel) - Box-shadow value according to $v-bevel documentation
 * @param {list} $shadow ($v-shadow) - Box-shadow value according to $v-shadow documentation
 * @param {list} $states (normal hover focus active disabled) - The button states for which to output corresponding styles
 *
 * @group button
 */
@mixin valo-button-style (
  $unit-size        : $v-unit-size,
  $padding          : null,

  $font-color       : null,
  $font-weight      : $v-font-weight + 100,
  $font-size        : null, // Inherited by default
  $cursor           : null,

  $background-color : $v-background-color,
  $border           : $v-border,
  $border-radius    : $v-border-radius,

  $gradient         : $v-gradient,
  $bevel            : $v-bevel,
  $shadow           : $v-shadow,

  $states           : (normal, hover, focus, active, disabled)
) {

  @if contains($states, focus) or contains($states, active) {
    $border-width: first-number($border);
    &:after {
      border: inherit;
      top: -$border-width;
      right: -$border-width;
      bottom: -$border-width;
      left: -$border-width;
    }
  }

  @if contains($states, normal) {
    @if $unit-size {
      height: $unit-size;
      @if type-of($padding) == number or type-of($padding) == list {
        padding: $padding;
      } @else {
        padding: 0 round($unit-size/2.4) + round($border-radius/3);
      }
    }

    $_font-color: $font-color or valo-font-color($background-color, 0.9);
    color: $_font-color;
    font-weight: $font-weight;
    font-size: $font-size;
    cursor: $cursor;

    border-radius: $border-radius;

    @if type-of($background-color) == color {
      @include valo-border-with-gradient($border: $border, $color: darkest-color($background-color, $v-background-color), $gradient: $gradient);
      @include valo-gradient($background-color, $gradient);
      @include box-shadow(valo-bevel-and-shadow($bevel: $bevel, $shadow: $shadow, $background-color: $background-color, $gradient: $gradient));
    }

    @if $bevel and type-of($_font-color) == color and type-of($background-color) == color {
      text-shadow: valo-text-shadow($_font-color, $background-color);
    }

    @if $bevel == none and $shadow == none {
      @include box-shadow(none);
    }
  }

  @if $background-color {
    @if contains($states, hover) {
      &:hover:after {
        @include valo-button-hover-style($background-color);
      }
    }

    @if contains($states, focus) {
      &:focus:after {
        @include valo-button-focus-style($background-color);
      }
    }

    @if contains($states, active) {
      &:active:after {
        @include valo-button-active-style($background-color);
      }
    }
  }
}


/**
 * Outputs the hover state styles for a button. The styles are by default targeted
 * for a pseudo element which is shown on top of the normal state button.
 *
 * @group button
 *
 * @param {color} $background-color ($v-background-color) - The background color of the normal state button
 */
@mixin valo-button-hover-style ($background-color: $v-background-color) {
  $bg: darken($background-color, 25%);
  @if is-dark-color($background-color) {
    $bg: lighten($background-color, 15%);
  }
  background-color: rgba($bg, .1);
}


/**
 * Outputs the focus state styles for a button. The styles are by default targeted
 * for a pseudo element which is shown on top of the normal state button.
 *
 * @group button
 *
 * @param {color} $background-color ($v-background-color) - The background color of the normal state button
 * @param {list} $border-fallback (inherit) - If the luminance of $v-focus-color is less than the $background-color, the focus color is also used for the border color. If not, then $border-fallback is used for the focus element's border value.
 */
@mixin valo-button-focus-style ($background-color: $v-background-color, $border-fallback: inherit) {
  $focus-color: $v-focus-color;

  @if color-luminance($focus-color) + 50 < color-luminance($background-color) {
    border-color: $focus-color;
  } @else if $border-fallback != none {
    border: $border-fallback or valo-border($color: $background-color);
  }

  @include valo-focus-style;
}


/**
 * Outputs the active state (pressed/down) styles for a button. The styles are by default targeted
 * for a pseudo element which is shown on top of the normal state button.
 *
 * @group button
 *
 * @param {color} $background-color ($v-background-color) - The background color of the normal state button
 */
@mixin valo-button-active-style ($background-color: $v-background-color) {
  $bg: scale-color($background-color, $lightness: -50%, $saturation: saturation($background-color));
  background-color: rgba($bg, .2);
}


/**
 * Outputs styles to allow vertical centering of the icon and the caption, independent of the
 * height of the button.
 *
 * @group button
 */
@mixin valo-button-vertical-centering {
  @include valo-vertical-align-guide($to-align: div, $pseudo-element: before);

  // WebKit handles line-heights and vertical-alignments somewhat differently, so we need to adjust
  .v-sa &:before {
    height: 110%;
  }

  // Firefox needs a bit of adjusting as well
  .v-ff &:before {
    height: 107%;
  }

  // ...and so does IE. Who knew?
  .v-ie &:before {
    margin-top: 4px;
  }
}


/**
 * Output styles for a borderless button. Expects that the targeted element
 * already has both valo-button-static-style and valo-button-style included.
 *
 * @param {color} $font-color (inherit) - The font color of the borderless button
 *
 * @group button
 */
@mixin valo-button-borderless-style ($font-color: inherit) {
  border: none;
  @include box-shadow(none);
  background: transparent;
  color: $font-color;

  &:hover {
    &:after {
      background: transparent;
    }

    @if type-of($font-color) == color {
      color: lighten($font-color, 10%);
    }
  }

  &:active:not(.v-disabled) {
    @include opacity(.7);

    &:after {
      background: transparent;
    }
  }
}


/**
 * Output styles for a "quiet" button (a button whose outline is only shown
 * once the user hovers over the button caption). Expects that the targeted
 * element already has both valo-button-static-style and valo-button-style
 * included.
 *
 * @group button
 */
@mixin valo-button-quiet-style {
  visibility: hidden;

  &:focus,
  &:hover {
    visibility: visible;
  }

  [class*="wrap"] {
    visibility: visible;
  }

  [class*="caption"] {
    // For IE8
    display: inline-block;
  }
}


/**
 * Output styles to align a button's icon on the right side of its caption.
 *
 * @group button
 */
@mixin valo-button-icon-align-right-style {
  [class*="wrap"] {
    display: inline-block;
  }

  .v-icon {
    float: right;
    $padding-width: ceil($v-unit-size/2.4);
    margin-left: $padding-width + ceil($padding-width/-5);

    + span:not(:empty) {
      margin-left: 0;
    }
  }
}


/**
 * Output styles to align a button's icon on top of its caption.
 *
 * @group button
 */
@mixin valo-button-icon-align-top-style {
  height: auto;
  padding-top: ceil($v-unit-size/9);
  padding-bottom: ceil($v-unit-size/9);

  [class*="wrap"] {
    display: inline-block;
  }

  .v-icon {
    display: block;
    margin-left: auto;
    margin-right: auto;

    + span:not(:empty) {
      margin-top: ceil($v-unit-size/6);
      margin-left: 0;
    }
  }
}
