#include "minishell.h"

static t_command *command_new(void)
{
	t_command *cmd = (t_command *)calloc(1, sizeof(t_command));
	return cmd;
}

static void command_add_arg(t_command *cmd, const char *text)
{
	char **new_argv;
	int i;

	if (!cmd || !text)
		return;
	i = cmd->argc;
	new_argv = (char **)calloc((size_t)i + 2, sizeof(char *));
	if (!new_argv)
		return;
	for (int j = 0; j < i; j++)
		new_argv[j] = cmd->argv[j];
	new_argv[i] = ms_strdup(text);
	new_argv[i + 1] = NULL;
	free(cmd->argv);
	cmd->argv = new_argv;
	cmd->argc += 1;
}

static void command_add_redir(t_command *cmd, t_redirtype type, const char *target)
{
	t_redir *r = (t_redir *)calloc(1, sizeof(t_redir));
	t_redir *cur;
	if (!r)
		return;
	r->type = type;
	r->target = ms_strdup(target);
	r->fd = -1;
	r->next = NULL;
	if (!cmd->redirs)
	{
		cmd->redirs = r;
		return;
	}
	cur = cmd->redirs;
	while (cur->next)
		cur = cur->next;
	cur->next = r;
}

static void free_redirs(t_redir *r)
{
	t_redir *n;
	while (r)
	{
		n = r->next;
		if (r->fd != -1)
			close(r->fd);
		free(r->target);
		free(r);
		r = n;
	}
}

void free_pipeline(t_pipeline *p)
{
	size_t i;
	if (!p)
		return;
	for (i = 0; i < p->count; i++)
	{
		if (p->cmds[i])
		{
			for (int j = 0; p->cmds[i]->argv && p->cmds[i]->argv[j]; j++)
				free(p->cmds[i]->argv[j]);
			free(p->cmds[i]->argv);
			free(p->cmds[i]->path);
			free_redirs(p->cmds[i]->redirs);
			free(p->cmds[i]);
		}
	}
	free(p->cmds);
	free(p);
}

static int pipeline_add_cmd(t_pipeline *p, t_command *cmd)
{
	t_command **new_cmds;
	size_t i;

	new_cmds = (t_command **)calloc(p->count + 1, sizeof(t_command *));
	if (!new_cmds)
		return 1;
	for (i = 0; i < p->count; i++)
		new_cmds[i] = p->cmds[i];
	new_cmds[p->count] = cmd;
	free(p->cmds);
	p->cmds = new_cmds;
	p->count += 1;
	return 0;
}

t_pipeline *parse_tokens(t_token *toks, int *error)
{
	t_pipeline *p;
	t_command *cmd;
	t_token *cur;

	*error = 0;
	p = (t_pipeline *)calloc(1, sizeof(t_pipeline));
	if (!p)
		return NULL;
	cmd = command_new();
	if (!cmd)
	{
		free(p);
		return NULL;
	}
	cur = toks;
	while (cur)
	{
		if (cur->type == TOK_PIPE)
		{
			if (cmd->argc == 0)
			{
				*error = 1;
				free_pipeline(p);
				free(cmd);
				return NULL;
			}
			pipeline_add_cmd(p, cmd);
			cmd = command_new();
			if (!cmd)
			{
				*error = 1;
				free_pipeline(p);
				return NULL;
			}
			cur = cur->next;
			continue;
		}
		if (cur->type == TOK_REDIR_IN || cur->type == TOK_REDIR_OUT
			|| cur->type == TOK_REDIR_APPEND || cur->type == TOK_HEREDOC)
		{
			if (!cur->next || cur->next->type != TOK_WORD)
			{
				*error = 1;
				free_pipeline(p);
				free(cmd);
				return NULL;
			}
			if (cur->type == TOK_REDIR_IN)
				command_add_redir(cmd, REDIR_IN, cur->next->text);
			else if (cur->type == TOK_REDIR_OUT)
				command_add_redir(cmd, REDIR_OUT, cur->next->text);
			else if (cur->type == TOK_REDIR_APPEND)
				command_add_redir(cmd, REDIR_APPEND, cur->next->text);
			else if (cur->type == TOK_HEREDOC)
				command_add_redir(cmd, REDIR_HEREDOC, cur->next->text);
			cur = cur->next->next;
			continue;
		}
		if (cur->type == TOK_WORD)
			command_add_arg(cmd, cur->text);
		cur = cur->next;
	}
	if (cmd->argc == 0)
	{
		*error = 1;
		free_pipeline(p);
		free(cmd);
		return NULL;
	}
	pipeline_add_cmd(p, cmd);
	return p;
}
