// --------------------------------------
//    Define the default color set
// ------------------------------------

$default-color-set: $color-default !default;

// ------------------------------------------------------------------------
//    There has been made another colorset, lets check it an apply it.
// ----------------------------------------------------------------------

@function define-custom-colorset($current-color-set) {
	$passed: true;
	// Let's first check if it has values

	@if length($custom-colorset) < 1 {
		$passed: false;
		@warn "[function define-custom-colorset] The custom colorset you've made, doesnt have any values an therefor the default colorset will be used.";
	}

	// If the colorset is not a map, it won't work. So lets check that too.

	@else if type-of($custom-colorset) != 'map' {
		$passed: false;
		@warn "[function define-custom-colorset] The custom colorset you've made, is not a map.";
	}

	// If the colorset doesn't have Black, it won't work.

	@else if map-get($custom-colorset, 'Black') == null {
		$passed: false;
		@warn "[function define-custom-colorset] Your colorset doesn't have Black defined. Therefore not appplied.";
	}

	// If the colorset doesn't have White, it won't work.

	@else if map-get($custom-colorset, 'White') == null {
		$passed: false;
		@warn "[function define-custom-colorset] Your colorset doesn't have White defined. Therefore not appplied.";
	}

	// It appears that everything is alright. Lets change the set to your new set.

	@if $passed {
		@return $custom-colorset;
	} @else {
		@return $current-color-set;
	}
}

// ---------------------------------------------------------------------------------------------
//    If you defined custom colors, we will extend the existing colorset with these colors.
// -------------------------------------------------------------------------------------------

@function define-custom-colors($current-color-set) {
	$passed: true;

	// Let's first check if it has values

	@if length($custom-colors) < 1 {
		$passed: false;
		@warn "[function define-custom-colors] The custom colorset you've made, doesnt have any values an therefor the default colorset will be used.";
	} @else {
		@if length(nth($custom-colors, 1)) != 2 {
			$passed: false;
			@warn "[function define-custom-colors] The custom colors you've made, doesn't have right structure.";
		}
	}
	@if $passed {
		@return map-merge($current-color-set, $custom-colors);
	} @else {
		@return $current-color-set;
	}
}

// ------------------------------
//    Define a set color set
// ----------------------------

@function define-color-set() {
	$set: ();
	// Define the Color set if its a string
	@if type-of($default-color-set) == 'string' {
		@if $default-color-set == 'default' {
			$set: $color-default;
		} @else if $default-color-set == 'social' {
			$set: $color-default;
		} @else {
			@warn "[function define-color-set] the requested colorset doesnt exist so default color set has ben set back.";
			$set: $color-default;
		}
	} @else {
		$set: $color-default;
		@warn "[function define-color-set] the argument given in the function is not a string and can't be set as new colorset";
	}
	@return $set;
}

// -----------------------------------------------------
//    Check if there has been set another color set
// ---------------------------------------------------

@if type-of($default-color-set) == 'string' {
	$default-color-set: define-color-set();
}

// ----------------------------------------------------------------------
//    Let's check if there is a new colorset defined in the project.
// --------------------------------------------------------------------

@if variable-exists(custom-colorset) {
	$default-color-set: define-custom-colorset($default-color-set);
}

// --------------------------------------------------------------------------------------
//    Also, you might have extra colors to add to the default set, overrule or extend
// ------------------------------------------------------------------------------------

@if variable-exists(custom-colors) {
	$default-color-set: define-custom-colors($default-color-set);
}

// -----------------------------------------
//   Return a normal color
// ---------------------------------------

