//This file is part of AcetoneISO. Copyright 2006,2007,2008,2009 Marco Di Antonio and Fabrizio Di Marco (acetoneiso@gmail.com)
//
//    AcetoneISO 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.
//
//    AcetoneISO 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 AcetoneISO.  If not, see <http://www.gnu.org/licenses/>.
#include <QtGui>
#include <QCoreApplication>
#include <QByteArray>
#include <Phonon/MediaObject>
#include <Phonon/AudioOutput>
#include <QProcess>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusMessage>
#include <QList>
#include <QVariant>
#include <fcntl.h>
#include <iostream>
#include <QDebug>
#include "erase_cd.h"


/*
cancellare cd completo: wodim -verbose dev=/dev/sr0  blank=all
cancellare cd rapido: wodim -verbose dev=/dev/sr0  blank=fast
dice il tipo di media inserito: hal-get-property "--key volume.disc.type --udi $udi
*/

//
erasecd::erasecd( QWidget * parent, Qt::WFlags f) 
	: QDialog(parent, f)
{

    setupUi(this);
    is_erasing = false;
    loaded_success = false;
    QCoreApplication::setApplicationName("AcetoneISO");
    connect( start, SIGNAL( clicked() ), this, SLOT( start_erase() ) );

    textBrowser->clear();
    device_scan();

}




void erasecd::device_scan() {


/*creo la connessione dbus a hal*/
QDBusConnection conn = QDBusConnection::systemBus();
QDBusInterface hal("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager", "org.freedesktop.Hal.Manager", conn);
/*cerco tutti i dispositivi storage.cdrom con hal via dbus*/
QDBusMessage msg = hal.call( "FindDeviceByCapability", "storage.cdrom");

QList<QVariant> devices = msg.arguments(); 
/*per ogni udi (dispositivo cdrom) che trovo, ricavo vendor, model, velocità e path*/

//disabilita tutto se non viene trovato almeno 1 periferica
int count = devices.count();
if (count < 1) {
 QMessageBox::warning(this, "AcetoneISO::warning", tr("No CD/DVD device found.\nIf you think this is a bug please report it."));
 disable_buttons();
 devices_combo->addItem( tr("No CD/DVD device found") );
 return;
}


QIcon icon_optical_drive( ":/images/drive-optical.png" );

//scannerizzo tutte le periferiche e le aggiungo nella combobox. questa funzione viene chiamato una sola volta.
QVariant name(devices);
int cc = 0;
int success = -1;
while (cc < count) {
		  QString cdrom = name.toStringList()[0]; 
		  qDebug() << "Found device: " << cdrom; 
		  QDBusInterface device("org.freedesktop.Hal", cdrom, "org.freedesktop.Hal.Device", conn);
		  
		  //vedo se effittivamente il device puo scrivere su dischi cd-rw
		  msg = device.call("GetProperty", "storage.cdrom.cdrw");
		  QVariant vcan_write_cdrw = msg.arguments()[0];
		  bool can_write_cdrw = vcan_write_cdrw.toBool();
		  if (!can_write_cdrw) {
		    cc = cc + 1;
		    continue;
		  }
		  //success si ricorda sempre la posizione in cui aggiungere all'array indipendentemente dal cc del ciclo while
		  success = success + 1;
		  //aggiungo id nell'array
		  id_device.insert(success, cdrom);		  
		  /*ottengo il nome del vendor del cdrom*/
		  msg = device.call("GetProperty", "storage.vendor");
		  QVariant var = msg.arguments()[0]; 
		  QString vendor = var.toStringList()[0];
		  qDebug() << "VENDOR" << vendor;
		  /*ottengo il nome del modello del cdrom*/
		  msg = device.call("GetProperty", "storage.model");
		  QVariant var2 = msg.arguments()[0]; 
		  QString model = var2.toStringList()[0];
		  qDebug() << "MODEL" << model;

		  /*ottengo il path del dispositivo cdrom*/
		  msg = device.call("GetProperty", "block.device");
		  QVariant var3 = msg.arguments()[0]; 
		  device_path.insert(success, var3.toStringList()[0]);
		  qDebug() << "PATH" << device_path;
		  
		  msg = device.call("GetProperty", "storage.firmware_version");
		  QVariant firmwarev = msg.arguments()[0];
		  QString firmware = firmwarev.toString();
		   /*aggiungo il nome del device nella combobox*/
		  QString final_device = vendor.append( "\t" + model + " " + firmware );
		  devices_combo->insertItem(success,icon_optical_drive, " " + final_device );
		  
		  cc = cc + 1;
		  }

media_available();
//if < 1 significa che sebbene ci sono 1 o piu periferiche cdrom, nessuna e' capace di scrivere su cd-rw
if (devices_combo->count() < 1) {
disable_buttons();
QMessageBox::warning(this, "AcetoneISO::warning", tr("No CD/DVD device found capable of writing to CD-RW discs.\nIf you think this is a bug please report it."));
return; 
}
else { //c'e' almeno 1 periferica cdrom in grado di scrivere su dischi cd-rw
loaded_success = true;
//crea un timer cosi aggiorna automaticamente la label_info
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(media_available()));
timer->start(2000);
connect( devices_combo, SIGNAL(currentIndexChanged(int) ), this , SLOT( combo_changed(int) ) ); 
}

}


