#include "minishell.h"

static void buf_append(char **buf, size_t *len, size_t *cap, const char *s)
{
	size_t slen;
	char *newbuf;

	if (!s)
		return;
	slen = strlen(s);
	if (*len + slen + 1 > *cap)
	{
		*cap = (*len + slen + 1) * 2;
		newbuf = (char *)realloc(*buf, *cap);
		if (!newbuf)
			return;
		*buf = newbuf;
	}
	memcpy(*buf + *len, s, slen);
	*len += slen;
	(*buf)[*len] = '\0';
}

static void buf_append_char(char **buf, size_t *len, size_t *cap, char c)
{
	char tmp[2];
	tmp[0] = c;
	tmp[1] = '\0';
	buf_append(buf, len, cap, tmp);
}

static char *expand_word(const char *word, t_shell *sh)
{
	int in_single = 0;
	int in_double = 0;
	size_t i = 0;
	char *out = NULL;
	size_t len = 0, cap = 0;

	while (word && word[i])
	{
		if (word[i] == '\'' && !in_double)
		{
			in_single = !in_single;
			i++;
			continue;
		}
		if (word[i] == '"' && !in_single)
		{
			in_double = !in_double;
			i++;
			continue;
		}
		if (word[i] == '$' && !in_single)
		{
			if (word[i + 1] == '?')
			{
				char *v = ms_itoa(sh->last_status);
				buf_append(&out, &len, &cap, v);
				free(v);
				i += 2;
				continue;
			}
			if (ms_is_alpha((unsigned char)word[i + 1]))
			{
				size_t j = i + 1;
				while (word[j] && ms_is_alnum((unsigned char)word[j]))
					j++;
				char *name = ms_strndup(word + i + 1, j - (i + 1));
				char *val = env_get(sh, name);
				buf_append(&out, &len, &cap, val ? val : "");
				free(name);
				i = j;
				continue;
			}
		}
		buf_append_char(&out, &len, &cap, word[i]);
		i++;
	}
	if (!out)
		out = ms_strdup("");
	return out;
}

int expand_pipeline(t_pipeline *p, t_shell *sh)
{
	size_t i;
	int j;
	for (i = 0; i < p->count; i++)
	{
		for (j = 0; p->cmds[i]->argv && p->cmds[i]->argv[j]; j++)
		{
			char *neww = expand_word(p->cmds[i]->argv[j], sh);
			free(p->cmds[i]->argv[j]);
			p->cmds[i]->argv[j] = neww;
		}
		if (p->cmds[i]->redirs)
		{
			t_redir *r = p->cmds[i]->redirs;
			while (r)
			{
				if (r->target)
				{
					char *nt = expand_word(r->target, sh);
					free(r->target);
					r->target = nt;
				}
				r = r->next;
			}
		}
	}
	return 0;
}