@function to-color($value) {
	$new-value: null;
	// Check if the color exists in another way in the colorset.
	@each $color-name, $color-value in $default-color-set {
		// Check if the value given exists in any predefined colors.
		$str-value: '#{$value}';
		$str-color: to-string-color($color-name);

		// First make sure the color is not in the colorset. If so, just return the right color back. Also makes it possible to
		// Fix uppercase/lowercase mistakes. Will still give a warning that the color doesn't exist, but will return the right color.
		@if to-lower-case($str-color) == to-lower-case($str-value) {
			$new-value: $color-value;
		}

		// Check if the requested colorname exists in a color name in the existing colorset
		@else if str-contains(to-lower-case($str-value), to-lower-case($str-color))
		{
			$new-value: rgba(
				red($color-value),
				green($color-value),
				blue($color-value),
				1
			);
		}

		// Check if the requested names in the colorset exists in a requested color name
		@else if str-contains(to-lower-case($str-color), to-lower-case($str-value))
		{
			$new-value: $color-value;
		}
	}
	@if $new-value == null {
		$new-value: '#{$value}';
	}

	// Return a closer color.
	@return to-string($new-value);
}

// --------------------------------------------------------------------------
//    The main color function, get the color from  the current colorset
// ------------------------------------------------------------------------

// @function color($value: null, $opacity: 1, $colorset: $default-color-set) {
@function color($args...) {
	$value: '';
	$opacity: 1;
	$colorset: $default-color-set; 
		
	@if length($args) > 0 and type-of(nth($args,1)) == 'string' or type-of(nth($args,1)) == 'color'{
		$value: '#{nth($args,1)}';
	} @else {
		@warn "[function color] #{nth($args,1)} is not a color"; 
	}
	
	@if length($args) > 1 and nth($args,2) and type-of(nth($args,2)) == 'number'{
		@if nth($args,2) > 1 or nth($args,2) < 0{
			@warn "[function color] #{nth($args,1)} is not a valid number for opacity";
		}
		@else {
			$opacity: nth($args,2);
		}
	}
	// @else if nth($args,2) and type-of(nth($args,2)) == 'list'{
	// 	$colorset: nth($args,2);
	// }
	
	
	// Check if value atleast is set.
	@if $value == null {
		@warn "No color given";
		@return null;
	}
	// By Default add an underscores to the String so it will stay a string for sure.

	// // check Value type and convert the color always to a string.
	// $value-type: type-of($value);

	// When the type is 'color' we need to either convert color to a string
	// or directly pass it back when its an actual color
	@if is-string-color($value) {
		$value: to-string($value);
	} @else {
		@return to-string-color($value, $opacity);
	}

	// Check if the color exist in the current colorset

	@if color-exist('#{$value}', $colorset) {
		@return rgba(get-color('#{$value}', $colorset), $opacity);
	}

	// The last resort for return

	@else {
		@warn "[function color] #{$value} (#{type-of($value)}) does not exist in the current colorset.";
		@return to-color($value);
	}
}

// -----------------------------------------------------------------------
//    Check if the type of a color and return if its not a rgb or hex
// ---------------------------------------------------------------------

@function is-string-color($value) {
	$value: to-string($value);

	@if str-slice('#{$value}', 1, 1) == '#' {
		@return false;
	}

	// Check if the color is a rgb color.

	@else if str-slice('#{$value}', 1, 3) == 'rgb' {
		@return false;
	}

	// Check if the color type is color.
	@else if type-of($value) == 'color' {
		@return unquote('_#{$value}');
	}

	// Else, just return the string and make the best of it.
	@else {
		@return true;
	}
}

// ------------------------------------------------
//    Convert the string back to an actual color
//    and always to a rgba color with opacity
// ---------------------------------------------

@function to-string-color($value, $opacity: 1) {
	
	// Check if the color is a hex color.
	@if str-slice('#{$value}', 1, 1) == '#' {
		@return $value;
	}
	
	// Check if the color is a rgb color.
	@else if str-slice('#{$value}', 1, 3) == 'rgb' {
		@return rgba(red($value), green($value), blue($value), $opacity);
	} @else {
		@return '#{$value}';
	}
}

