// If `$___defined-colors` doesn't exist then this creates it.
// This variable is to store the different namespaces and colors as they're defined.
@if not global-variable-exists(___defined-colors){
 $___defined-colors: () !global;
}

// This should never change. If you want to change them just define your
// own variable `$color-settings` to overwrite one or more of these settings.
@if not global-variable-exists(___color-settings){
 $___color-settings: (
  base: 0, // defines the base color to look for in the maps
  increment: 5%, // this is a fall back increment if the color functions that are defined are lists and not maps
  colors: (), // placeholder for defined colors, these will always be defined in $color-settings colors
  map: "integers", // determins if you're using integers to get your light and dark values or words.(@feature - this hasn't been added yet)
  smart-color: .25, // determins how far you go back if the color is #fff or #000 (example if you called color(#ccc, 25) that will be black but if smart color is set then it will be #060606)
  functions: ( // holds the light and dark functions to use for the different variations. (only light, and dark can be the keys of this map)
   light: ( // holds the light functions that will run if the variation is less than 0
    lighten: 5%
   ),
   dark: ( // holds the dark functions that will run if the variation is less than 0
    darken: 5%
   )
  )
 ) !global;
}


// @author Tyler Benton
// @page helpers/mixins
//
// @description
// This is used to set the color settings for the default namespace
// The main reason this is a seperate mixin is for the simple fact that it
// increases the performance. Only having to merge the namespace settings
// with the necessary defaults once is a huge performance increase.
//
// @arg {string} $namespace (default) - the namespace for your colors
// @arg {map} $settings (false) - the settings for your namespace. If false it will use the default settings
// @arg {boolean} $merge-color-settings (true) - Determins if you want to merge your default settings that where defined in `$color-settings`
//
// @markup {scss} - How to define default color settings
// $color-settings: (
//  smart-color: .45,
//  colors: (
//   a: (
//    0: #ccc,
//    name: gray
//   )
//  )
// );
// \@import "_colors.scss";
// /\/ define-color-set doesn't need to be called if you define $color-settings (defaults) before you import colors.scss
//
// @markup {scss} - How to define default color settings after you import colors.scss
// \@import "_colors.scss";
// $color-settings: (
//  smart-color: .45,
//  colors: (
//   a: (
//    0: #ccc,
//    name: gray
//   )
//  )
// );
// \@include define-color-set;
//
// @markup {scss} - How to define a different namespace of colors
// /@include define-color-set(messaging, (
//   smart-color: .33,
//   colors: (
//    info: (
//     0: #cbe8f5,
//     name: light blue
//    )
//   )
//  )
// );
@mixin define-color-set($namespace: "default", $settings: false, $merge-color-settings: true){
 // This merges the default color settings(`$color-settings`) with the default settings.
 $default-settings: if($merge-color-settings and global-variable-exists(color-settings) and type-of($color-settings) == map,
                     map-merge($___color-settings, $color-settings),
                     $___color-settings
                    );

 // Merges $settings with default color settings
 $settings: if(type-of($settings) == map, map-merge($default-settings, $settings), $default-settings);

 // this will add a theme for the color
 $colors: map-get($settings, colors);
 @each $theme, $base in $colors{
  @if type-of($base) == map and map-get($base, theme) == null{
   $base: map-merge($base, (theme: $theme))
  }
  $colors: map-merge($colors, ($theme: $base));
 }

 $settings: map-merge($settings, (colors: $colors));

 $defined-namespace: map-get($___defined-colors, $namespace);

 $___defined-colors: map-merge($___defined-colors,
                      if($defined-namespace == null,
                       ($namespace: (settings: $settings, defined-colors: ())),
                       ($namespace: (map-merge($defined-namespace, (settings: $settings))))
                      )
                     ) !global;
}

@include define-color-set;

