/* mkisofs.c
 * Copyright (C) 2004, 2005 Sylvain Cresto <scresto@gmail.com>
 *
 * This file is part of graveman!
 *
 * graveman! 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, or
 * (at your option) any later version.
 * 
 * graveman! 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 program; see the file COPYING. If not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA. 
 * 
 * URL: http://www.nongnu.org/graveman/
 *
 */

#include "graveman.h"

/* communication avec mkisofs */

#define MKISOFS_ESTIMATE "done, estimate finish"
#define MKISOFS_ERROR "mkisofs:"
#define MKISOFS_IGNORE "-follow-links does not always"
#define MKISOFS_OK "Total translation table size"
#define MKISOFS_NOSPACE "No space left on device"
#define MKISOFS_SUPPORT_ISOV2 "Set ISO9660 conformance level (1..3) or 4 for ISO9660 version 2"
#define MKISOFS_CHARSET "Known charsets are:"

/* on verifie si le support iso9660 version 2 est disponnible ou non */
gboolean check_mkisofs()
{
  gchar *Lmkisofs = conf_get_string("mkisofs");
  gchar *Lcommandline, *Lerr = NULL;
  gboolean Lstatus;
  gint Lexit = 0;
  if (!Lmkisofs || !*Lmkisofs) return FALSE;

  Lcommandline = g_strdup_printf("%s -help", conf_get_string("mkisofs"));
  Lstatus = g_spawn_command_line_sync(Lcommandline, NULL, &Lerr, &Lexit, NULL);
  g_free(Lcommandline);

  Lstatus = (Lstatus == TRUE && Lerr && ((strstr(Lerr, MKISOFS_SUPPORT_ISOV2))));
  g_free(Lerr);

  return Lstatus;
}

/* recherche les parametres supplementaires a passer a mkisofs */
gchar *make_image_getextrapara(Tgrave *Ag, gchar *Aop)
{
  const gchar *Ldatavoli = gtk_entry_get_text(GTK_ENTRY(sc_grave_get_widgetv(Ag, "%svoli", Aop)));
  const gchar *Ldatapubl = gtk_entry_get_text(GTK_ENTRY(sc_grave_get_widgetv(Ag, "%spubl", Aop)));
  const gchar *Ldataprep = gtk_entry_get_text(GTK_ENTRY(sc_grave_get_widgetv(Ag, "%sprep", Aop)));
  const gchar *Ldatabibl = gtk_entry_get_text(GTK_ENTRY(sc_grave_get_widgetv(Ag, "%sbibl", Aop)));
  const gchar *Ldatacopy = gtk_entry_get_text(GTK_ENTRY(sc_grave_get_widgetv(Ag, "%scopy", Aop)));
  const gchar *Ldataabst = gtk_entry_get_text(GTK_ENTRY(sc_grave_get_widgetv(Ag, "%sabst", Aop)));
  gchar *Lreturn, *Linputcharset = NULL;
  gchar *Lextra = NULL;
  GtkTextIter Lstart, Lend;
  GtkTextBuffer *Lbufappi = gtk_text_view_get_buffer (GTK_TEXT_VIEW (sc_grave_get_widgetv(Ag, "%sappi", Aop)));
  char *Ldataappi, *Ltmpappi;
  gtk_text_buffer_get_bounds (Lbufappi, &Lstart, &Lend);
  Ltmpappi = gtk_text_iter_get_text (&Lstart, &Lend);
  Ldataappi = g_strescape(Ltmpappi, "");
  g_free(Ltmpappi);
  gchar *Ldevchar = NULL;

  if (!strcmp(Aop, "data")) { /* data cd */
    gboolean Lrockridge = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sc_grave_get_widget(Ag, "datarockridge")));
    gboolean Ljoliet = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sc_grave_get_widget(Ag, "datajoliet")));
    gchar *Lisolevel = get_combo_value(sc_grave_get_widget(Ag, "dataisolevel"));
    gchar *Lmediainfo = NULL;

    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sc_grave_get_widget(Ag, "datamulti")))) {
      gboolean *Luseautoblank = (gboolean *) sc_grave_get_data(Ag, "useautoblank");

      if (*Luseautoblank == FALSE) {
        Tdriveinfo *Ldevice = matos_get_drive_info(Ag, "dstdatacombo");
        if (Ldevice) {
          Ldevchar = DRIVE_DEV(Ldevice);
          Lmediainfo = cdrecord_get_mediainfo(Ag, Ldevice, NULL);
        }
      }
    }

    Lextra = g_strdup_printf("%s %s -iso-level %s %s%s %s%s", Lrockridge == TRUE ? "-r" : "", Ljoliet ? "-J" : "", Lisolevel,
        Lmediainfo ? "-C " : "", Lmediainfo ? Lmediainfo : "", Lmediainfo && Ldevchar ? "-M " : "",
        Lmediainfo && Ldevchar ? Ldevchar : "");
    g_free(Lmediainfo);
    g_free(Lisolevel);
  } else {  /* data dvd */
    Lextra = g_strdup("-r -J");
  }

  /* charsets a utiliser pour la creation de l'image iso */
  if ((Lreturn = conf_get_string("inputcharset"))) {
    Linputcharset = g_strdup_printf("-input-charset %s", Lreturn);
  }
  Lreturn = g_strdup_printf("-V \"%s\" -A \"%s\" -publisher \"%s\" -p \"%s\" -biblio \"%s\" -copyright \"%s\" "
            "-abstract \"%s\" %s %s",
            _NN(Ldatavoli), _NN(Ldataappi), _NN(Ldatapubl), _NN(Ldataprep), _NN(Ldatabibl), _NN(Ldatacopy),
            _NN(Ldataabst), Lextra, Linputcharset ? Linputcharset : "");
  g_free(Linputcharset);
  g_free(Lextra);

  return Lreturn;
}