void erasecd::media_available() {
//qDebug() << "media_available()";
//se sto masterizzando deve uscire da qui
if (is_erasing) {
start->setEnabled(false);
label_info->setText(tr("The CD-RW is getting blanked..."));
return;
}

//if < 1 it means there are no devices capaci di scrivere su dischi cd-rw
if (devices_combo->count() < 1) {
return; 
}

//se non e' visibile deve disconnettere le connessioni
if (loaded_success) {
  if (!devices_combo->isVisible()) {
    disconnect(devices_combo, 0, 0, 0);
    disconnect(timer, 0, 0, 0);
    loaded_success = false;
  }
}
//scopro se ho un cd dentro il device
/*creo la connessione dbus a hal*/
QDBusConnection conn = QDBusConnection::systemBus();
QDBusMessage msg;
//prendo indice corrente della combobox cosi so chi l'id della periferica selezionata
int current_index = devices_combo->currentIndex();
QString id = id_device[current_index];

//mi connetto alla periferica corrente selezionata in combobox
QDBusInterface device("org.freedesktop.Hal", id, "org.freedesktop.Hal.Device", conn);
//vedo se e' inserito un cd 
msg = device.call("GetProperty", "storage.removable.media_available");
QVariant var5 = msg.arguments()[0];
bool opticDev = var5.toBool();
if (!opticDev) {
  label_info->setText(tr("Insert a CD-RW disc."));
  start->setEnabled(false);
  //devices_combo->setItemText(cc,tr("No Media Inserted, insert a media and click on refresh button."));
  return;
}

//vedo il tipo di cd inserito
QDBusMessage fbp;
QDBusInterface newh("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager", "org.freedesktop.Hal.Manager", conn);
fbp = newh.call("FindDeviceStringMatch", "info.parent", id);
QList<QVariant> var6 = fbp.arguments();
QString disc_type = var6.at(0).toString();
QDBusInterface device_type("org.freedesktop.Hal", disc_type, "org.freedesktop.Hal.Device", conn);
msg = device_type.call("GetProperty", "volume.disc.type");
QString var7 = msg.arguments()[0].toString();
QString disc_is = var7;
//ferma in caso che il disco inserito non sia un disco CD-RW
if (disc_is != "cd_rw") {
label_info->setText(tr("The disc isn't a CD-RW. Please insert a CD-RW disc."));
start->setEnabled(false); 
return;
}

label_info->setText(tr("CD-RW succesfully found in device."));
start->setEnabled(true);


}

