/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   init.c                                             :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: hulamy <hulamy@student.42.fr>              +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2022/01/26 15:30:34 by hulamy            #+#    #+#             */
/*   Updated: 2022/02/02 00:18:04 by hulamy           ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include "philo.h"

static t_philo	*lst_add_philo(t_params *params, t_global *global, int i)
{
	t_philo	*new;

	new = malloc(sizeof(t_philo) * 1);
	if (new == NULL)
		return (NULL);
	new->params = params;
	new->global = global;
	new->p_nbr = i + 1;
	if (pthread_mutex_init(&(new->m_fork), NULL) != 0)
		return (NULL);
	if (pthread_mutex_init(&(new->m_time), NULL) != 0)
		return (NULL);
	if (pthread_mutex_init(&(new->m_eat), NULL) != 0)
		return (NULL);
	new->t_last_meal.ts = 0;
	new->t_last_meal.tu = 0;
	new->eat_count = 0;
	new->next = NULL;
	return (new);
}

static t_philo	*init_chain_philo(t_params *params, t_global *global)
{
	t_philo	*philo;
	t_philo	*tmp;
	t_philo	*start;
	int		i;

	i = 0;
	philo = NULL;
	while (i < params->n_phi)
	{
		tmp = lst_add_philo(params, global, i);
		if (philo)
			philo->next = tmp;
		else
			start = tmp;
		philo = tmp;
		i++;
	}
	if (philo)
		philo->next = start;
	return (philo);
}

static t_params	*init_params(int ac, char **av)
{
	t_params	*params;
	int			i;

	if (ac < 5 || ac > 6)
		return (NULL);
	if (!ft_isdigit_2d_arr(av + 1))
		return (NULL);
	i = 0;
	while (av[i])
	{
		if (ft_int_overflow(av[i]))
			return (NULL);
		i++;
	}
	params = malloc(sizeof(t_params));
	if (!params)
		return (NULL);
	params->n_phi = ft_atoi(av[1]);
	params->t_die = ft_atoi(av[2]);
	params->t_eat = ft_atoi(av[3]);
	params->t_slp = ft_atoi(av[4]);
	params->n_eat = -1;
	if (ac == 6)
		params->n_eat = ft_atoi(av[5]);
	return (params);
}

static t_global	*init_global(void)
{
	t_global	*global;

	global = malloc(sizeof(t_global));
	if (!global)
		return (NULL);
	global->stop = 0;
	global->satiated_count = 0;
	global->t_start.ts = 0;
	global->t_start.tu = 0;
	if (pthread_mutex_init(&(global->m_print), NULL) != 0)
		return (NULL);
	if (pthread_mutex_init(&(global->m_init_time), NULL) != 0)
		return (NULL);
	if (pthread_mutex_init(&(global->m_stop), NULL) != 0)
		return (NULL);
	return (global);
}

t_philo	*init(int ac, char **av, pthread_t **id)
{
	t_philo		*philo;
	t_params	*params;
	t_global	*global;

	philo = NULL;
	params = NULL;
	global = NULL;
	params = init_params(ac, av);
	if (params == NULL)
		return (NULL);
	global = init_global();
	if (global == NULL)
		return (return_free(params, NULL, NULL));
	*id = malloc(sizeof(pthread_t) * params->n_phi);
	if (*id == NULL)
		return (return_free(params, global, NULL));
	philo = init_chain_philo(params, global);
	if (philo == NULL)
		return (return_free(params, global, *id));
	return (philo);
}