gboolean mkisofs_makeimage_callback(GIOChannel *Astd, GIOCondition Acond, gpointer Adata)
{
  GIOStatus Lstatus;
  Tgrave *Lg = (Tgrave *)Adata;
  gint *Lcont = (gint *) sc_grave_get_data(Lg, "cont"); /* on traite encore des donnees ? */
  GError **Lerreur = (GError **) sc_grave_get_data(Lg, "gerror"); /* pointeur erreur */
  gint *Ltodo = (gint *) sc_grave_get_data(Lg, "todo"); /* nombre de piste a traiter */
  gint *Ldone = (gint *) sc_grave_get_data(Lg, "done"); /* nombre de piste deja traite */
  GtkProgressBar *Lprogressbar = GTK_PROGRESS_BAR(sc_grave_get_data(Lg, "pb_total"));
  GtkProgressBar *Lprogressbar2 = GTK_PROGRESS_BAR(sc_grave_get_data(Lg, "pb_step"));
  gchar *Lbuffer = NULL, *f, *Ltxt; 
  gdouble Lpct, Ltava;
  gchar Lsbuf[100], Lsbuf2[100];

  /* fin du callback lorsque l'on recoi un signal comme quoi le pipe est ferme */
  if (Acond == G_IO_HUP || Acond == G_IO_ERR) {
    *Lcont = 0;
    return FALSE;
  }
  Lstatus = g_io_channel_read_line(Astd, &Lbuffer, NULL, NULL, NULL);    
  if (!Lbuffer || Lstatus == G_IO_STATUS_ERROR || Lstatus == G_IO_STATUS_AGAIN) return TRUE;
_DEB("on recoi => '%s'\n", Lbuffer);

  if ((strstr(Lbuffer, MKISOFS_ESTIMATE)) && Lbuffer[3]=='.') {
    Lbuffer[3]=0;
    f=ltrim(Lbuffer);

    /* avancement tache */
    Lpct = 0.01 * atof(f);
    gtk_progress_bar_set_fraction(Lprogressbar2, Lpct);
    g_snprintf(Lsbuf, sizeof(Lsbuf)-1, "%s%%", f);
    gtk_progress_bar_set_text(Lprogressbar2, Lsbuf);
    /* avancement total */
    Ltava = (1.0 / (*Ltodo)) * ((*Ldone)-1+Lpct);
    gtk_progress_bar_set_fraction(Lprogressbar, Ltava);
    g_snprintf(Lsbuf2, sizeof(Lsbuf2)-1, "%.0f%%", Ltava*100);
    gtk_progress_bar_set_text(Lprogressbar, Lsbuf2);
  } else if ((strstr(Lbuffer, MKISOFS_ERROR)) && (!strstr(Lbuffer, MKISOFS_IGNORE))) {
    *Lcont = 0;

    if (!strstr(Lbuffer, MKISOFS_NOSPACE)) {
      Ltxt = _UTF8(Lbuffer);
    } else {
      Ltxt = g_strdup(_("Not enough free disk space to create iso image !"));
    }
    g_set_error(Lerreur, GRAVEMAN_ERROR, _ERR_MKISOFS, Ltxt);
    g_free(Ltxt);
    return FALSE;
  } else if (!strncmp(Lbuffer, MKISOFS_OK, strlen(MKISOFS_OK))) {
    gboolean *Lopstatus = (gboolean *) sc_grave_get_data(Lg, "operationstatus");
    /* ok tout s'est bien passe ! */
    gtk_progress_bar_set_fraction(Lprogressbar2, 1);
    gtk_progress_bar_set_text(Lprogressbar2, "100%");
    Ltava = (1.0 / (*Ltodo)) * (*Ldone);
    gtk_progress_bar_set_fraction(Lprogressbar, Ltava);
    g_snprintf(Lsbuf2, sizeof(Lsbuf2)-1, "%.0f%%", Ltava*100);
    gtk_progress_bar_set_text(Lprogressbar, Lsbuf2);
    *Lcont = 0;
    *Lopstatus = TRUE;
  }

  return TRUE;
}

