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

#include "b_export_next.h"
#include "d_define.h"
#include "f_fail.h"
#include "s_destroy.h"
#include "s_struct.h"
#include "u_utils.h"
#include "u_vars.h"
#include "u_vars_next.h"

static void
	b_set_oldpwd(t_msh *msh)
{
	char	pwd[PATH_MAX];
	char	tmp[PATH_MAX];

	u_get_var_value(pwd, "$PWD", PATH_MAX, msh);
	if (pwd[0] == C_NUL)
	{
		ft_strlcpy(pwd, msh->cwd, PATH_MAX);
	}
	u_get_var_value(tmp, "$OLDPWD", PATH_MAX, msh);
	if (tmp[0] == C_NUL)
	{
		ft_sprintf(tmp, "%s=%s", "OLDPWD", pwd);
		b_export_with_equals(tmp, msh);
	}
	else
	{
		u_subst_var_value("$OLDPWD", pwd, msh);
	}
}

static void
	b_fill_repath(char repath[],
				char *splited[])
{
	size_t	i;
	size_t	j;

	i = 0;
	repath[0] = (splited[0] == NULL) ? '/' : repath[0];
	while (splited[i] != NULL)
	{
		if (ft_strncmp(splited[i], "..", 3) == 0)
		{
			j = (repath[0] == '\0') ? (0) : (ft_strlen(repath));
			while (repath[j] != '/' && j > 0)
				j--;
			repath[j] = '\0';
		}
		else if (ft_strncmp(splited[i], ".", 2) == 0)
		{
		}
		else
		{
			j = (ft_strncmp(repath, "/", 2) == 0) ? (1) : (ft_strlen(repath) + 1);
			repath[j - 1] = '/';
			ft_strlcpy(repath + j, splited[i], ft_strlen(splited[i]) + 1);
		}
		i++;
	}
}

static void
	b_upgrade_pwd(const char path[], t_msh *msh)
{
	char	**splited;
	char	repath[262144];
	char	fmt[262144];

	b_set_oldpwd(msh);
	splited = NULL;
	repath[0] = '\0';
	if (path[0] != '/')
		ft_memcpy(repath, msh->cwd, (ft_strlen(msh->cwd) + 1) * sizeof(char));
	if (path[0] == '/' && path[1] == '\0')
		ft_memcpy(repath, "/", 2 * sizeof(char));
	else if ((splited = ft_split(path, '/')) == NULL)
		f_alloc_and_destroy_msh(msh);
	if (splited != NULL)
	{
		b_fill_repath(repath, splited);
		ft_delwords(splited);
	}
	repath[0] = (repath[0] == '\0') ? '/' : repath[0];
	ft_sprintf(fmt, "%s=%s", "PWD", repath);
	b_export_with_equals(fmt, msh);
	ft_memdel((void*)&msh->cwd);
	if ((msh->cwd = ft_strdup(repath)) == NULL)
		f_alloc_and_destroy_msh(msh);
}

uint8_t
	b_cd(char *args[],
		t_msh *msh)
{
	const uint64_t	argc = u_builtins_get_argc((const char**)args);
	char			path[PATH_MAX];

	if (argc >= 2)
	{
		f_fail_too_many_args("cd", msh);
		return (1);
	}
	else if (argc == 0)
	{
		u_get_var_value(path, "$HOME", PATH_MAX, msh);
		if (path[0] == C_NUL)
		{
			ft_dprintf(STDERR_FILENO, "minishell: cd: %s\n",
				FT_FAIL_HOME_NOT_SET);
			return (2);
		}
	}
	else
		ft_strlcpy(path, *args, PATH_MAX);
	if (chdir(path) != 0)
	{
		f_fail_chd("cd", path, msh);
		return (1);
	}
	b_upgrade_pwd(path, msh);
	return (0);
}