// ------------------------------------------------------------
//    Check if the color is a rgb, hex or a specific
//    color from the existing colorset and return a color
// ---------------------------------------------------------

@function to-defined-color($color, $return: 'string') {
	@if is-string-color(to-string($color)) {
		@if color-exist(to-string($color)) {
			@return color(to-string($color));
		} @else {
			@return $color;
		}
	} @else if $return == 'string' {
		@return to-string-color($color);
	} @else if $return == 'color' {
		@return $color;
	}
}

// ----------------------------------------------------
//    Check if the color exists in the current set
// --------------------------------------------------

@function color-exist($value, $colorset: $default-color-set) {
	
	// Return true if the color exists in the current colorset; Or false when not.
	@if map-get($colorset, $value) or
		map-get($colorset, str-slice($value, 2, str-length($value)))
	{
		@return true;
	} @else {
		@return false;
	}
}

// -----------------------------------------
//    Get the color from the colorset;
// ---------------------------------------

@function get-color($value, $colorset: $default-color-set) {
	// Return the color if the color exists in the current colorset; Or nothing + a warning when not.

	$_: false;
	@if str-index($value, '_') == 1 {
		$_: true;
	}
	@if color-exist($value, $colorset) {
		@if $_ {
			@return map-get($colorset, str-slice($value, 2, str-length($value)));
		} @else {
			@return map-get($colorset, $value);
		}
	} @else {
		@warn "[function get-color]#{$value} does not exist in the current colorset";
		@return '';
	}
}

// ------------------------------------------
//    Define the default black and white
// ----------------------------------------

@function define-bw($opacity) {
	// Standard set the default black and white;
	$black: black;
	$white: white;

	// Black should exist in defined colorset
	@if color-exist('Black') {
		$black: color(Black, $opacity);
	} @else {
		@warn "[function define-bw] 'Black' does not exist in defined colorset";
	}

	// White should exist in defined colorset
	@if color-exist('White') {
		$white: color(White, $opacity);
	} @else {
		@warn "[function define-bw] 'White' does not exist in defined colorset";
	}

	// Return Black and White
	@return ($black, $white);
}

// ------------------------------------------
//    Get brightness of a specific color
// ----------------------------------------

@function color-brightness($color, $percentage: true) {
	// Check if the color is already al color or if we have to convert it to a color.
	@if type-of($color) == 'color' {
		// Get the brigthness values
		$brightness: color-brightness-calc($color);
	} @else {
		// Get the brigthness values
		$brightness: color-brightness-calc(color($color));
	}
	// Return either a percentage or hard value*/
	@if $percentage {
		@return percentage(color-brightness-calc($color) / 100);
	} @else {
		@return (color-brightness-calc($color));
	}
}

// --------------------------------------------------
//    Calculate the brightness value of a color
// ------------------------------------------------

@function color-brightness-calc($color) {
	@if type-of($color) != 'color' {
		$color: color($color);
	}

	// Calculate all colors from the given color in percentages.
	$red: ((red($color) / 255) * 100);
	$green: ((green($color) / 255) * 100);
	$blue: ((blue($color) / 255) * 100);

	// Calculate the average over all colors
	$sum: (($red + $green + $blue) / 3);

	@return $sum;
}

// ------------------------------------------------------
//    Get the opposite color (either black or white)
// ----------------------------------------------------

@function contra($value, $opacity: 1, $colors: null, $contrast: 57.5) {
	$contra-color: white;
	$color: black;
	$bw: ();
	// Define dark and light colors to return.

	//  Alternative dark and light can be given in a map form.
	// `contra([COLOR],1,([DARKCOLOR],[LIGHTCOLOR]);`

	@if $colors != null {
		@if length($colors) == 2 {
			$bw: (nth($colors, 1), nth($colors, 2));
		} @else {
			@warn "[function contra] Set with alternative has a invalid amount of values (#{length($colors)})";
		}
	} @else {
		$bw: define-bw($opacity);
	}

	// When the type is 'color' we need to either convert color to a string
	// or directly pass it back when its an actual color.
	$color: to-defined-color($value);

	// Get the brightness value

	$brightness: color-brightness($color, false);

	@if $brightness > $contrast {
		$contra-color: nth($bw, 1);
	} @else {
		$contra-color: nth($bw, 2);
	}
	
	// Make really sure you pass back a color, or otherwise unquote the color. 
	@if type-of($contra-color) != 'color'{
		@return unquote($contra-color);
	} @else {
		@return $contra-color;
	}
}