//gestisce quando l'utente cambia periferica nella combobox
void erasecd::combo_changed(int n) {
int a;
a = n;
media_available();
}


void erasecd::start_erase() {
QMessageBox msgBox;
msgBox.setText(tr("You decided to blank the CD-RW.\nAre you sure?"));
 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
 switch (msgBox.exec()) {
 case QMessageBox::Yes:
    {
      //continue below
     }
     break;
 case QMessageBox::No:
 {
  return; //exit
 }
     break;
 default:
     // should never be reached
     break;
 }

QString erase_type;
if (radioButton->isChecked()) {
erase_type = "blank=all";
}
else {
erase_type = "blank=fast";
}


disable_buttons();
QString dev = device_path.at(devices_combo->currentIndex());

dev = dev.prepend("dev=");
textBrowser->clear(); 
erase = new QProcess();
erase->setReadChannel(QProcess::StandardOutput);
erase->setProcessChannelMode(QProcess::MergedChannels);	
//connection to update the display
connect(erase, SIGNAL(readyReadStandardOutput()), SLOT(updateEraseDisplay() )); 
connect(erase, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(printOutErase(int, QProcess::ExitStatus)));
QDir bin("/usr/bin");
QDir::setCurrent( bin.absolutePath() );
is_erasing = true;
if (eject->isChecked()) {
erase->start("wodim",QStringList()  << "-verbose" << dev <<  erase_type << "-eject" );
}
else {
erase->start("wodim",QStringList()  << "-verbose" << dev <<  erase_type );
}

}

//fa loutput nel display del processo wodim
void erasecd::updateEraseDisplay() {
erase_output = erase->readAllStandardOutput(); 
textBrowser->setPlainText(erase_output);   
}
//gestisce quando il processo wodim finisce
void erasecd::printOutErase(int, QProcess::ExitStatus) {
enable_buttons();
is_erasing = false;
int valore_uscita = erase->exitCode();
if(valore_uscita == 0) {
  if (playcheckbox->isChecked()) {
    play_success();
  }
  QMessageBox::information(this, "AcetoneISO",tr("Process Succesfully Finished!"));
}
else {
  if (playcheckbox->isChecked()) {
    play_error();
  }
  QMessageBox::critical(this, "AcetoneISO","Process Error Code: " + QString::number(valore_uscita) );
}
}

//abilita i bottoni
void erasecd::enable_buttons() { 
start->setEnabled(true);
devices_combo->setEnabled(true);
eject->setEnabled(true);
radioButton->setEnabled(true);
radioButton_2->setEnabled(true);
playcheckbox->setEnabled(true);
}
//disabilita i bottoni
void erasecd::disable_buttons() {
start->setEnabled(false);
devices_combo->setEnabled(false);
eject->setEnabled(false);
radioButton->setEnabled(false);
radioButton_2->setEnabled(false); 
playcheckbox->setEnabled(false);
}


void erasecd::play_success() {
Phonon::MediaObject *mediaObject;	
Phonon::AudioOutput *audioOutput; 
Phonon::Path path;
mediaObject = new Phonon::MediaObject();
audioOutput = new Phonon::AudioOutput(Phonon::NoCategory);
path = Phonon::createPath(mediaObject, audioOutput);
QString file(":/audio/success.ogg");
mediaObject->setCurrentSource(Phonon::MediaSource(file));
mediaObject->play();
}

void erasecd::play_error() {
Phonon::MediaObject *mediaObject;	
Phonon::AudioOutput *audioOutput; 
Phonon::Path path;
mediaObject = new Phonon::MediaObject();
audioOutput = new Phonon::AudioOutput(Phonon::NoCategory);
path = Phonon::createPath(mediaObject, audioOutput);
QString file(":/audio/error.ogg");
mediaObject->setCurrentSource(Phonon::MediaSource(file));
mediaObject->play();
}



