// |------------------------------------------------------
// |------------------------------------------------------
// | Generate mixins
// |------------------------------------------------------
// |------------------------------------------------------


//
// Generate a custom class for all the states
//
// @param 	list 	$pattern 		The name pattern of the class
// @param 	list 	$statesNames 		The states names to generate
//
@mixin gridle_generate_custom_class(
	$pattern,
	$statesNames : null,
	$replacements...
) {
	// manage states to generate :
	$states : ();
	@if $statesNames == null or $statesNames == all {
		// loop on each states to generate names list :
		@each $stateName, $state in $_gridle_states {
			$states : append($states, $stateName);
		}
	} @else {
		$states : $statesNames;
	}

	// Get all pattern
	$unmatched_patterns :  _gridle_unmatched_patterns($pattern);
	$matched_patterns :  _gridle_matched_patterns($pattern);

    // Adjust the replacement list length to be the same as unmatched_patterns
    @while length( $unmatched_patterns ) != length( $replacements ) {
        @if length( $unmatched_patterns ) < length( $replacements ) {
            $replacements : list-pop($replacements);
        }@else{
            $replacements : append($replacements, (null));
        }
    }

    // for each valid pattern, get replacement list
    @each $index, $pattern in $matched_patterns {
        @if $pattern == "%state" {
            $matched_patterns : map-remove($matched_patterns, $index);
        }@else{
            $replacements : append($replacements, _gridle_get_pattern_values(str-slice($pattern, 2)));
        }
    }

    $found_patterns : map-merge($unmatched_patterns, $matched_patterns);

	// loop on each states :
	@each $stateName in $states
	{
		// manage statename :
		@if type-of($stateName) != string {
			$stateName : map-get($stateName, name);
		}

		// classes :
		$classes : gridle_get_state_var(classes, $stateName);

		// genrate the classname :
		@if $classes
		{
			@include gridle_state($stateName, false) {
				$length_a:length($found_patterns);
				$length_b:length($replacements);
				@if $length_a > 0 and $length_a <= $length_b {
					$list_indexes : ();
					@for $i from 1 through $length_a {
						$list_indexes : append($list_indexes, 1);
					}

					@while nth($list_indexes, 1) <= length( nth($replacements, 1) ){
						$gridle-scope : () !global;
						$replacement_pattern : $pattern;
						$replaced_count : 0;

						// Work the replacement
						@each $index, $flag in $found_patterns {
							$replaced_count : $replaced_count + 1;

							$current_replacement : nth( $replacements, $replaced_count );
							$current_index : nth($list_indexes, $replaced_count);

							$replacement_pattern : set-nth( $replacement_pattern, $index, nth( $current_replacement, $current_index ) );

							$var_name : str-slice($flag, 2);

							$gridle-scope : map-set( $gridle-scope, $var_name, nth( $current_replacement, $current_index ) ) !global;
						}

						#{_gridle_classname($replacement_pattern, $stateName)} {
							@content;
						}

						$gridle-scope : () !global;

						// Add 1 to indexes
						$break : false;
						$current_iteration_index : length( $list_indexes ); // The last index
						@while $break == false {
							$list_indexes : set-nth( $list_indexes, $current_iteration_index, nth( $list_indexes, $current_iteration_index ) + 1 );

							@if nth( $list_indexes, $current_iteration_index ) > length( nth( $replacements, $current_iteration_index ) )
								and $current_iteration_index != 1 {
								$list_indexes : set-nth( $list_indexes, $current_iteration_index, 1);

								$current_iteration_index : $current_iteration_index - 1;
							}@else{
								$break : true;
							}
						}
					}
				}@else{
					#{_gridle_classname($pattern, $stateName)} {
						@content;
					}
				}
			}
		}
	}
}


