#include "push_swap.h"

int	last_element(t_stack *a)
{
	while (a->next)
		a = a->next;
	return (a->n);
}

// size is initialized to 1 because the loop check the next element, so it will end one step before reaching it
// it checks the next one to avoid handle the first one with ->limit set to 1
int	sublist_size(t_stack *list)
{
	int	size;

	if (list == NULL)
		return (0);
	size = 1;
	while (list->next != NULL && list->next->limit != 1)
	{
		list = list->next;
		size++;
	}
	return (size);
}

int	nbr_element_smaller(t_stack *list, int size, int pivot)
{
	int	nbr;

	nbr = 0;
	while (size-- > 0)
	{
		if (list->n < pivot)
			nbr++;
		list = list->next;
	}
	return (nbr);
}

// pivot is the smallest of the bigger group
int	find_pivot(t_stack *list, int size)
{
	int		pivot;
	t_stack	*head;

	pivot = list->n;
	head = list;
	while (head->next && nbr_element_smaller(list, size, pivot) != size / 2)
	{
		head = head->next;
		pivot = head->n;
	}
	return (pivot);
}

int	divide_a(t_stack **a, t_stack **b, t_list *solution)
{
	int		list_size;
	int		pivot;
	t_stack	*first_rotate;

	first_rotate = NULL;
	list_size = sublist_size(*a);
	pivot = find_pivot(*a, list_size);
	(*a)->limit = 0;
	while (list_size-- > 0)
	{
		if ((*a)->n >= pivot)
		{
			if (!first_rotate)
				first_rotate = *a;
			ra(a, &solution);
		}
		else
			pb(b, a, &solution);
	}
	while (*a != first_rotate)
		rra(a, &solution);
	(*a)->limit = 1;
	(*b)->limit = 1;
	mark_step(solution, "divide_a");
	return (0);
}

int	divide_b(t_stack **a, t_stack **b, t_list *solution)
{
	int	list_size;
	int	pivot;
	t_stack	*first_rotate;

	first_rotate = NULL;
	list_size = sublist_size(*b);
	pivot = find_pivot(*b, list_size);
	(*b)->limit = 0;
	while (list_size-- > 0)
	{
		if ((*b)->n >= pivot)
			pa(a, b, &solution);
		else
		{
			if (!first_rotate)
				first_rotate = *b;
			rb(b, &solution);
		}
	}
	while (*b != first_rotate)
		rrb(b, &solution);
	(*a)->limit = 1;
	(*b)->limit = 1;
	mark_step(solution, "divide_b");
	return (0);
}

void	send_sublist_to_a(t_stack **a, t_stack **b, t_list *solution)
{
	int	list_size;

	list_size = sublist_size(*b);
	(*b)->limit = 0;
	while (list_size-- > 0)
		pa(a, b, &solution);
	(*a)->limit = 1;
	if (*b)
		(*b)->limit = 1;
	mark_step(solution, "send_sublist_to_a");
}

/*
int	find_smallest(t_stack *list, int size)
{
	t_stack	*head;
	int		smallest;
	int		position;

	smallest = list->n;
	head = list;
	while (--size > 0)
	{
		head = head->next;
		if (head->n < smallest)
			smallest = head->n;
	}
	position = 0;
	while (list->n != smallest)
	{
		position++;
		list = list->next;
	}
	return (position);
}

void	mini_sort(t_stack **a, t_stack **b, t_list *solution)
{
	int	list_size;
	int	next;
	int	temp;

	list_size = sublist_size(*a);
	if(list_size == 1)
		return ;
	(*a)->limit = 0;
	while (--list_size > 0)
	{
		next = find_smallest(*a, list_size + 1);
		temp = next;
		while (next-- > 0)
			ra(a, &solution);
		pb(b, a, &solution);
		while (temp-- > 0)
			rra(a, &solution);
	}
	list_size = sublist_size(*b);
	while (list_size-- > 0)
		pa(a, b, &solution);
	(*a)->limit = 1;
	mark_step(solution, "mini_sort");
}
*/

void	mark_sublist(t_stack *list)
{
	while (list && list->limit != 1)
	{
		if (list->limit == 2)
			list->limit = 0;
		else if (list->limit == 0)
			list->limit = 2;
		list = list->next;
	}
}

int	find_smallest(t_stack *list)
{
	int	i;
	int	smallest;
	int	position;

	smallest = list->n;
	position = 1;
	i = 0;
	while (list)
	{
		i++;
		if (list->limit == 2 && list->n < smallest)
		{
			smallest = list->n;
			position = i;
		}
		list = list->next;
	}
	if (i - position + 1 < position)
		position = position - i - 1;
	return (position);
}

void	sort_big(t_stack **a, t_stack **b, t_list *solution)
{
	int	list_size;
	int	next;
	int	i;

	list_size = sublist_size(*a);
	mark_sublist(*a);
	while (--list_size >= 0)
	{
		i = 0;
		next = find_smallest(*a);
		if (next > 0)
			while (++i < next)
				ra(a, &solution);
		else if (next < 0)
			while (i-- > next)
				rra(a, &solution);
		pb(b, a, &solution);
	}
	list_size = sublist_size(*b);
	while (list_size-- > 0)
		pa(a, b, &solution);
	mark_sublist(*a);
}

int	find_rank(t_stack *list, int nbr, int i)
{
	t_stack	*head;
	int		comp;
	int		rank;
	int		j;

	head = list;
	j = 0;
	while (++j <= nbr - i)
		head = head->next;
	comp = head->n;
	head = list;
	j = 0;
	rank = 1;
	while (++j <= nbr)
	{
		if (comp > head->n)
			rank++;
		head = head->next;
	}
	return (rank);
}

