/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   get_next_line.c                                    :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: bchanot <bchanot@student.42.fr>            +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2015/12/13 15:04:06 by bchanot           #+#    #+#             */
/*   Updated: 2018/04/17 11:47:45 by bchanot          ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include "libft.h"
#include <unistd.h>

static t_gnl	*gnl_add(int fd)
{
	t_gnl	*tmp;

	if (!(tmp = (t_gnl *)ft_memalloc(sizeof(t_gnl))))
		return (NULL);
	tmp->tmp = NULL;
	tmp->eof = 0;
	tmp->fd = fd;
	tmp->next = NULL;
	return (tmp);
}

static t_gnl	*gnl_find_reader(t_gnl **list, int fd)
{
	t_gnl	*tmp;

	tmp = *list;
	while (tmp)
	{
		if (tmp->fd == fd)
		{
			if (!tmp->tmp && tmp->eof == 1)
				tmp->eof = 0;
			return (tmp);
		}
		tmp = tmp->next;
	}
	tmp = *list;
	if (!(*list))
		return ((*list = gnl_add(fd)));
	while (tmp->next)
		tmp = tmp->next;
	return ((tmp->next = gnl_add(fd)));
}

static int		gnl_check_already(t_gnl *rdr, char **line)
{
	char	*chr;

	if ((chr = ft_strdup(ft_strchr(rdr->tmp, '\n'))))
	{
		*line = ft_strndup(rdr->tmp, ft_strlen(rdr->tmp) - ft_strlen(chr));
		ft_memdel((void **)&(rdr->tmp));
		rdr->tmp = ft_strdup(chr + 1);
		ft_memdel((void **)&chr);
		return (1);
	}
	if (rdr->eof == 1 && (!rdr->tmp || !(*(rdr->tmp))))
		return (0);
	if (rdr->eof == 1)
	{
		*line = ft_strdup(rdr->tmp);
		ft_memdel((void **)&(rdr->tmp));
		return (0);
	}
	return (-1);
}

static int		gnl_read(t_gnl *rdr, char **chr)
{
	char	*tmp;
	char	c[BUFF_SIZE + 1];
	int		ret;

	tmp = NULL;
	ft_bzero(c, BUFF_SIZE + 1);
	while ((ret = read(rdr->fd, c, BUFF_SIZE)))
	{
		if (rdr->tmp)
		{
			tmp = ft_strnew(ft_strlen(rdr->tmp) + ft_strlen(c));
			ft_memcpy(tmp, rdr->tmp, ft_strlen(rdr->tmp));
			ft_memcpy(tmp + ft_strlen(rdr->tmp), c, ft_strlen(c));
			ft_memdel((void **)&(rdr->tmp));
			rdr->tmp = tmp;
		}
		else
			rdr->tmp = ft_strdup(c);
		ft_bzero(c, BUFF_SIZE + 1);
		if ((*chr = ft_strdup(ft_strchr(rdr->tmp, '\n'))))
			break ;
	}
	return (ret);
}

int				get_next_line(const int fd, char **line)
{
	static t_gnl	*readers = NULL;
	t_gnl			*rdr;
	char			*chr;
	int				ret;

	if (fd < 0 || !line || !(rdr = gnl_find_reader(&readers, fd)))
		return (-1);
	if ((ret = gnl_check_already(rdr, line)) > -1)
		return (ret);
	chr = NULL;
	ret = gnl_read(rdr, &chr);
	if (ret < BUFF_SIZE && fd != 0)
		rdr->eof = 1;
	if (!chr)
	{
		if (rdr->tmp && *(rdr->tmp))
			*line = ft_strdup(rdr->tmp);
		ft_memdel((void **)&(rdr->tmp));
		return (0);
	}
	*line = ft_strndup(rdr->tmp, ft_strlen(rdr->tmp) - (ft_strlen(chr)));
	ft_memdel((void **)&(rdr->tmp));
	rdr->tmp = ft_strdup(chr + 1);
	ft_memdel((void **)&chr);
	return (rdr->eof == 1 && !rdr->tmp ? 0 : 1);
}