//
// Generate all helpers classes
//
@mixin _gridle_generate_helper_classes (
	$state : null,
	$package : null
) {
	// helpers :
	@if _gridle_need_to_generate(float, $package) {
		#{_gridle_classname(float, $state, left)} {
			@include gridle_float(left);
		}
		#{_gridle_classname(float, $state, right)} {
			@include gridle_float(right);
		}
	}

	@if _gridle_need_to_generate(clear, $package) {
		#{_gridle_classname(clear, $state)} {
			@include gridle_clear(both);
		}
		#{_gridle_classname(clear, $state, left)} {
			@include gridle_clear(left);
		}
		#{_gridle_classname(clear, $state, right)} {
			@include gridle_clear(right);
		}
	}

	@if _gridle_need_to_generate(no-gutter, $package) {
		#{_gridle_classname(no-gutter, $state)} {
			@include gridle_no_gutter();
		}
		#{_gridle_classname(no-gutter, $state, left)} {
			@include gridle_no_gutter(left);
		}
		#{_gridle_classname(no-gutter, $state, right)} {
			@include gridle_no_gutter(right);
		}
		#{_gridle_classname(no-gutter, $state, top)} {
			@include gridle_no_gutter(top);
		}
		#{_gridle_classname(no-gutter, $state, bottom)} {
			@include gridle_no_gutter(bottom);
		}
	}

	@if _gridle_need_to_generate(gutter, $package) {
		#{_gridle_classname(gutter, $state)} {
			@include gridle_gutter(top right bottom left);
		}
		#{_gridle_classname(gutter, $state, left)} {
			@include gridle_gutter(left);
		}
		#{_gridle_classname(gutter, $state, right)} {
			@include gridle_gutter(right);
		}
		#{_gridle_classname(gutter, $state, top)} {
			@include gridle_gutter(top);
		}
		#{_gridle_classname(gutter, $state, bottom)} {
			@include gridle_gutter(bottom);
		}
	}

	@if _gridle_need_to_generate(auto-height, $package) {
		#{_gridle_classname(auto-height, $state)} {
			height:inherit;
		}
	}

	@if _gridle_need_to_generate(grid-centered, $package) {
		#{_gridle_classname(grid-centered, $state)} {
			@include gridle_grid_centered();
		}
	}

	@if _gridle_need_to_generate(container, $package) {
		#{_gridle_classname(container, $state)} {
			@include gridle_container();
		}
	}

	@if _gridle_need_to_generate(row, $package) {
		#{_gridle_classname(row, $state)} {
			@include gridle_row(false);
		}
		#{_gridle_classname(row, $state, reverse)} {
			@include gridle_row(true);
		}
	}

	@if _gridle_need_to_generate(row-full, $package) {
		#{_gridle_classname(row-full, $state)} {
			@include gridle_row_full();
		}
	}

	@if _gridle_need_to_generate(col, $package) {
		#{_gridle_classname(col, $state)} {
			@include gridle_col(false);
		}
		#{_gridle_classname(col, $state, reverse)} {
			@include gridle_col(true);
		}
	}

	@if _gridle_need_to_generate(grid-table, $package) {
		#{_gridle_classname(grid-table, $state)} {
			@include gridle_grid_table();
		}
	}

	@if _gridle_need_to_generate(grid-adapt, $package) {
		#{_gridle_classname(grid-adapt, $state)} {
			@include gridle_grid_adapt();
		}
	}

	@if _gridle_need_to_generate(grid-grow, $package) {
		#{_gridle_classname(grid-grow, $state)} {
			@include gridle_grid_grow();
		}
	}

	@if _gridle_need_to_generate(row-align, $package) {
		#{_gridle_classname(row-align, $state, left)} {
			@include gridle_row_align(left);
		}
		#{_gridle_classname(row-align, $state, center)} {
			@include gridle_row_align(center);
		}
		#{_gridle_classname(row-align, $state, right)} {
			@include gridle_row_align(right);
		}
		#{_gridle_classname(row-align, $state, middle)} {
			@include gridle_row_align(middle);
		}
		#{_gridle_classname(row-align, $state, top)} {
			@include gridle_row_align(top);
		}
		#{_gridle_classname(row-align, $state, bottom)} {
			@include gridle_row_align(bottom);
		}
		@if gridle_is_driver(flex) {
			#{_gridle_classname(row-align, $state, around)} {
				@include gridle_row_align(around);
			}
			#{_gridle_classname(row-align, $state, between)} {
				@include gridle_row_align(between);
			}
		}
	}

	//
	// Wrapping
	//
	@if _gridle_need_to_generate(nowrap, $package) {
		#{_gridle_classname(nowrap, $state)} {
			@include gridle_nowrap();
		}
	}
	@if _gridle_need_to_generate(wrap, $package) {
		#{_gridle_classname(wrap, $state)} {
			@include gridle_wrap();
		}
	}

	//
	// Visible, hide, etc...
	//
	@if _gridle_need_to_generate(hide, $package) {
		#{_gridle_classname(hide, $state)} {
			@include gridle_hide();
		}
	}

	@if _gridle_need_to_generate(not-visible, $package) {
		#{_gridle_classname(not-visible, $state)} {
			@include gridle_not_visible();
		}
	}

	@if _gridle_need_to_generate(show, $package) {
		#{_gridle_classname(show, $state)} {
			@include gridle_show();
		}
	}

	@if _gridle_need_to_generate(show-inline, $package) {
		#{_gridle_classname(show-inline, $state)} {
			@include gridle_show_inline();
		}
	}

	@if _gridle_need_to_generate(visible, $package) {
		#{_gridle_classname(visible, $state)} {
			@include gridle_visible();
		}
	}

	//
	// Clear each class :
	//
	@if _gridle_need_to_generate(clear-each, $package) {
		@each $clearName, $clearMap in $_gridle_clear_classes {
			// get count :
			$clearCount : map-get($clearMap, clearEach);
			// what to clear :
			$clearWhat : map-get($clearMap, clearWhat);
			// generate the class :
			#{_gridle_classname(clear-each, $state, $clearCount)} {
				@include gridle_clear_each($clearCount, $clearWhat);
			}
		}
	}

	//
	// debug
	//
	@if _gridle_need_to_generate(row-debug, $package) {
		#{_gridle_classname(row-debug, $state)} {
			@include gridle_row_debug();
		}
	}
}


