/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   ft_priority_queue_utils.c                          :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: thrieg <thrieg@student.42mulhouse.fr>      +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2024/11/19 16:00:58 by thrieg            #+#    #+#             */
/*   Updated: 2025/02/16 19:07:01 by thrieg           ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include "ft_priority_queue_private.h"
#include "../ft_printf/ft_printf.h"

static inline void	pq_swap(t_priority_queue_node *a, t_priority_queue_node *b)
{
	t_priority_queue_node	temp;

	temp = *a;
	*a = *b;
	*b = temp;
}

void	heapify_up(t_priority_queue *pq, size_t index)
{
	size_t	parent;

	while (index > 0)
	{
		parent = (index - 1) / 2;
		if (pq->nodes[index].priority < pq->nodes[parent].priority)
		{
			pq_swap(&pq->nodes[index], &pq->nodes[parent]);
			index = parent;
		}
		else if (pq->nodes[index].priority == pq->nodes[parent].priority
			&& pq->compare(pq->nodes[index].data, pq->nodes[parent].data) < 0)
		{
			pq_swap(&pq->nodes[index], &pq->nodes[parent]);
			index = parent;
		}
		else
		{
			break ;
		}
	}
}

void	heapify_down(t_priority_queue *pq, size_t index)
{
	size_t	smallest;
	size_t	left;
	size_t	right;

	smallest = index;
	left = 2 * index + 1;
	right = 2 * index + 2;
	if (left < pq->size
		&& ((pq->nodes[left].priority < pq->nodes[smallest].priority)
			|| (pq->compare(pq->nodes[left].data,
					pq->nodes[smallest].data) < 0)))
		smallest = left;
	if (right < pq->size
		&& ((pq->nodes[right].priority < pq->nodes[smallest].priority)
			|| (pq->compare(pq->nodes[right].data,
					pq->nodes[smallest].data) < 0)))
		smallest = right;
	if (smallest != index)
	{
		pq_swap(&pq->nodes[index], &pq->nodes[smallest]);
		heapify_down(pq, smallest);
	}
}

void	ft_resize_pq(t_priority_queue *pq)
{
	size_t					new_capacity;
	t_priority_queue_node	*new_nodes;
	size_t					i;

	new_capacity = pq->capacity * 2;
	new_nodes = malloc(new_capacity * sizeof(t_priority_queue_node));
	if (!new_nodes)
		return ;
	i = 0;
	while (i < pq->size)
	{
		new_nodes[i] = pq->nodes[i];
		i++;
	}
	free(pq->nodes);
	pq->nodes = new_nodes;
	pq->capacity = new_capacity;
}

void	ft_shrink_pq(t_priority_queue *pq)
{
	size_t					new_capacity;
	t_priority_queue_node	*new_nodes;
	size_t					i;

	if (pq->size >= pq->capacity / 4 || pq->capacity <= 4)
		return ;
	new_capacity = pq->capacity / 2;
	new_nodes = malloc(new_capacity * sizeof(t_priority_queue_node));
	if (!new_nodes)
		return ;
	i = 0;
	while (i < pq->size)
	{
		new_nodes[i] = pq->nodes[i];
		i++;
	}
	free(pq->nodes);
	pq->nodes = new_nodes;
	pq->capacity = new_capacity;
}