// -------------------------------------------------------------
//    Populate variable $colors with the current colorset;
// -----------------------------------------------------------

$colors: $default-color-set;

// -------------------------------------------------------------------------
//    Define Black, White and Gray function with the existing colorset
// -----------------------------------------------------------------------

@function black($opacity: 1) {
	@if color-exist('Black') {
		@return color(Black, $opacity);
	} @else {
		@return rgba(0, 0, 0, $opacity);
	}
}

@function white($opacity: 1) {
	@if color-exist('White') {
		@return color(White, $opacity);
	} @else {
		@return rgba(255, 255, 255, $opacity);
	}
}
@function gray($lightness: 0.5, $opacity: 1) {
	$amount: 255 * $lightness;
	@return rgba($amount, $amount, $amount, $opacity);
}

// --------------------------------------------------------
//    Extend standard SASS function with more options.
// ------------------------------------------------------

@function darken($color, $amount) {
	//  When the type is 'color' we need to either convert color to a string
	// or directly pass it back when its an actual color.
	@if is-percentage($amount) == false {
		$amount: percentage(1 * $amount);
	}

	$darkness: 0;
	$color: to-defined-color($color, 'color');

	// Apply the darkness to the color like the original function also does.

	@if type-of($color) == 'color' {
		$darkness: lightness($color) - $amount;
		@if $darkness < 0 {
			$darkness: 0%;
		} @else if $darkness > 100 {
			$darkness: 100%;
		}
		// Return the new darkened color.
		@return hsl(hue($color), saturation($color), $darkness);
	} @else {
		@warn "#{$color} is not a color";
		@return $color;
	}
}

@function lighten($color, $amount) {
	// When the type is 'color' we need to either convert color to a string
	// or directly pass it back when its an actual color.

	@if is-percentage($amount) == false {
		$amount: percentage(1 * $amount);
	}

	$color: to-defined-color($color);
	// Apply the lightness to the color like the original function also does.

	$lightness: lightness($color) + $amount;
	@if $lightness < 0 {
		$lightness: 0%;
	} @else if $lightness > 100 {
		$lightness: 100%;
	}
	// Return the new darkened color.

	@return hsl(hue($color), saturation($color), $lightness);
}

// ----------------------------------------------------------------------
//    SASS has a problem with the use of rgba with custom propertis,
//    using this function fixes this.
// -------------------------------------------------------------------

@function native-rgba($string, $opacity) {
	@return #{'rgba(#{$string}, #{$opacity})'};
}

// ----------------------------------------------------------------------
//    Add a color to a colorset, can be usefull when your full colorset
//    is coming from an external source.
// -------------------------------------------------------------------

@function add-color($color-set, $color: null, $value: null) {
	// args: Existing colorset, new color; ex; add-color($my-color-set, ('MyColor', #123456));

	$current-value: false;
	$i: 0;
	$color-name: null;
	$color-value: null;
	$new-color: ();

	@if type-of($color) == 'list' {
		$color-name: nth($color, 1);
		$color-value: nth($color, 2);
		$new-color: map-set($new-color, $color-name, $color-value);
	} @else {
		$color-name: $color;
		$color-value: $value;
		$new-color: map-set($new-color, $color-name, $color-value);
	}

	$index: key-index($color-set, $color-name);
	$color-set: map-set($color-set, $color-name, $color-value);

	@return $color-set;
}