//
// Generate json settings
//
@mixin gridle_generate_json_settings() {

	// settings content :
	$gridle-settings-states : "{";

	// generate all classes for differents media queries :
	$statesCount : length($_gridle_states);
	$i : 0;
	@each $stateName, $state in $_gridle_states {

		$name : $stateName;

		$gridle-settings-states : "#{$gridle-settings-states} \"#{$name}\":{";

		@each $varName, $var in $state {

			$value : null;
			@if $varName == "query" {
				$value : gridle_get_media_query($stateName);
			} @else {
				$value : map-get($state,$varName);
			}

			@if $value == null {
				$gridle-settings-states : "#{$gridle-settings-states} \"#{$varName}\" : null,";
			} @elseif type-of($value) == bool {
				$gridle-settings-states : "#{$gridle-settings-states} \"#{$varName}\" : #{$value},";
			} @elseif type-of($value) == map {
				$gridle-settings-states : "#{$gridle-settings-states} \"#{$varName}\" : {";
				@each $vn, $vv in $value {
					$gridle-settings-states : "#{$gridle-settings-states} \"#{$vn}\" : \"#{$vv}\","
				}
				$gridle-settings-states : "#{$gridle-settings-states} \"_\" : true";
				$gridle-settings-states : "#{$gridle-settings-states} },";
			} @else {
				$gridle-settings-states : "#{$gridle-settings-states} \"#{$varName}\" : \"#{$value}\",";
			}
		}

		$gridle-settings-states : "#{$gridle-settings-states} \"_\" : true";

		@if $i >= $statesCount - 1 {
			$gridle-settings-states : "#{$gridle-settings-states} }";
		} @else {
			$gridle-settings-states : "#{$gridle-settings-states} },";
		}

		// update i :
		$i : $i + 1;

	}

	 // generate settings json :
	$gridle-settings-states : "#{$gridle-settings-states}}";
	$gridle-settings : "{";
	$gridle-settings : "#{$gridle-settings} \"version\" : \"#{$_gridle-version}\"";

	// states :
	$gridle-settings : "#{$gridle-settings}, \"states\" : #{$gridle-settings-states}";

	// settings :
	$gridle-settings : "#{$gridle-settings} }";
	#gridle-settings {
		content : $gridle-settings;
	}
}