// @name color
// @author Tyler Benton
// @page helpers/functions
//
// @description
// This function helps control the colors that are used on the site.
// It will get dynamic color values based off a **base** color See the examples for more information.
// It's highly configurable, and focuses on performance.
//
// @arg {color | map | key-of-a-map(string)} $this - The type determins how to find the correct color.
// @arg {integer} $variation - This accepts any integer value, and does support decimal points.
// @arg {boolean} $force - This forces the function to ignore already defined color values, and has it get a new varation.
// @arg {boolean} $save - This determins if you want to save the color variation. The reason there're two defaults is that if $force is true then by default the status of $save changes to false
// @arg {boolean | map} $settings - These are the user defined settings stored in $this-settings, if there're no color settings then it's false
// @arg {boolean} $list - This will list out the colors theme, color, and name that you specify in the settings.
//
// @returns {color} - The color variation that you specified from the namespace that you specifed
//
// @markup {scss} (example="false") - Simplest form:
// color(#fff, 1.75); /\/ #e9e9e9
//
// @markup {scss} (example="false") - Defined colors:
// $color-settings: (
//  colors: (
//   a: #ccc
//  )
// );
// .foo{
//  color(a, 3); /\/ #a6a6a6
// }
//
// @markup {scss} (example="false") - Using a different map of colors other than default
// /\/ option 1
// $messaging-colors: (
//  info: (
//   -1: #cbe8f5,
//   0: #457da6
//  ),
//  ...
// );
// .foo{
//  color(map-get($messaging-colors, info), 2);
// }
// /\/ option 2(much better way)
// $messaging-settings: (
//  name-space: "messaging",
//  colors: (
//   info: (
//    -1: #cbe8f5,
//    0: #457da6
//   ),
//   ...
//  )
// );
// \@function messaging-color($type, $variation: 0){
//  \@return color($type, $variation, $settings: $messaging-settings);
// }
// .foo{
//  color: messaging-color(info, -1); /\/ #cbe8f5
// }
//
// @markup {scss} (example="false") - How to force this function to get a variation without checking locally
// $color-settings: (
//  colors: (
//   a: (
//    5: #e2e2e2,
//    0: #ccc,
//    name: gray
//   ),
//   ...
//  )
// );
// color(#fff, 5, true) /\/ forcing it will return #7f7f7f instead of #e2e2e2 which was defined
@function color($this: #000, $variation: 0, $force: false, $save: true, $namespace: "default"){
 // Sets save to false because, if you're forcing a color variation you probably don't want to save it.
 @if $force{
  $save: false;
 }

 $this-namespace: map-get($___defined-colors, $namespace); // The current set to work with
 @if $this-namespace == null{
  @error "to use the #{$namespace} you must first set your settings using `@include define-color-set(#{$namespace}, (your settings in a map))`";
  @return false;
 }

 $settings: map-get($this-namespace, settings);

 // helper variables
 $this-type: type-of($this); // stores the type of this so it doesn't have to be called multiple times.
 $this-base-color: false; // placeholder for the base color
 $result: false; // placeholder for result
 $base: map-get($settings, base); // how to determin the base color if the color is in a map
 $name-of-color: null; // placeholder for the actual name of the color
 $theme-of-color: null; // placeholder for the key name

 // ```scss
 // $color-settings: (
 //  colors: (
 //   a: #ccc,
 //   b: (
 //    0: #aaa
 //   )
 //  )
 // );
 // color(a, 3); // #b2b2b2
 // ```
 @if $this-type == string{
  // stores the name of this theme
  $theme-of-color: $this;
  // try to find $this in the settings colors map
  $this: map-get(map-get($settings, colors), $this);

  // reset $this-type to be the new type of this.
  $this-type: type-of($this);

  @if $this == null{
   @error "Couldn't find '#{$theme-of-color}' in map-get($settings, colors): #{map-get($settings, colors)}";
   @return false;
  }
 }

 // ```scss
 // color(#fff, 2);
 // ```
 @if $this-type == color{
  $this-base-color: $this;
  @if $variation == $base{
   // ```scss
   // color(#ccc, 0); // #ccc
   // ```
   $result: $this-base-color;
  }
 }

 // ```scss
 // $messaging-settings: (
 //  name-space: "messaging",
 //  colors: (
 //   info: (
 //    -1: #cbe8f5,
 //    0: #457da6
 //   ),
 //   ...
 //  )
 // );
 // \@function messaging-color($type, $variation: 0){
 //  \@return color($type, $variation, $settings: $messaging-settings);
 // }
 // messaging-color(info, -1) /\/ #cbe8f5
 // ```
 @if not $result and $this-type == map{
  // defineds base color
  $this-base-color: map-get($this, $base);
  $name-of-color: map-get($this, name);

  // if there isn't a base color defined then throw this error.
  @if not $this-base-color{
   @error "If you are going to use a map of colors, you have to specify a base color (aka. `0`)";
  }

  // try to find the local variation
  @if not $force{
   $local-attempt: map-get($this, $variation);
   @if $local-attempt{
    $result: $local-attempt;
   }
  }
 }

 // Ensures that the base color is infact a color
 @if type-of($this-base-color) != color{
  @error "#{$this-base-color} isn't a base color";
  @return false;
 }


 // try to find the color variation in storage (`$___defined-colors`)
 @if not $result and not $force{
  $stored-attempt: map-get(map-get($this-namespace, defined-colors), "#{$this-base-color}");
  $stored-attempt: if($stored-attempt != null, map-get($stored-attempt, $variation), null);
  @if $stored-attempt {
   // since the color is already defined it doens't need to be defined again so just return the color
   $result: $stored-attempt;
  }
 }


 // Finds the color variation programatically if the color variation
 // isn't found locally, and isn't found in storage
 @if not $result{
  $functions: map-get($settings, functions);
  // This determins wether or not to use the light or dark function set
  $functions: if($variation > 0, map-get($functions, dark), map-get($functions, light));

  // if it's a list then make it into a map using the settings default values
  @if type-of($functions) == list{
   $temp: ();
   @each $function in $functions{
    $temp: map-merge($temp, (#{$function}: map-get($settings, increment)));
   }
   $functions: $temp;
  }

  // store the absolute value of the variation as a variable
  $variation-floor: floor(abs($variation));
  $variation-remander: abs($variation) - $variation-floor;

  // reset the $result to be the base color because that's what's going to get modified.
  $result: $this-base-color;

  // Reverse for loop so you can wrap the color functions correctly in reverse order.
  // Where the last function in the map is the first function to get called.
  // Example: (lighten: 5%, tint: 5%) ==> lighten(tint([base color], 5%), 5%);
  @for $i from length($functions) through 1{

   // gets the color function name from $function-set
   $function: nth(map-keys($functions), $i);

   // the value of the function is the incrementor
   $incrementor: map-get($functions, $function);

   // gets the current increment
   $increment: $variation-floor * $incrementor;

   // this handles the decimal values for variations
   @if $variation-remander > 0{
    $increment: $increment + ($incrementor * $variation-remander);
   }

   // updates the result to be the new value
   // "DEPRECATION WARNING: Passing a string to call() is deprecated and will be
   // illegal in Sass 4.0" with lib-sass 3.5.0"
   // Sass 3.5 compatibility: Use call(get-function('foo'), $args) instead of call('foo', $args)
   $result: call(get-function($function), $result, $increment);
  }

  // if the smart color is greater than 0
  $smart-color: abs(map-get($settings, smart-color)); // the abs is to ensure it's using positive numbers since it has to be manipulated to work for both white and black values.
  @if $smart-color > 0 and index((white, #fff, #ffffff, black, #000, #000000), $result){ // i went with a index of the color values just incase sass changes what it returns in a later release.
   $result: color(
             $this,
             $variation + ($smart-color * if($result == white, 1, -1)), // new variation based off of the smart color
             $force, // force is same as what was passed because the previous variation could already bed defined.
             false, // it's false because it's shouldn't be saved.
             $namespace
            );
  }

 }

 // return the result
 @if type-of($result) == color{
  @if $save == true{
   $defined-colors: map-get($this-namespace, defined-colors);
   // get the current color set to work with
   $this-base-color-string: "#{$this-base-color}";

   $base-map: (0: $this-base-color);

   // the map of this colors variations
   $this-color: map-get($defined-colors, $this-base-color-string);

   // if this-color doesn't already exist then create it and set the base color
   @if $this-color == null{
    $this-namespace: map-merge($this-namespace, (defined-colors: map-merge($defined-colors, ($this-base-color-string: $base-map))));
    $defined-colors: map-get($this-namespace, defined-colors);
    $this-color: map-get($defined-colors, $this-base-color-string);
   }

   // attempt to get the variation, if there's a defined variation already
   // then return this attempt and skip everything below
   $storage-attempt: map-get($this-color, $variation);
   @if $storage-attempt{
    @return $storage-attempt;
   }

   // add the new color variation to this color
   $this-color: map-merge($this-color, ($variation: $result));

   // update defined colors to include the new color
   $defined-colors: map-merge($defined-colors, ($this-base-color-string: $this-color));

   // update this-namespace with this color
   $this-namespace: map-merge($this-namespace, (defined-colors: $defined-colors));

   // update $___defined-colors with the new namespace
   $___defined-colors: map-merge($___defined-colors, ($namespace: $this-namespace)) !global;
  }
  @return $result;
 }@else{
  @return $result unquote("/* @errror { #{type-of($result)} isn't a color } */");
 }
};


// @author Tyler Benton
// @page helpers/functions
//
// @description
// This will list out the colors of a color namespace and what they're actually called if you need that
// This is just a helper function to `color`, and is purely for debuging and convenience
//
// @arg {string} $namespace ("default") - this is the namespace that you want to list, or "all" to see all the namespaces
// @arg {string} $to-console ("colors") - "colors" | "settings" | "defined-colors" | "all"
//
// @markup {scss} (example="false") - How to list the current colors and their names in the console:
// @include define-color-set("messaging", (
//  namespace: "messaging"
//  colors: (
//   info: (
//    0: #ccc,
//    name: blue /\/ this has to be specifed for every color if you want to see it in the console
//   ),
//   ...
//  )
// ));
//
// .foo{
//  color: color(info); /\/ called to add it to the stored map
// }
//
// $console: console-colors("messaging");
//
// @markup {scss} (example="false") - How to log every namespace and their colors, settings, and defined-colors
// $console: console-colors(all, all);
@function console-colors($namespace: "default", $to-console: "colors"){
 @if $namespace == all{
  @each $space in map-keys($___defined-colors){
   $d: console-colors($space, $to-console);
  }
  @return false;
 }

 @if $to-console == "all"{
  @each $name in (colors, settings, defined-colors){
   $d: console-colors($namespace, $name);
  }
  @return false;
 }

 $this-namespace: map-get($___defined-colors, $namespace);
 $settings: map-get($this-namespace, settings);
 $seperator: "---------------------------------------------------------------------";
 $title: "colors #{str-slice($seperator, 0, 3)} #{$namespace} #{str-slice($seperator, 0, 3)} #{$to-console}";
 $title: $title + str-slice($seperator, str-length($title) + 1);
 @debug unquote(" ");
 @debug $title;

 @if $to-console == "colors"{
  @each $theme, $value in map-get($settings, colors){
   @if type-of($value) == map{
    $color-name: map-get($value, name);
    $color-name: unquote(if($color-name != null, "// #{$color-name}", ""));
    @debug "#{map-get($value, theme)} = #{map-get($value, 0)} #{$color-name}";
   }
  }
 }@else if $to-console == "settings"{
  // @debug $settings;
  @each $setting, $setting-value in $settings{
   @if type-of($setting-value) == map{
    @debug "#{$setting}: (";
     @each $key, $value in $setting-value{
      @if type-of($value) == map{
       @debug " #{$key}: (";
        @each $variation, $color in $value{
         @debug "  #{$variation}: #{$color},";
        }
       @debug " ),"
      }@else{
       @debug "#{$key}: #{$value}";
      }

     }
    @debug "),";
   }@else{
    @debug "#{$setting}: #{$setting-value},";
   }
  }
 }@else if $to-console == "defined-colors"{
  @each $color, $variations in map-get($this-namespace, defined-colors){
   @debug "#{$color}: (";
   @each $variation, $color-value in $variations{
    @debug " #{$variation}: #{$color-value},";
   }
   @debug ");";
  }
 }

 @debug $seperator;
 @debug unquote(" ");

 @return false;
};

// @author Tyler Benton
// @page helpers/mixins
//
// @description
// This will list out the colors of a color namespace and what they're actually called if you need that
// This is just a helper function to `color`, and is purely for debuging and convenience
//
// @arg {string} $namespace ("default") - this is the namespace that you want to list, or "all" to see all the namespaces
// @arg {string} $to-console ("colors") - "colors" | "settings" | "defined-colors" | "all"
//
// @markup {scss} (example="false") - How to list the current colors and their names in the console:
// @include define-color-set("messaging", (
//  namespace: "messaging"
//  colors: (
//   info: (
//    0: #ccc,
//    name: blue /\/ this has to be specifed for every color if you want to see it in the console
//   ),
//   ...
//  )
// ));
//
// .foo{
//  color: color(info); /\/ called to add it to the stored map
// }
//
// @include console-colors("messaging");
//
// @markup {scss} (example="false") - How to log every namespace and their colors, settings, and defined-colors
// @include console-colors(all, all);
@mixin console-colors($namespace: "default", $to-console: "colors"){
 $console-log: console-colors($namespace, $to-console);
}