/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   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>
#include <limits.h>

#include "f_fail.h"
#include "d_define.h"
#include "p_split.h"
#include "s_struct.h"
#include "u_parse.h"
#include "u_utils.h"

static void	p_meet_splitter(char *ptr,
							const char line[],
							t_split_block *sp,
							t_quote_mode mode)
{
	if (mode == Q_NONE && *ptr == C_SEMIC && *(ptr + 1) != C_SEMIC
		&& u_is_not_escaped(line, ptr) == TRUE)
	{
		sp->pos[sp->count] = (ptr - line);
		sp->nextif[sp->count] = 0;
		sp->count += 1;
	}
	else if (mode == Q_NONE && *ptr == C_AMP && *(ptr + 1) == C_AMP
		&& (*ptr + 2) != C_PIPE && u_is_not_escaped(line, ptr) == TRUE)
	{
		sp->pos[sp->count] = (ptr - line);
		sp->nextif[sp->count] = 1;
		sp->count += 1;
	}
	else if (mode == Q_NONE && *ptr == C_PIPE && *(ptr + 1) == C_PIPE
		&& *(ptr + 2) != C_PIPE && u_is_not_escaped(line, ptr) == TRUE)
	{
		sp->pos[sp->count] = (ptr - line);
		sp->nextif[sp->count] = 2;
		sp->count += 1;
	}
}

static void	p_fill_sp(t_split_block *sp, const char line[])
{
	char			*ptr;
	t_quote_mode	mode;

	sp->pos[0] = 0;
	sp->nextif[0] = 0;
	sp->count = 0;
	mode = Q_NONE;
	ptr = (char*)line;
	while (*ptr != C_NUL)
	{
		if (*ptr == C_SQUOTE)
			mode = u_meet_squote(line, ptr, mode);
		else if (*ptr == C_DQUOTE)
			mode = u_meet_dquote(line, ptr, mode);
		else if (*ptr == C_SEMIC || *ptr == C_AMP || *ptr == C_PIPE)
			p_meet_splitter(ptr, line, sp, mode);
		ptr++;
	}
	sp->pos[sp->count] = ptr - line;
	sp->nextif[sp->count] = 0;
	sp->count += 1;
}

static void	*p_del_split(char *words[], size_t todel)
{
	size_t	i;

	i = 0;
	while (i < todel)
	{
		ft_memdel((void*)&words[i]);
	}
	ft_memdel((void*)&words);
	return (NULL);
}

static char	**p_get_words(const char line[], const t_split_block *sp)
{
	char	**words;
	int64_t	i;
	size_t	oldpos;
	int8_t	oldif;

	if ((words = (char**)malloc((sp->count + 1) * sizeof(char*))) == NULL)
		return (NULL);
	oldpos = 0;
	oldif = -1;
	i = -1;
	while (++i < sp->count)
	{
		if ((words[i] = (char*)malloc(((sp->pos[i] - oldpos) + 2) *
			sizeof(char))) == NULL)
			return ((char**)p_del_split(words, i));
		ft_strlcpy(words[i], line + oldpos + ((oldif > 0) ? (2) : (oldif) + 1),
			sp->pos[i] - oldpos + 1 - ((oldif > 0) ? (2) : (1)) +
			((oldif < 0) ? (1) : (0)));
		words[i][ft_strlen(words[i]) + 1] = C_NUL;
		words[i][ft_strlen(words[i])] = sp->nextif[i] + 0x30;
		oldpos = sp->pos[i];
		oldif = sp->nextif[i];
	}
	words[i] = NULL;
	return (words);
}

char		**p_split_line(char line[])
{
	t_split_block	sp;
	char			**words;

	words = NULL;
	p_fill_sp(&sp, line);
	if ((words = p_get_words(line, &sp)) == NULL)
	{
		ft_memdel((void*)&line);
		return (NULL);
	}
	ft_memdel((void*)&line);
	return (words);
}