/* creation image iso */
gboolean make_iso(Tgrave *Ag, GError **Aerror)
{
  gboolean Lstatus = FALSE;
  gchar **Lcmd;
  gchar *Lcommandline;
  GIOChannel *Lcomerr, *Lcom;
  guint Lcomerrevent, Lcomevent;
  gint *Lcont = (gint *)sc_grave_get_data(Ag, "cont");
  gboolean *Labort = (gboolean *) sc_grave_get_data(Ag, "gabort");
  gchar *Ltmpdir = (gchar *)sc_grave_get_data(Ag, "tmpdir");
  gchar *Lextrapara = (gchar *)sc_grave_get_data(Ag, "extrapara");
  gint *Lpid = (gint *) sc_grave_get_data(Ag, "pid");
  gint *Ldone = (gint *)sc_grave_get_data(Ag, "done"); /* fais */
  gchar *Liso = (gchar *)sc_grave_get_data(Ag, "iso"); /* image iso */
  gboolean *Loperationstatus = (gboolean *)sc_grave_get_data(Ag, "operationstatus");
  GtkLabel *Ltitle = GTK_LABEL(sc_grave_get_data(Ag, "gravetitle"));
  gint g_out, g_err, Lnbrarg;

  *Loperationstatus = FALSE;
  gtk_label_set_text(Ltitle, _("Writing image..."));

  Lcommandline = g_strdup_printf("%s %s %s -o %s -graft-points -path-list %s/pathlist", 
      conf_get_string("mkisofs"), Lextrapara, conf_get_string("mkisofspara"), Liso, Ltmpdir);

  _DEB("execution [%s]\n", Lcommandline);
  Lstatus = g_shell_parse_argv(Lcommandline, &Lnbrarg, &Lcmd, Aerror);
  _DEB("nbr arg [%d]\n", Lnbrarg);
  g_free(Lcommandline);
  if (Lstatus == FALSE) {
    return FALSE;
  }

  Lstatus = g_spawn_async_with_pipes(NULL, Lcmd, NULL, /* env argument */
    (GSpawnFlags ) (G_SPAWN_DO_NOT_REAP_CHILD),
     NULL, NULL, Lpid, NULL, &g_out, &g_err, Aerror);
  g_strfreev(Lcmd);

  if (Lstatus == FALSE) {
    g_warning("ERROR EXECUTION !\n");
    return FALSE;
  }

  Lcom = g_io_channel_unix_new( g_out );
  g_io_channel_set_encoding (Lcom, NULL, NULL);
  g_io_channel_set_flags( Lcom, G_IO_FLAG_NONBLOCK, NULL );
  Lcomevent = g_io_add_watch (Lcom, (G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI),
                                      mkisofs_makeimage_callback, Ag);

  Lcomerr = g_io_channel_unix_new( g_err );
  g_io_channel_set_encoding (Lcomerr, NULL, NULL);
  g_io_channel_set_flags( Lcomerr, G_IO_FLAG_NONBLOCK, NULL );
  Lcomerrevent = g_io_add_watch (Lcomerr, (G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI),
                                      mkisofs_makeimage_callback, Ag); 
_DEB("debut !!");
  while (*Lcont > 0 && *Labort == FALSE) {
   gtk_main_iteration();
  }
  exit_prog(*Lpid, *Labort, Aerror, NULL);

_DEB("fin !!");

  g_source_remove(Lcomerrevent);
  g_source_remove(Lcomevent);

  /* fermeture mkisofs */
  g_io_channel_shutdown(Lcomerr, FALSE, NULL);
  g_io_channel_unref(Lcomerr);  
  g_io_channel_shutdown(Lcom, FALSE, NULL);
  g_io_channel_unref(Lcom);
  g_spawn_close_pid(*Lpid);
  *Lpid = 0;

  if (*Aerror) {
    return FALSE;
  }

  (*Ldone)++;
  return TRUE;  
}