int	order_is(t_stack *list, int nbr)
{
	int		order;
	int		rank;
	int		i;

	i = 0;
	order = 0;
	while (++i <= nbr)
	{
		rank = find_rank(list, nbr, i);
		order = order * 10 + rank;
	}
	return (order);
}

void	sort_4(t_stack **a, t_list *solution)
{
	int	order;

	order = order_is(*a, 4);
	if (order == 1234)
	{
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
	}
	else if (order == 1243)
	{
		ra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
	}
	else if (order == 1324)
	{
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
	}
	else if (order == 1342)
	{
		ra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
	}
	else if (order == 1423)
	{
		sa(a, &solution);
		ra(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
	}
	else if (order == 1432)
	{
		ra(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
	}
	else if (order == 2134)
	{
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
	}
	else if (order == 2143)
	{
		ra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
	}
	else if (order == 2314)
	{
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
	}
	else if (order == 2341)
	{
		ra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
	}
	else if (order == 2413)
	{
		sa(a, &solution);
		ra(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
	}
	else if (order == 2431)
	{
		ra(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
	}
	else if (order == 3124)
	{
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
	}
	else if (order == 3142)
	{
		ra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
	}
	else if (order == 3214)
	{
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		rra(a, &solution);
	}
	else if (order == 3241)
	{
		ra(a, &solution);
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		rra(a, &solution);
	}
	else if (order == 3412)
	{
		sa(a, &solution);
		ra(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		rra(a, &solution);
	}
	else if (order == 3421)
	{
		ra(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		rra(a, &solution);
	}
	else if (order == 4123)
	{
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
	}
	else if (order == 4132)
	{
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
	}
	else if (order == 4213)
	{
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
	}
	else if (order == 4231)
	{
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
	}
	else if (order == 4312)
		sa(a, &solution);
}

void	sort_3(t_stack **a, t_list *solution)
{
	int	order;

	order = order_is(*a, 3);
	if (order == 123)
	{
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
	}
	else if (order == 132)
	{
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
		sa(a, &solution);
	}
	else if (order == 213)
	{
		sa(a, &solution);
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
	}
	else if (order == 231)
	{
		ra(a, &solution);
		sa(a, &solution);
		rra(a, &solution);
	}
	else if (order == 312)
		sa(a, &solution);
}

void	sort_2(t_stack **a, t_list *solution)
{
	int	order;

	order = order_is(*a, 2);
	if (order == 12)
		sa(a, &solution);
}
void	mini_sort(t_stack **a, t_list *solution)
{
	int	list_size;

	list_size = sublist_size(*a);
	if(list_size == 1)
		return ;
	(*a)->limit = 0;
	if(list_size == 2)
		sort_2(a, solution);
	else if(list_size == 3)
		sort_3(a, solution);
	else if(list_size == 4)
		sort_4(a, solution);
	/*
	else if(list_size == 5)
		sort_5(a, solution);
	else if(list_size == 6)
		sort_6(a, solution);
	else
		sort_big(a, b, solution);
	*/
	(*a)->limit = 1;
	mark_step(solution, "mini_sort");
}

void	hugo_sort(t_stack **a, t_stack **b, t_list *solution)
{
	if (sublist_size(*a) > 3)
		divide_a(a, b, solution);
	else
	{
		mini_sort(a, solution);
		if (sublist_size(*b) > 3)
			divide_b(a, b, solution);
		else if (sublist_size(*b) > 0)
			send_sublist_to_a(a, b, solution);
		else
			return ;
	}
	hugo_sort(a, b, solution);
}

// /*
// ** n is the nbr of elements of the list that are competiting
// ** position start at 0, ie position 3 is the 4th element
// */
// int	match(t_stack *a, int n, int *smaller)
// {
// 	int		position;
// 	int		i;
// 
// 	*smaller = a->n;
// 	position = 0;
// 	i = 1;
// 	while (a->next && i < n)
// 	{
// 		a = a->next;
// 		if (a->n < *smaller)
// 		{
// 			*smaller = a->n;
// 			position = i;
// 		}
// 		i++;
// 	}
// 	return (position);
// }
// 
// void	nb_to_top(t_stack **a, t_list *solution, int i)
// {
// 	int	n;
// 
// 	if (!i)
// 		return ;
// 	n = i;
// 	while (--n)
// 		ra(a, &solution);
// 	n = i;
// 	sa(a, &solution);
// 	while (--n)
// 	{
// 		rra(a, &solution);
// 		sa(a, &solution);
// 	}
// }
// 
// void	push_to_b(t_stack **a, t_stack **b, t_list *solution, int position)
// {
// 	int i;
// 
// 	i = position;
// 	while (i--)
// 		ra(a, &solution);
// 	pb(b, a, &solution);
// 	while (++i < position)
// 		rra(a, &solution);
// }
// 
// /*
// ** so far it's bullshit :p
// */
// void	hugo_sort(t_stack **a, t_stack **b, t_list *solution)
// {
// 	int		last;
// 	int		position;
// 	int		value;
// 
// 	last = last_element(*a);
// 	while ((*a)->n != last)
// 	{
// 		position = match(*a, 4, &value);
// 		if (!(*b) || value > (*b)->n)
// 			push_to_b(a, b, solution, position);
// 		else
// 			ra(a, &solution);
// 	}
// }
/*
	sa(a, &solution);
	ra(a, &solution);
	rra(a, &solution);

	pb(b, a, &solution);
	pa(a, b, &solution);

	sb(b, &solution);
	rb(b, &solution);
	rrb(b, &solution);

	rrr(a, b, &solution);
	rr(a, b, &solution);
*/