//
// Generate classes
//
@mixin gridle_generate_classes(
	$states : all,
	$package : all,
	$scope : null
) {

	// init gridle
	@include gridle_init();

	// check if a scope exist
	@if $scope {
		// wrapp grid into scope
		.#{$scope} {
			@include _gridle_generate_classes($states, $package, true);
		}
	} @else {
		// generate classes
		@include _gridle_generate_classes($states, $package, false);
	}
}
$_gridle_generateOnlyOnce : true !default; // keep track of generate once classes
@mixin _gridle_generate_classes(
	$states : all,
	$package : all,
	$has-parent : false
) {

	// set that we are in generate phase (that can be used anywhere)
	$_gridle_is_in_generate_phase : true !global;

	// get all the registered states that will be processed after
	// to determine which states to generate
	$generate-states : gridle_get_states_names();

	// if we have provided some states to generate
	@if $states != null and $states != all {
		// check if we have only some - in the states list
		// mean that we want to only remove these specified states
		// from the all states list
		$onlyRemove : true;
		@each $stateName in $states {
			@if str-slice($stateName,1,1) != '-' {
				$onlyRemove : false;
			}
		}
		// if we want to only remove some states
		@if $onlyRemove {
			// loop on all the states to remove
			@each $stateName in $states {
				$sn : str-slice($stateName,2);
				$idx : index($generate-states, $sn);
				@if $idx != null {
					$generate-states : remove-nth($generate-states,$idx);
				}
			}
		} @else {
			$generate-states : $states;
		}
	}


	// generate these classes only once
	@if $_gridle_generateOnlyOnce
	{

		// update status
		$_gridle_generateOnlyOnce : false !global;

		// | ------------------------
		// | Windows 8 fix
		// | ------------------------

		// Windows 8 fix for snap mode
		@media screen and (max-width: 400px) {
			@-ms-viewport { width: device-width; }
		}

		// | ------------------------
		// | JSON Settings
		// | ------------------------

		// generate json settings
		@if $gridle-generate-json-settings
		{
			@include gridle_generate_json_settings();
		}

	}

	// loop on each states to generate all the classes
	@each $stateName in $generate-states {

		// get the actual state
		$state : gridle_get_state($stateName);
		$classes : gridle_get_state_var(classes, $state);

		// stop here if no classes wanted
		@if $classes {

			// debug
			// @debug("Generate classes for state #{$stateName}");

			// scope all the classes in a media query
			@include gridle_state($state, false) {

				// generate all classes for columns
				$i : 0;
				@each $columnName, $column in gridle_get_columns($state) {

					// variables
					$columnsCount : map-get($column, columns);
					$columnsContext : map-get($column, context);
					$columnsNameMultiplicator : map-get($column, name-multiplicator);

					// extend context in state (for columns)
					$extendedState : map-merge($state, (
						context : $columnsContext,
						name-multiplicator : $columnsNameMultiplicator // inject the name multiplicator here getted from column to handle custom registered columns
					));

					// classes
					@if _gridle_need_to_generate(grid, $package) {
						#{_gridle_classname(grid, $stateName, $columnName)} {
							@include gridle_grid($columnsCount, $columnsContext);
						}
					}
					@if _gridle_need_to_generate(push, $package) {
						#{_gridle_classname(push, $stateName, $columnName)} {
							@include gridle_push($columnsCount, $columnsContext);
						}
					}
					@if _gridle_need_to_generate(pull, $package) {
						#{_gridle_classname(pull, $stateName, $columnName)} {
							@include gridle_pull($columnsCount, $columnsContext);
						}
					}
					@if _gridle_need_to_generate(prefix, $package) {
						#{_gridle_classname(prefix, $stateName, $columnName)} {
							@include gridle_prefix($columnsCount, $columnsContext);
						}
					}
					@if _gridle_need_to_generate(suffix, $package) {
						#{_gridle_classname(suffix, $stateName, $columnName)} {
							@include gridle_suffix($columnsCount, $columnsContext);
						}
					}
					@if _gridle_need_to_generate(order, $package) {
						#{_gridle_classname(order, $stateName, first)} {
							@include gridle_order(-1);
						}
						#{_gridle_classname(order, $stateName, $i)} {
							@include gridle_order($i);
						}
						#{_gridle_classname(order, $stateName, last)} {
							@include gridle_order(9999);
						}
					}
					// up $i
					$i : $i + 1;
				}

				// media queries helpers classes
				@include _gridle_generate_helper_classes($stateName, $package);

				// handle direction on body
				body {
					direction: gridle_get_state_var(direction);
				}
			}
		}
	}

	// apply css for states of each elements
	@each $map in $_gridle_apply_css_for {
		@each $stateName, $fors in $map {
			@include _gridle_state($stateName, false) {
				@each $f, $rules in $fors {
					@if map-get($fors, $f) {
						@if _gridle_need_to_generate($f, $package) {
							@include gridle_selector($f, null) {
								@include _gridle_map_2_css($rules);
							}
						}
					}
				}
			}
		}
	}

	// make nested grids working automatically
	@if _gridle_need_to_generate(col, $package) or _gridle_need_to_generate(row, $package) {
		@each $stateName, $state in gridle_get_states() {
			$classes : gridle_get_state_var(classes, $state);
			@if $classes {
				$gutter-left : gridle_get_state_var(gutter-left, $state);
				$gutter-right : gridle_get_state_var(gutter-right, $state);
				@include _gridle_state($stateName, false) {
					#{_gridle_get_generic_selector(grid)} > [class^="#{str-slice(_gridle_classname(row),2)}"],
					#{_gridle_get_generic_selector(grid)} > [class^="#{str-slice(_gridle_classname(col),2)}"] {
						margin-left: -#{$gutter-left};
						margin-right: -#{$gutter-right};
					}
					// [class*="#{str-slice(_gridle_classname(grid),2)}"] > [class^="#{str-slice(_gridle_classname(row),2)}"],
					// [class*="#{str-slice(_gridle_classname(grid),2)}"] > [class^="#{str-slice(_gridle_classname(col),2)}"] {
					// 	margin-left: -#{$gutter-left};
					// 	margin-right: -#{$gutter-right};
					// }
				}
			}
		}
	}

	// reset the variable that track if we are in generate phase or not
	$_gridle_is_in_generate_phase : false !global;
}
