/* GAdmin-Rsync - An easy to use GTK+ frontend for the rsync backup client and server.
 * Copyright (C) 2007-2011 Magnus Loef <magnus-swe@telia.com> 
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
*/


#include "../config.h"
#include <gtk/gtk.h>
#include "gettext.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "allocate.h"
#include "widgets.h"
#include "commands.h"
#include "show_info.h"
#include "backup_and_restore.h"
#include "cron_functions.h"

extern gchar *global_backup_name;
extern int client_active;
gint child_pid;


void cancel_process_clicked(struct w *widgets)
{
    gchar *cmd;

    /* Set by status_update() */
    if( ! client_active )
      return;

    /* Kill all rsync processes (This is not optimal) */
    cmd = g_strdup_printf("killall -9 rsync");
    if( ! run_command(cmd) )
    {
	printf("Error: Can not kill the process.\n");
    }
    g_free(cmd);
}


void backup_button_clicked(struct w *widgets)
{
    char *script_path, *cmd;
    gchar *utf8=NULL, *info;
    GtkTextBuffer *text_buffer;

    /* Set by status_update() */
    if( client_active )
      return;

    script_path = mk_backup_script_path(global_backup_name);
    if( script_path == NULL || strlen(script_path) < 1 )
    {
	info = g_strdup_printf(_("The backup has no backup script.\nYou need to add a backup first.\n"));
	show_info(info);
	g_free(info);

	if( script_path!=NULL )
	  g_free(script_path);
	return;
    }

    /* Return if the backup script doesnt exist */
    if( ! file_exists(script_path) )
    {
	info = g_strdup_printf(_("Error: Backup script doesnt exist.\n"));
	show_info(info);
	g_free(info);

	g_free(script_path);
	return;
    }

    /* Switch to the notebooks progress tab */
    gtk_notebook_set_current_page(GTK_NOTEBOOK(widgets->main_notebook), 1);

    /* Clear the progress textview and set informational text */
    info = g_strdup_printf("\nBackup operation starting, please wait...\n\n");
    utf8 = g_locale_to_utf8(info, strlen(info), NULL, NULL, NULL);
    text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widgets->progress_textview));
    gtk_text_buffer_set_text(text_buffer, utf8, -1);
    if( utf8!=NULL )
      g_free(utf8);

    g_free(info);

    /* Setup the command to show output for */
    cmd = g_strdup_printf("%s", script_path);

    /* Run the command */
    run_process_command(widgets, cmd);

    g_free(cmd);
}


void run_process_command(struct w *widgets, gchar *cmd)
{
    gint standard_output, standard_error;
    gint ret, argc;
    gchar **argv;

    /* Add the command to argv */
    g_shell_parse_argv(cmd, &argc, &argv, NULL);

    /* Spawn the command */
    if( g_spawn_async_with_pipes(NULL,
		        	 argv,
		    		 NULL,
		  G_SPAWN_SEARCH_PATH,
				 NULL,
	    		         NULL,
		    	   &child_pid,
		   // &standard_input,
				 NULL,
		     &standard_output,
		      &standard_error,
				 NULL) )
    {
	/* Read standard output and insert in progress textview */
	GIOChannel *output_channel = g_io_channel_unix_new(standard_output);
	/* Accept binary, allow no buffering */
	g_io_channel_set_encoding(output_channel, NULL, NULL);
	/* Dont block, allowing gui redraws */
	g_io_channel_set_flags(output_channel, G_IO_FLAG_NONBLOCK, NULL);
	/* Poll and dispatch the output */
	ret = g_io_add_watch(output_channel,
		G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
		    (GIOFunc)read_process_output, widgets);
	if( ! ret )
	  printf("Error: Can not add a watch for the output channel.\n");

	g_io_channel_unref(output_channel);

	/* Read standard error and insert in progress textview */
	GIOChannel *error_channel = g_io_channel_unix_new(standard_error);
	/* Accept binary, allow no buffering */
	g_io_channel_set_encoding(error_channel, NULL, NULL);
	/* Dont block, allowing gui redraws */
	g_io_channel_set_flags(error_channel, G_IO_FLAG_NONBLOCK, NULL);
	/* Poll and dispatch the output */
	ret = g_io_add_watch(error_channel, 
		G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
		     (GIOFunc)read_process_error, widgets);
	if( ! ret )
	  printf("Error: Can not add a watch for the error channel.\n");

	g_io_channel_unref(error_channel);

	g_spawn_close_pid(child_pid);
    }
    g_strfreev(argv);
}



gboolean read_process_output(GIOChannel *channel, GIOCondition condition, struct w *widgets)
{
    GIOStatus status;
    GError *error = NULL;
    gchar *line;
    gsize count = 1;
    gsize len;

    /* Allocate 1 byte to hold our input */
    line = g_strdup_printf("A");

    status = g_io_channel_read_chars(channel, line, count, &len, &error);

    if( status!=G_IO_STATUS_NORMAL || line==NULL || error!=NULL )
    {
	if( error )
          g_error("Error reading %s\n", error->message);

	if( channel!=NULL )
	  g_io_channel_shutdown(channel, TRUE, NULL);

	channel = NULL;

	if( line!=NULL )
          g_free(line);

	return FALSE;
    }

    /* Show the progress */
    show_progress(line, widgets);

    if( line!=NULL )
      g_free(line);

    return TRUE;
}


gboolean read_process_error(GIOChannel *channel, GIOCondition condition, struct w *widgets)
{
    GIOStatus status;
    GError *error = NULL;
    gchar *line;
    gsize len;

    status = g_io_channel_read_line(channel, &line, &len, NULL, &error);

    if( status!=G_IO_STATUS_NORMAL || line==NULL || error!=NULL )
    {
	if( error )
          g_error("Error reading %s\n", error->message);

	if( channel!=NULL )
	  g_io_channel_shutdown(channel, TRUE, NULL);

	channel = NULL;

	if( line!=NULL )
          g_free(line);

	return FALSE;
    }

    /* Show the progress */
    show_progress(line, widgets);

    if( line!=NULL )
      g_free(line);

    return TRUE;
}


/* Shows progress output in the textview */
void show_progress(gchar *line, struct w *widgets)
{
    gchar *utf8 = NULL;
    GtkTextIter iter;
    GtkTextMark *mark = NULL;
    gchar *mark_name = NULL;
    GtkTextBuffer *text_buffer = NULL;

    /* Get the textbuffer associated with the progress textview */
    text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widgets->progress_textview));

    /* Insert progress text if any */
    utf8 = g_locale_to_utf8(line, strlen(line), NULL, NULL, NULL);
    if( utf8!=NULL )
    {
        /* Get the end iter from the buffer */
        gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(text_buffer), &iter);

        /* Append data to the textview at the location specified by iter */
	gtk_text_buffer_insert(text_buffer, &iter, utf8, -1);

	/* Get the end iter from the buffer */
	gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(text_buffer), &iter);
	
	/* Create a mark at the end of the buffer specified by iter */
	mark = gtk_text_buffer_create_mark(GTK_TEXT_BUFFER(text_buffer), mark_name, &iter, FALSE);
	
	/* Move the mark to the bottom of the textview then scroll to it */
	gtk_text_view_move_mark_onscreen(GTK_TEXT_VIEW(widgets->progress_textview), mark);
	gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(widgets->progress_textview), mark, 0.4, TRUE, 0.0, 0.0);

	/* Delete the mark */
	gtk_text_buffer_delete_mark(GTK_TEXT_BUFFER(text_buffer), mark);

	g_free(utf8);
    }
}
