#include "minishell.h"

static t_token *token_new(t_tokentype type, const char *text, size_t len)
{
	t_token *t = (t_token *)calloc(1, sizeof(t_token));
	if (!t)
		return NULL;
	t->type = type;
	if (text)
		t->text = ms_strndup(text, len);
	return t;
}

static void token_add(t_token **head, t_token *new)
{
	t_token *cur;
	if (!new)
		return;
	if (!*head)
	{
		*head = new;
		return;
	}
	cur = *head;
	while (cur->next)
		cur = cur->next;
	cur->next = new;
}

void free_tokens(t_token *toks)
{
	t_token *n;
	while (toks)
	{
		n = toks->next;
		free(toks->text);
		free(toks);
		toks = n;
	}
}

static int is_meta(char c)
{
	return (c == '|' || c == '<' || c == '>');
}

static int read_word(const char *line, size_t *i, t_token **out)
{
	size_t start = *i;
	int in_single = 0;
	int in_double = 0;

	while (line[*i])
	{
		if (line[*i] == '\'' && !in_double)
			in_single = !in_single;
		else if (line[*i] == '"' && !in_single)
			in_double = !in_double;
		else if (!in_single && !in_double)
		{
			if (ms_is_space(line[*i]) || is_meta(line[*i]))
				break;
		}
		(*i)++;
	}
	if (in_single || in_double)
		return 1;
	*out = token_new(TOK_WORD, line + start, *i - start);
	return 0;
}

t_token *lex_line(const char *line, int *error)
{
	t_token *toks = NULL;
	size_t i = 0;

	*error = 0;
	while (line[i])
	{
		if (ms_is_space(line[i]))
		{
			i++;
			continue;
		}
		if (line[i] == '|')
		{
			token_add(&toks, token_new(TOK_PIPE, "|", 1));
			i++;
			continue;
		}
		if (line[i] == '<')
		{
			if (line[i + 1] == '<')
			{
				token_add(&toks, token_new(TOK_HEREDOC, "<<", 2));
				i += 2;
			}
			else
			{
				token_add(&toks, token_new(TOK_REDIR_IN, "<", 1));
				i++;
			}
			continue;
		}
		if (line[i] == '>')
		{
			if (line[i + 1] == '>')
			{
				token_add(&toks, token_new(TOK_REDIR_APPEND, ">>", 2));
				i += 2;
			}
			else
			{
				token_add(&toks, token_new(TOK_REDIR_OUT, ">", 1));
				i++;
			}
			continue;
		}
		{
			t_token *w = NULL;
			if (read_word(line, &i, &w))
			{
				*error = 1;
				free_tokens(toks);
				return NULL;
			}
			token_add(&toks, w);
		}
	}
	return toks;
}
