////
/// In order to improve modular namespacing, LibSass 4 only accepts first-class
/// functions as argument so functions are called in their own context.
/// In most case, `get-function()` must only be used by the user in its own
/// context. It is used in this library to keep a maximum compatibility.
/// End developer must be encouraged to use first-class functions.
///
/// @link http://oddbird.net/2017/03/30/safe-get
/// @link http://sass.logdown.com/posts/809572-sass-35-release-candidate
////

///
/// Return if a given value is a function or a function name string.
///
/// @access private
///
/// @param {*} $value - Value to test
/// @return {Boolean}
///
@function -mui-is-function($value) {
  @return type-of($value) == 'function' or type-of($value) == 'string';
}

///
/// Return if a given value is callable.
///
/// @access private
///
/// @param {*} $value - Value to test
/// @return {Boolean}
///
@function -mui-is-callable($value) {
  @return type-of($value) == 'function' or (type-of($value) == 'string' and function-exists($value));
}

///
/// Check if a given value is callable and throw the appropriate error otherwise
///
/// @access private
///
/// @param {*} $value - Value to check
/// @return {Boolean}
///
@function -mui-assert-function($value) {
  @if -mui-is-callable($value) {
    @return true;
  } @else if (type-of($value) == 'string' and function-exists('get-function') == true) {
    @error 'Assertion Error: function name string "#{$value}" cannot be found. You may need to use `get-function()` and first-class functions instead. See http://oddbird.net/2017/03/30/safe-get';
  } @else if (type-of($value) == 'string' and function-exists('get-function') == false) {
    @error 'Assertion Error: function name string "#{$value}" cannot be found.';
  } @else {
    @error 'Assertion Error: #{$value} (#{type-of($value)}) is not a function.';
  }
}

///
/// Return a reference to the given function or function name string compatible
/// with the current Sass version.
///
/// * For Sass < 3.5, return the passed argument
/// * For Sass >= 3.5, return a first-class function if a function name string
///   was passed
///
/// @access private
///
/// @param {Function|String} -  $func - Function or name of the function
/// @return {Function|String}   Function or name of the function following
///                             the support of first-class functions.
///
@function -mui-safe-get-function($func) {
  @if -mui-assert-function($func) {
    @if function-exists('get-function') and type-of($func) == 'string' {
      @return get-function($func);
    } @else {
      @return $func;
    }
  }
}

///
/// Polyfill for the `call` function supporting both functions and strings.
///
/// @access private
///
/// @param {Function|String} $func - Function or name of the function to call
/// @param {Arglist} $args... - Arguments to call the function with
///
/// @return {*}
///
@function -mui-safe-call($func, $args...) {
  @if -mui-assert-function($func) {
    @return call(-mui-safe-get-function($func), $args...);
  }
}
