/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   p_split.c                                          :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: rbousset <marvin@42.fr>                    +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2020/02/14 17:19:27 by rbousset          #+#    #+#             */
/*   Updated: 2020/02/14 17:19:29 by rbousset         ###   ########lyon.fr   */
/*                                                                            */
/* ************************************************************************** */

#include <libft.h>
#include <stdlib.h>

static size_t
	p_count_semi_words(const char line[])
{
	size_t	count;
	size_t	i;

	count = 0;
	i = 0;
	while (line[i] != '\0')
	{
		if (line[i] == ';' && line[i + 1] != ';' && line[i + 1] != '\0')
			count += 1;
		i++;
	}
	return (count);
}

static size_t
	p_count_and_or_words(const char line[], const char c)
{
	size_t	count;
	size_t	i;

	count = 0;
	i = 0;
	while (line[i] != '\0')
	{
		if (line[i] == c && line[i + 1] == c &&
			line[i + 2] != c && line[i + 2] != '\0')
			count += 1;
		i++;
	}
	return (count);
}

static char
	*p_get_first_occur(const char *line_ptr)
{
	char	*ptr[3];
	size_t	len[3];

	ptr[0] = ft_strnstr(line_ptr, ";", ft_strlen(line_ptr) + 1);
	ptr[1] = ft_strnstr(line_ptr, "&&", ft_strlen(line_ptr) + 1);
	ptr[2] = ft_strnstr(line_ptr, "||", ft_strlen(line_ptr) + 1);
	len[0] = ft_strlen(ptr[0]);
	len[1] = ft_strlen(ptr[1]);
	len[2] = ft_strlen(ptr[2]);
	if (len[0] > len[1] && len[0] > len[2])
		return (ptr[0]);
	else if (len[1] > len[0] && len[1] > len[2])
		return (ptr[1]);
	else if (len[2] > len[0] && len[2] > len[1])
		return (ptr[2]);
	return ((char*)line_ptr);
}

static char
	**p_split_destroy(char **words,
					size_t i)
{
	while (i > 0)
	{
		ft_memdel((void*)&words[i]);
	}
	ft_memdel((void*)&words);
	return (NULL);
}

static char
	**p_split_to_stuff(const char line[],
					const size_t count)
{
	char	**words;
	char	*line_ptr;
	char	*need_ptr;
	size_t	i;
	char	c;

	if ((words = (char**)malloc((count + 1) * sizeof(char*))) == NULL)
		return (NULL);
	line_ptr = (char*)line;
	i = 0;
	while (i < count)
	{
		need_ptr = p_get_first_occur(line_ptr);
		c = need_ptr[0];
		need_ptr += (c == ';') ? (1) : (0);
		need_ptr += (c == '&') ? (2) : (0);
		need_ptr += (c == '|') ? (2) : (0);
		if (need_ptr - line_ptr == 0)
		{
			if ((words[i] = (char*)malloc(((ft_strlen(line_ptr) + 2) *
				sizeof(char)))) == NULL)
				return (p_split_destroy(words, i));
			ft_memcpy(words[i], line_ptr, ft_strlen(line_ptr));
			words[i][ft_strlen(line_ptr)] = ';';
			words[i][ft_strlen(line_ptr) + 1] = '\0';
		}
		else
		{
			if ((words[i] = (char*)malloc(((need_ptr - line_ptr) + 1) *
				sizeof(char))) == NULL)
				return (p_split_destroy(words, i));
			ft_memcpy(words[i], line_ptr, (need_ptr - line_ptr) - 1);
			words[i][(need_ptr - line_ptr) - ((c == ';') ? (1) : (2))] = c;
			words[i][(need_ptr - line_ptr) - ((c == ';') ? (0) : (1))] = '\0';
			line_ptr = need_ptr;
		}
		i++;
	}
	words[i] = NULL;
	return (words);
}

char
	**p_split_line(const char line[])
{
	char	**words;
	size_t	count;

	count = p_count_semi_words(line);
	count += p_count_and_or_words(line, '&');
	count += p_count_and_or_words(line, '|');
	count += 1;
	if ((words = p_split_to_stuff(line, count)) == NULL)
		return (NULL);
	return (words);
}