/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   here_doc.c                                         :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: lperrey <lperrey@student.42.fr>            +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2021/11/11 18:46:43 by lperrey           #+#    #+#             */
/*   Updated: 2021/11/29 12:38:58 by lperrey          ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include "minishell.h"

#define TMP_HERE_DOC "/tmp/minishell_here_doc"

static int	here_doc_write(char *delimiter, int doc_fd);

int	here_doc(char *delimiter)
{
	// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04
	// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02
	/* If any part of word is quoted,
	the delimiter shall be formed by performing quote removal on word,
	and the here-document lines shall not be expanded.
	Otherwise, the delimiter shall be the word itself. */
	// TODO : A voir si on fait les expansions de variables dans le here_doc.
	// implementer une gestion des signaux pour here_doc (verifier comportement bash et doc POSIX).
	// Peut-être remplacer gnl() par readline() pour avoir une gestion correct
	// du terminal (actuellement l'affichage lors du changement de ligne est foireux).
	int	here_doc;
	int	ret;

	delimiter = ft_strdup_quotes(delimiter);
	if (!delimiter)
		return (ft_reti_perror(-1, "ft_strdup_quotes()"));
	here_doc = open(TMP_HERE_DOC, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
	if (here_doc == -1)
		return (ft_reti_perror_io(-1, "open() ", TMP_HERE_DOC));
	ret = here_doc_write(delimiter, here_doc);
	free(delimiter);
	if (close(here_doc) == -1)
		ft_perror_io("close() ", TMP_HERE_DOC);
	if (ret != 0)
	{
		if (unlink(TMP_HERE_DOC) == -1)
			return (ft_reti_perror_io(ret, "unlink() ", TMP_HERE_DOC));
		return (ret);
	}
	here_doc = open(TMP_HERE_DOC, O_RDONLY);
	if (here_doc == -1)
		ft_perror_io("open() ", TMP_HERE_DOC);
	if (unlink(TMP_HERE_DOC) == -1)
		return (ft_reti_perror_io(-1, "unlink() ", TMP_HERE_DOC));
	return (here_doc);
}

int	void_func_return_readline(void)
{
	return (0);
}

// rl_done
//   Setting this to a non-zero value causes Readline to return the current line
//   immediately
// rl_event_hook
//   If non-zero, this is the address of a function to call periodically when Readline
//   is waiting for terminal input. By default, this will be called at most ten times
//   a second if there is no keyboard input
// from stackoverflow (https://stackoverflow.com/questions/53165704/readline-c-force-return-of-certain-text-in-readline)
//   "rl_done is only checked in the event loop. When you give it a null event hook
//    function, it checks the rl_done and exits"
//
// rl_signal_event_hook
//   If non-zero, this is the address of a function to call if a read system call is
//   interrupted when Readline is reading terminal input.
static int	here_doc_write(char *delimiter, int doc_fd)
{
	char	*line;
	size_t	line_count;
	struct sigaction	signal_action;

	ft_bzero(&signal_action, sizeof(signal_action));
	signal_action.sa_handler = sigint_handler_heredoc;
	sigaction(SIGINT, &signal_action, NULL);
	g_switch_heredoc_sigint = 0;
	rl_event_hook = void_func_return_readline;
	//rl_signal_event_hook = void_func_return_readline;
	line_count = 0;
	while (1)
	{
		line_count++;
		line = NULL;
		line = readline("> ");
		if (g_switch_heredoc_sigint == 1)
			return (set_last_exit_status(EXIT_SIGNAL + SIGINT));
		if (!line)
		{ // TODO : error print wrapper
			ft_putstr_fd("minishell: ", 2);
			ft_putstr_fd("warning: here-document at line ", 2);
			ft_putnbr_fd(line_count, 2);
			ft_putstr_fd(" delimited by end-of-file (wanted `", 2);
			ft_putstr_fd(delimiter, 2);
			ft_putstr_fd("')\n", 2);
			return (-1);
		}
		if (ft_strncmp(line, delimiter, ft_strlen(line) + 1) == 0) // Ou ft_strlen(delimiter) + 1 ? Ça devrais être identique et ça peux se calculer une seul fois.
			break ;
		if (write(doc_fd, line, ft_strlen(line)) == -1)
			return (ft_reti_perror_free(-1, line, free, "write() "TMP_HERE_DOC));
		if (write(doc_fd, "\n", 1) == -1)
			return (ft_reti_perror_free(-1, line, free, "write() "TMP_HERE_DOC));
		free(line);
	}
	free(line);
	signal_action.sa_handler = SIG_IGN;
	sigaction(SIGINT, &signal_action, NULL);
	return (0);
}

/* 
static int	here_doc_write(char *delimiter, int doc_fd)
{
	char	*line;
	int		ret;

	line = NULL;
	ret = 1;
	while (ret)
	{
		ret = gnl(STDIN_FILENO, &line, 0);
		if (ret == -1)
			return (ft_reti_perror_free(0, line, free, "gnl() STDIN"));
		if (ft_strncmp(line, delimiter, ft_strlen(line) + 1) == 0) // Ou ft_strlen(delimiter) + 1 ? Ça devrais être identique et ça peux se calculer une seul fois.
			break ;
		if (write(doc_fd, line, ft_strlen(line)) == -1)
			return (ft_reti_perror_free(0, line, free, "write() "TMP_HERE_DOC));
		if (write(doc_fd, "\n", 1) == -1)
			return (ft_reti_perror_free(0, line, free, "write() "TMP_HERE_DOC));
		free(line);
		line = NULL;
	}
	free(line);
	gnl(STDIN_FILENO, NULL, 1);
	return (1);
}
 */
