/** -*- Mode: C++; tab-width: 4 -*-
 * vim: sw=4:ts=4:
 *
 * Gnome Apt package installation handler
 *
 * 	(C) 1998 Havoc Pennington <hp@pobox.com>
 * 	    2002, 2003 Filip Van Raemdonck <mechanix@debian.org>
 *
 * 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 2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 * 	$Id$
 *
 **/

using namespace std;

#include <iostream> 
#include <stdio.h>
#include <unistd.h>
#include <gtk/gtk.h>

#ifndef HAS_I18N
#define HAS_I18N
#endif
#include <libzvt/libzvt.h>

#include "childprocess.h"
#include "gnome-apt.h"

void 
ChildDialog::child_died_cb(GtkWidget* w, gpointer data)
{
  ChildDialog* cd = static_cast<ChildDialog*>(data);
  
  cd->child_died();
}

void 
ChildDialog::child_died()
{
  child_done_ = true;

  
}

gint 
ChildDialog::close_cb(GtkWidget* w, gpointer data)
{
  ChildDialog* cd = static_cast<ChildDialog*>(data);
  
  return cd->close();
}

gint 
ChildDialog::close()
{
  if (child_done_) return FALSE; 

	GtkWidget* dialog = gtk_message_dialog_new (
		NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
		_("The child process is still running. Do you want to kill it?\n"
			"If you do, you'll have to restart Gnome Apt."));
	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_NO);
  gnome_apt_setup_dialog(dialog);
	gint response = gtk_dialog_run (GTK_DIALOG (dialog));
	gtk_widget_destroy (dialog);
	if (response == GTK_RESPONSE_YES) {
    close_anyway_ = true;
    return FALSE;
	} else {
		if (response != GTK_RESPONSE_NO) {
			g_warning ("Got response: %d", response);
		}
  }

  return TRUE; // block the close
}

ChildDialog::ChildDialog(const char* title,
                         const char* label)
  : we_are_parent_(false), child_done_(false), close_anyway_(false)
{
	dialog_ = gtk_dialog_new_with_buttons (
		title, NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
		GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
	gnome_apt_setup_dialog (dialog_);
	g_signal_connect (G_OBJECT (dialog_), "close", G_CALLBACK (close_cb), this);

	label_ = gtk_label_new (label);
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_)->vbox),
		label_, FALSE, FALSE, 0);

	term_ = zvt_term_new();
	gtk_widget_set_size_request (GTK_WIDGET (term_),
	      (ZVT_TERM (term_)->grid_width * ZVT_TERM (term_)->charwidth)
	            + 2 /*padding*/ + (GTK_WIDGET (term_)->style->xthickness * 2),
	      (ZVT_TERM (term_)->grid_height * ZVT_TERM (term_)->charheight)
	            + 2 /*padding*/ + (GTK_WIDGET (term_)->style->ythickness * 2));
	g_signal_connect (G_OBJECT (term_), "child_died", G_CALLBACK (child_died_cb), this);

  zvt_term_set_scrollback(ZVT_TERM(term_), 10000);

  zvt_term_set_scroll_on_keystroke (ZVT_TERM(term_), TRUE);
  zvt_term_set_scroll_on_output (ZVT_TERM(term_), TRUE);

  gtk_widget_queue_draw (GTK_WIDGET (term_));

  GtkWidget* scrollbar = 
    gtk_vscrollbar_new (GTK_ADJUSTMENT (ZVT_TERM(term_)->adjustment));
  GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS);

  GtkWidget* hbox = gtk_hbox_new(FALSE,0);

  gtk_box_pack_start(GTK_BOX(hbox), term_, 
                     TRUE, TRUE, 0);
  gtk_box_pack_end(GTK_BOX(hbox), scrollbar,
                   FALSE, FALSE, 0);

	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_)->vbox),
		hbox, TRUE, TRUE, 0);

  gtk_widget_realize(term_);
  gtk_widget_realize(dialog_);

  gtk_widget_show_all(dialog_);

  while (gtk_events_pending())
    gtk_main_iteration();

  gtk_widget_show_now(dialog_);

  while (gtk_events_pending())
    gtk_main_iteration();
}

ChildDialog::~ChildDialog()
{
  if (we_are_parent_)
    {
      if (dialog_) gtk_widget_destroy(dialog_);
    }
}

int
ChildDialog::fork()
{
  // The ZvtTerm *must* get a size_allocate before the 
  //  child starts sending output, or it will 
  //  insert line breaks in the wrong place.
  gtk_widget_show_now(dialog_);

  // make sure we are all synced up here. weirdo paranoia.
  cout << flush;
  cerr << flush;
  fflush(stdout);
  fflush(stderr);

  int retval = zvt_term_forkpty (ZVT_TERM(term_), FALSE); // FALSE == no utmp
  switch (retval) {
  case -1:
    perror ("Error: unable to fork");
    break;
  case 0: 
    {
      we_are_parent_ = false;
      // touching the GUI == flaming death in the child
      dialog_ = 0;
      term_ = 0;
      label_ = 0;
      // Close all file descriptors but first 3 - total paranoia kludge
      int open_max = sysconf (_SC_OPEN_MAX);
      for (int i = 3; i < open_max; i++){
        ::close (i);
      }
    }
    break;
  default:
    we_are_parent_ = true;
    break;
  }

  return retval;
}


bool 
ChildDialog::run()
{
  g_return_val_if_fail(we_are_parent_, false);

  while (child_done_ == false)
    {
		int reply = gtk_dialog_run (GTK_DIALOG (dialog_));
      if (close_anyway_) break;
    }

  gtk_widget_destroy(dialog_);

	dialog_ = NULL;

  // for now, we just return true
  return true;
}