/* recuperation des charsets integré dans mkisofs */
gboolean get_builtin_charset(Tgrave *Ag, GError **Aerror)
{
  gchar *Lcommandline, *Lout = NULL, *Lerr = NULL;
  gboolean Lstatus = TRUE;
  gchar **Lcharsetl;
  gint Lexit = 0, i;
  gboolean Lajout = FALSE;
  gchar *Lmkisofs = conf_get_string("mkisofs");

  if (!Lmkisofs || !*Lmkisofs) return FALSE;

  Lcommandline = g_strdup_printf("%s -input-charset help", Lmkisofs);
_DEB("command [%s]", Lcommandline);
  Lstatus = g_spawn_command_line_sync(Lcommandline, &Lout, &Lerr, &Lexit, Aerror);
  g_free(Lcommandline);

  if (Lstatus == FALSE || !Lerr) {
    g_free(Lout);
    g_free(Lerr);
    return FALSE;
  }

  Lcharsetl = g_strsplit(Lerr, "\n", 0);
  g_slist_free(Gcharsetlist);
  Gcharsetlist = NULL;

  for (i=0; Lcharsetl[i] && *Lcharsetl[i]; i++) {
    if (Lajout) {
      config_append_charset(Lcharsetl[i], (gchar *)charset_code_to_label(Lcharsetl[i]));
    } else if (!strncmp(Lcharsetl[i], MKISOFS_CHARSET, strlen(MKISOFS_CHARSET))) {
      Lajout = TRUE;
    }
  } 
  
  g_strfreev(Lcharsetl);

  return TRUE;
}


/*
 * vim:et:ts=8:sts=2:sw=2
 */
