/*
Copyright (c) 2010 by Drake Justice <djustice.kde@gmail.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 2 of the License, or
(at your option) any later version.
*/

#include <QApplication>
#include <QCursor>
#include <QDebug>
#include <QFont>
#include <QGraphicsGridLayout>
#include <QGraphicsLinearLayout>
#include <QGraphicsSceneHoverEvent>
#include <QMessageBox>
#include <QPainter>
#include <QProcess>
#include <QSizePolicy>
#include <QStyleOptionGraphicsItem>
#include <QTimer>
#include <QTreeView>

#include <KColorScheme>
#include <KComboBox>
#include <KConfigDialog>
#include <KFileDialog>
#include <KGlobalSettings>
#include <KIcon>
#include <KPushButton>
#include <KSharedConfig>
#include <KStandardDirs>
#include <KUrl>
#include <kworkspace/kworkspace.h>

#include <solid/block.h>
#include <solid/device.h>
#include <solid/devicenotifier.h>
#include <solid/deviceinterface.h>
#include <solid/opticaldrive.h>
#include <solid/opticaldisc.h>

#include <Plasma/Animator>
#include <Plasma/CheckBox>
#include <Plasma/ComboBox>
#include <Plasma/Extender>
#include <Plasma/ExtenderItem>
#include <Plasma/IconWidget>
#include <Plasma/Label>
#include <Plasma/Meter>
#include <Plasma/PopupApplet>
#include <Plasma/PushButton>
#include <Plasma/Separator>
#include <Plasma/Svg>
#include <Plasma/Theme>
#include <Plasma/ToolTipManager>
#include <Plasma/TreeView>

#include "discburner.h"

#include "audiofile.h"

#include "backupthread.h"
#include "burnaudioimagethread.h"
#include "burndataimagethread.h"
#include "burnimagethread.h"
#include "convertthread.h"
#include "copythread.h"
#include "formatthread.h"
#include "ripthread.h"

DiscBurner::DiscBurner(QObject *parent, const QVariantList &args)
        : Plasma::PopupApplet(parent, args)
{
    m_extenderLayout = 0;
    m_actionsLayout = 0;
    m_discLabelLayout = 0;
    m_appletLayout = 0;
    m_extenderApplet = 0;
    m_createButton = 0;
    m_burnButton = 0;
    m_backupButton = 0;
    m_copyButton = 0;
    m_ripButton = 0;
    m_formatButton = 0;
    m_closeProjectButton = 0;
    m_meter = 0;
    m_projectMeter = 0;
    m_tree = 0;
    m_jobMaximum = 0;
    m_jobProgress = 0;
    m_currentProjectSize = 0;
    m_trackDuplicateCount = 0;
    m_isHovered = false;
    m_isBusy = false;
    m_firstRun = true;
    m_wasCancelled = false;
    m_cancelVisible = false;
    m_ejectVisible = true;
    m_stopDropping = false;
    m_hasAudioProjectLoaded = false;
    m_hasMP3ProjectLoaded = false;
    m_hasMixedModeProjectLoaded = false;
    m_hasDataCDProjectLoaded = false;
    m_hasDataDVDProjectLoaded = false;
    m_hasVideoCDProjectLoaded = false;
    m_hasVideoDVDProjectLoaded = false;

    m_firstDroppedUrl = QUrl();

    m_newImageMenu = new QMenu(this->widget());
    m_ripToMenu = new QMenu(this->widget());

    m_newAudioCDImageAction = new KAction(KIcon("media-optical-audio"), i18n("New Audio CD..."), this);
    m_newMP3CDImageAction = new KAction(KIcon("media-optical-audio"), i18n("New MP3 CD..."), this);
    m_newDataCDImageAction = new KAction(KIcon("media-optical"), i18n("New Data CD..."), this);
    m_newVideoCDImageAction = new KAction(KIcon("media-optical-video"), i18n("New Video CD..."), this);
    m_newDataDVDImageAction = new KAction(KIcon("media-optical-DVD"), i18n("New Data DVD..."), this);
    m_newVideoDVDImageAction = new KAction(KIcon("media-optical-video"), i18n("New Video DVD..."), this);
    m_newMixedModeImageAction = new KAction(KIcon("media-optical-audio"), i18n("New Mixed Mode CD..."), this);

    m_ripToMp3Action = new KAction(KIcon("media-optical-audio"), i18n("Rip to mp3s..."), this);
    m_ripToOggAction = new KAction(KIcon("media-optical-audio"), i18n("Rip to oggs..."), this);
    m_ripToWavAction = new KAction(KIcon("media-optical-audio"), i18n("Rip to wavs..."), this);

    m_discIcon = new Plasma::Svg(this);
    m_discIcon->setImagePath("discburner/k3b");
    m_isEmbedded = false;

    setAcceptsHoverEvents(true);
    setAcceptDrops(true);
    setHasConfigurationInterface(true);
    setPopupIcon(QIcon());
    setAspectRatioMode(Plasma::ConstrainedSquare);
    setBackgroundHints(NoBackground);
    setStatus(Plasma::ActiveStatus);

    resize(150, 150);
}

void DiscBurner::init()
{
    KConfigGroup cg = config();
    m_showOverlayLabel = cg.readEntry("showDropLabel", true);

    m_discIcon->resize(contentsRect().size());

    readColors();
    setActionState(Idle);
    setInteractionState(Waiting);

    m_appletLayout = new QGraphicsGridLayout(this);

    m_ejectButton = new Plasma::IconWidget;
    m_ejectButton->setIcon("media-eject");
    m_ejectButton->setOpacity(0.85);
    m_ejectButton->setVisible(false);
    m_ejectButton->setMaximumSize(QSize(42,42));
    m_ejectButton->setToolTip(i18n("Eject disc"));

    m_cancelButton = new Plasma::IconWidget;
    m_cancelButton->setIcon("dialog-cancel");
    m_cancelButton->setOpacity(0.85);
    m_cancelButton->setVisible(false);
    m_cancelButton->setMaximumSize(QSize(42,42));

    m_overlayLabel = new Plasma::Label;
    m_overlayLabel->setText("Drop!");
    m_overlayLabel->setOpacity(0);
    m_overlayLabel->setAlignment(Qt::AlignCenter);
    m_overlayLabel->setAcceptedMouseButtons(Qt::NoButton);
    m_overlayLabel->setStyleSheet("color: " + m_textColor.name().toLower());

    m_meter = new Plasma::Meter;
    m_meter->setVisible(false);
    m_meter->setMeterType(Plasma::Meter::BarMeterVertical);
    m_meter->setMaximumWidth(32);
    m_meter->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);

    m_busyWidget = new Plasma::BusyWidget;
    m_busyWidget->setVisible(false);
    m_busyWidget->setRunning(true);
    m_busyWidget->setMaximumSize(QSize(42,42));
    m_busyWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);

    m_appletLayout->addItem(m_ejectButton, 0, 2);
    m_appletLayout->addItem(m_busyWidget, 0, 0);
    m_appletLayout->addItem(m_meter, 1, 0, 2, 1);
    m_appletLayout->addItem(m_overlayLabel, 1, 1);
    m_appletLayout->addItem(m_cancelButton, 2, 2);
    m_appletLayout->setColumnAlignment(0, Qt::AlignRight);
    m_appletLayout->setColumnAlignment(1, Qt::AlignCenter);
    m_appletLayout->setColumnAlignment(2, Qt::AlignLeft);
    m_appletLayout->setRowAlignment(0, Qt::AlignCenter);
    m_appletLayout->setRowAlignment(1, Qt::AlignCenter);
    m_appletLayout->setRowAlignment(2, Qt::AlignCenter);

    m_overlayLabelAnimation = Plasma::Animator::create(Plasma::Animator::FadeAnimation);
    m_overlayLabelAnimation->setProperty("startOpacity", 0.0);
    m_overlayLabelAnimation->setProperty("targetOpacity", 1.0);
    m_overlayLabelAnimation->setTargetWidget(m_overlayLabel);

    m_ejectButtonAnimation = Plasma::Animator::create(Plasma::Animator::FadeAnimation);
    m_ejectButtonAnimation->setProperty("startOpacity", 0.0);
    m_ejectButtonAnimation->setProperty("targetOpacity", 1.0);
    m_ejectButtonAnimation->setTargetWidget(m_ejectButton);

    m_newImageMenu->addAction(m_newAudioCDImageAction);
    m_newImageMenu->addAction(m_newMP3CDImageAction);
//     m_newImageMenu->addAction(m_newMixedModeImageAction);
//     m_newImageMenu->addAction(m_newVideoCDImageAction);
//     m_newImageMenu->addAction(m_newVideoDVDImageAction);
    m_newImageMenu->addAction(m_newDataCDImageAction);
    m_newImageMenu->addAction(m_newDataDVDImageAction);
    m_ripToMenu->addAction(m_ripToMp3Action);
    m_ripToMenu->addAction(m_ripToOggAction);
    m_ripToMenu->addAction(m_ripToWavAction);

    connect(m_newAudioCDImageAction, SIGNAL(triggered()), this, SLOT(on_newAudioCDImage_clicked()));
    connect(m_newMP3CDImageAction, SIGNAL(triggered()), this, SLOT(on_newMP3CDImage_clicked()));
    connect(m_newMixedModeImageAction, SIGNAL(triggered()), this, SLOT(on_newMixedModeImage_clicked()));
    connect(m_newVideoCDImageAction, SIGNAL(triggered()), this, SLOT(on_newVideoCDImage_clicked()));
    connect(m_newVideoDVDImageAction, SIGNAL(triggered()), this, SLOT(on_newVideoDVDImage_clicked()));
    connect(m_newDataCDImageAction, SIGNAL(triggered()), this, SLOT(on_newDataCDImage_clicked()));
    connect(m_newDataDVDImageAction, SIGNAL(triggered()), this, SLOT(on_newDataDVDImage_clicked()));
    connect(m_ripToMp3Action, SIGNAL(triggered()), this, SLOT(ripDiscToMp3())); //
    connect(m_ripToOggAction, SIGNAL(triggered()), this, SLOT(ripDiscToOgg())); // -_-
    connect(m_ripToWavAction, SIGNAL(triggered()), this, SLOT(ripDiscToWav())); //

    connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(readColors()));
    connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), SLOT(readColors()));
    connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceAdded(const QString&)), this, SLOT(updateDrives()));
    connect(Solid::DeviceNotifier::instance(), SIGNAL(deviceRemoved(const QString&)), this, SLOT(updateDrives(const QString&)));

    connect(m_ejectButton, SIGNAL(clicked()), this, SLOT(on_ejectButton_clicked()));
    connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(on_cancelButton_clicked()));

    Plasma::ToolTipManager::self()->registerWidget(this);
    Plasma::ToolTipManager::self()->setContent(this, *m_toolTipData);

    if (!m_isEmbedded && !extender()->hasItem("discburnerlist")) {
        Plasma::ExtenderItem *eItem = new Plasma::ExtenderItem(extender());
        eItem->setName("discburnerlist");
        eItem->setAcceptDrops(false);
        extender()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        initExtenderItem(eItem);
    }

    updateConstraints(Plasma::StartupCompletedConstraint);
    update();
}

void DiscBurner::paintInterface(QPainter *p, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
{
    Q_UNUSED( option );

    m_discIcon->paint(p, contentsRect);
}

void DiscBurner::constraintsEvent(Plasma::Constraints constraints)
{
    if (constraints & (Plasma::FormFactorConstraint | Plasma::SizeConstraint)) {
        m_discIcon->resize(contentsRect().size().toSize());

        if(contentsRect().size().width() < 75) {
            m_overlayLabel->setVisible(false);
        } else if (contentsRect().size().width() > 230) {
            m_overlayLabel->setVisible(false);
        } else if (contentsRect().size().height() < 25) {
            m_overlayLabel->setVisible(false);
        } else if (contentsRect().size().height() > 230) {
            m_overlayLabel->setVisible(false);
        } else {
            m_overlayLabel->setVisible(true);
        }

        update();
    }
}

void DiscBurner::readColors()
{
    m_textColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
}

void DiscBurner::showOverlayLabel(bool show)
{
    if (show) {
        m_overlayLabelAnimation->setDirection(QAbstractAnimation::Forward);
        m_overlayLabelAnimation->start();
        m_ejectButtonAnimation->setDirection(QAbstractAnimation::Forward);
        m_ejectButtonAnimation->start();
    } else {
        m_overlayLabelAnimation->setDirection(QAbstractAnimation::Backward);
        m_overlayLabelAnimation->start();
        m_ejectButtonAnimation->setDirection(QAbstractAnimation::Backward);
        m_ejectButtonAnimation->start();
    }
}

void DiscBurner::setEmbedded(const bool embedded)
{
    m_isEmbedded = embedded;
}

void DiscBurner::setInteractionState(InteractionState state)
{
    m_interactionState = state;
}

void DiscBurner::setActionState(ActionState state)
{
    m_toolTipData = new Plasma::ToolTipContent();
    m_toolTipData->setAutohide(true);
    m_toolTipData->setMainText("DiscBurner");

    if (!m_toolTipData)
        return;

    switch (state ) {
    case Unset:
        m_toolTipData->setSubText(i18n("Drop files"));
        m_toolTipData->setImage(KIcon("media-optical-recordable"));
        break;
    case Idle:
        m_isBusy = false;
        m_toolTipData->setSubText(i18n("Drop files"));
        m_toolTipData->setImage(KIcon("media-optical-recordable"));
        break;
    case IdleError:
        setBusy(false);
        m_toolTipData->setSubText(i18n("Error."));
        m_toolTipData->setImage(KIcon("dialog-cancel"));
        QTimer::singleShot(10000, this, SLOT(resetActionState()));
        break;
    case IdleSuccess:
        setBusy(false);
        if (m_wasCancelled) {
            m_toolTipData->setSubText(i18n("Canceled"));
        } else {
            m_toolTipData->setSubText(i18n("Success"));
        }
        m_toolTipData->setImage(KIcon("dialog-ok"));
        QTimer::singleShot(10000, this, SLOT(resetActionState()));
        break;
    case Burning:
        setBusy(true);
        m_toolTipData->setSubText(i18n("Burning..."));
        m_toolTipData->setImage(KIcon("tools-media-optical-burn"));
        break;
    case Formatting:
        setBusy(true);
        m_toolTipData->setSubText(i18n("Formatting..."));
        m_toolTipData->setImage(KIcon("tools-media-optical-erase"));
        break;
    case Reading:
        setBusy(true);
        m_toolTipData->setSubText(i18n("Reading..."));
        m_toolTipData->setImage(KIcon("tools-media-optical-burn-image"));
        break;
    case Converting:
        setBusy(true);
        m_toolTipData->setSubText(i18n("Converting..."));
        m_toolTipData->setImage(KIcon("tools-wizard")); // fix meh
        break;
    default:
        break;
    }

    Plasma::ToolTipManager::self()->setContent(this, *m_toolTipData);
    m_actionState = state;
    update();
}

void DiscBurner::createConfigurationInterface(KConfigDialog *parent)
{
    QWidget *widget = new QWidget(parent);
    ui.setupUi(widget);
    parent->addPage(widget, i18n("General"), Applet::icon());
    connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
    connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
    ui.showDropLabelCheckBox->setChecked(m_showOverlayLabel ? Qt::Checked : Qt::Unchecked);
}

void DiscBurner::configAccepted()
{
    KConfigGroup cg = config();

    if (m_showOverlayLabel != ui.showDropLabelCheckBox->isChecked()) {
        m_showOverlayLabel = !m_showOverlayLabel;
        cg.writeEntry("showDropLabel", m_showOverlayLabel);
        if (m_showOverlayLabel && m_showOverlayLabel == ui.showDropLabelCheckBox->isChecked()) {
            showOverlayLabel(m_showOverlayLabel);
        }
    }

    emit configNeedsSaving();
}

void DiscBurner::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
    Q_UNUSED(event);
    setInteractionState(Hovered);
    showOverlayLabel(true);
    m_isHovered = true;
    if (m_ejectVisible)
        m_ejectButton->setVisible(true);

    if (m_cancelVisible)
        m_cancelButton->setVisible(true);

//    Plasma::Applet::hoverEnterEvent(event);
}

void DiscBurner::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
    Q_UNUSED(event);
    setInteractionState(Waiting);
    showOverlayLabel(false);
    m_isHovered = false;
    m_ejectButton->setVisible(false);
    m_cancelButton->setVisible(false);
//    Plasma::Applet::hoverLeaveEvent(event);
}

DiscBurner::~DiscBurner()
{

}

void DiscBurner::setBusy(bool busy)
{
    if(busy) {
        m_overlayLabel->setText(i18n("Busy..."));
    } else {
        m_overlayLabel->setText(i18n("Drop!"));
    }

    m_isBusy = busy;
}

void DiscBurner::initExtenderItem(Plasma::ExtenderItem *item)
{
    if (!m_isEmbedded && item->name() == "discburnerlist") {
        QGraphicsWidget *burnlist = new QGraphicsWidget(item);
        burnlist->setMinimumSize(350, 300);
        burnlist->setAcceptDrops(false);

        m_extenderLayout = new QGraphicsLinearLayout(burnlist);
        m_extenderLayout->setOrientation(Qt::Vertical);
        m_extenderLayout->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

        m_actionsLayout = new QGraphicsGridLayout(m_extenderLayout);
        m_actionsLayout->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

        m_discLabelLayout = new QGraphicsGridLayout(m_extenderLayout);
        m_discLabelLayout->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

        m_driveCombo = new Plasma::ComboBox(burnlist);
        m_driveCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);

        m_extenderLayout->addItem(m_driveCombo);

        m_currentDiscLabel = new Plasma::IconWidget(burnlist);
        m_currentDiscLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
        m_currentDiscLabel->setOrientation(Qt::Horizontal);
        m_currentDiscLabel->setText(i18n("No Disc Found"));
        m_currentDiscLabel->setTextBackgroundColor(QColor());
        m_currentDiscLabel->setEnabled(false);
        m_currentDiscLabel->setAcceptDrops(false);

        m_discLabelLayout->addItem(m_currentDiscLabel, 0, 0);

        m_closeProjectButton = new Plasma::IconWidget(burnlist);
        m_closeProjectButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
        m_closeProjectButton->setMaximumSize(22, 22);
        m_closeProjectButton->setIcon(KIcon("dialog-close"));
        m_closeProjectButton->setOrientation(Qt::Horizontal);
        m_closeProjectButton->setTextBackgroundColor(QColor());
        m_closeProjectButton->setToolTip(i18n("Close active project"));
        m_closeProjectButton->setAcceptDrops(false);

        m_discLabelLayout->addItem(m_closeProjectButton, 0, 1);

        m_extenderLayout->addItem(m_discLabelLayout);

        m_tree = new Plasma::TreeView(burnlist);
        m_tree->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

        m_projectModel = new ProjectModel;

        m_tree->setModel(m_projectModel);
        m_tree->nativeWidget()->setAnimated(true);
        m_tree->nativeWidget()->setHeaderHidden(true);
        m_tree->nativeWidget()->setDragDropMode(QAbstractItemView::InternalMove);
        m_tree->nativeWidget()->setSelectionMode(QAbstractItemView::SingleSelection);
        m_tree->nativeWidget()->setIconSize(QSize(22,22));
        m_tree->nativeWidget()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

        m_projectMeter = new Plasma::Meter;
        m_projectMeter->setMeterType(Plasma::Meter::BarMeterHorizontal);
        m_projectMeter->setMaximumHeight(14);
        m_projectMeter->setAcceptDrops(false);

        updateDrives();

        m_extenderLayout->addItem(m_tree);
        m_extenderLayout->addItem(m_projectMeter);

        m_createButton = new Plasma::IconWidget(burnlist);
        m_createButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
        m_createButton->setIcon("media-optical");
        m_createButton->setOrientation(Qt::Horizontal);
        m_createButton->setDrawBackground(true);
        m_createButton->setTextBackgroundColor(QColor());
        m_createButton->setText(i18n("Create"));
        m_createButton->setMaximumHeight(36);
        m_createButton->setAcceptDrops(false);

        m_actionsLayout->addItem(m_createButton, 0, 2);

        m_burnButton = new Plasma::IconWidget(burnlist);
        m_burnButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        m_burnButton->setIcon("tools-media-optical-burn");
        m_burnButton->setDrawBackground(true);
        m_burnButton->setTextBackgroundColor(QColor());
        m_burnButton->setText(i18n("Burn"));
        m_burnButton->setAcceptDrops(false);

        m_actionsLayout->addItem(m_burnButton, 0, 0, 2, 1);

        m_actionsLayoutSeparator = new Plasma::Separator(burnlist);
        m_actionsLayoutSeparator->setOrientation(Qt::Vertical);

        m_actionsLayout->addItem(m_actionsLayoutSeparator, 0, 1, 2, 1);

        m_backupButton = new Plasma::IconWidget(burnlist);
        m_backupButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
        m_backupButton->setIcon("tools-media-optical-burn-image");
        m_backupButton->setOrientation(Qt::Horizontal);
        m_backupButton->setDrawBackground(true);
        m_backupButton->setTextBackgroundColor(QColor());
        m_backupButton->setText(i18n("Backup"));
        m_backupButton->setMaximumHeight(36);
        m_backupButton->setAcceptDrops(false);

        m_actionsLayout->addItem(m_backupButton, 0, 3);

/*        m_copyButton = new Plasma::IconWidget(burnlist);
        m_copyButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
        m_copyButton->setIcon("tools-media-optical-copy");
        m_copyButton->setOrientation(Qt::Horizontal);
        m_copyButton->setDrawBackground(true);
        m_copyButton->setTextBackgroundColor(QColor());
        m_copyButton->setText(i18n("Copy"));
        m_copyButton->setMaximumHeight(36);
        m_copyButton->setAcceptDrops(false);
*/
//         m_actionsLayout->addItem(m_copyButton, 1, 0);

        m_ripButton = new Plasma::IconWidget(burnlist);
        m_ripButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
        m_ripButton->setIcon("media-optical-audio");
        m_ripButton->setOrientation(Qt::Horizontal);
        m_ripButton->setDrawBackground(true);
        m_ripButton->setTextBackgroundColor(QColor());
        m_ripButton->setText(i18n("Rip"));
        m_ripButton->setMaximumHeight(36);
        m_ripButton->setAcceptDrops(false);

        m_actionsLayout->addItem(m_ripButton, 1, 2);

        m_formatButton = new Plasma::IconWidget(burnlist);
        m_formatButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
        m_formatButton->setIcon("tools-media-optical-format");
        m_formatButton->setOrientation(Qt::Horizontal);
        m_formatButton->setDrawBackground(true);
        m_formatButton->setTextBackgroundColor(QColor());
        m_formatButton->setText(i18n("Format"));
        m_formatButton->setMaximumHeight(36);
        m_formatButton->setAcceptDrops(false);

        m_actionsLayout->addItem(m_formatButton, 1, 3);
        m_actionsLayout->setColumnMinimumWidth(1, 40);

        m_extenderLayout->addItem(m_actionsLayout);

        burnlist->setLayout(m_extenderLayout);

        connect(m_createButton, SIGNAL(clicked()), this, SLOT(on_createButton_clicked()));
        connect(m_burnButton, SIGNAL(clicked()), this, SLOT(on_burnButton_clicked()));
        connect(m_backupButton, SIGNAL(clicked()), this, SLOT(on_backupButton_clicked()));
//        connect(m_copyButton, SIGNAL(clicked()), this, SLOT(on_copyButton_clicked()));
        connect(m_ripButton, SIGNAL(clicked()), this, SLOT(on_ripButton_clicked()));
        connect(m_formatButton, SIGNAL(clicked()), this, SLOT(on_formatButton_clicked()));
        connect(m_closeProjectButton, SIGNAL(clicked()), this, SLOT(closeOpenProject()));

        connect(m_tree->nativeWidget(), SIGNAL(pressed(QModelIndex)), m_projectModel, SLOT(setCurrentItem(QModelIndex)));

        m_closeProjectButton->setEnabled(false);

        DiscBurner *m_extenderApplet = static_cast<DiscBurner*>(Plasma::Applet::load("discburner"));

        if (m_extenderApplet) {
            m_extenderApplet->setParent(this);
            m_extenderApplet->setAcceptsHoverEvents(false);
            m_extenderApplet->setAcceptDrops(false);
            m_extenderApplet->setParentItem(burnlist);
            m_extenderApplet->setEmbedded(true);
            m_extenderApplet->resize(350, 300);
            m_extenderApplet->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
            m_extenderApplet->setBackgroundHints(NoBackground);
            m_extenderApplet->setFlag(QGraphicsItem::ItemIsMovable, false);
            m_extenderApplet->init();
            m_extenderLayout->addItem(m_extenderApplet);
            m_extenderApplet->updateConstraints(Plasma::StartupCompletedConstraint);
        }

        item->setIcon("tools-media-optical-burn");
        item->setWidget(burnlist);
        item->setTitle(i18n("DiscBurner"));
        item->setMinimumSize(360,360);
    }
}

void DiscBurner::resetActionState()
{
    setActionState(Idle);
    update();
}

void DiscBurner::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
    InteractionState istate = Rejected; // todo: check more mimes.
    if (event->mimeData()->hasFormat("text/plain")) {
        event->acceptProposedAction();
    }

    if (event->mimeData()->hasText()) {
        istate = DraggedOver;
    }

    setInteractionState(istate);

    showOverlayLabel(false);
    m_isHovered = true;
//    Applet::dragEnterEvent(event);
}

void DiscBurner::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
{
    setInteractionState(Waiting);
    showOverlayLabel(false);
    m_isHovered = false;
    event->accept();
}

void DiscBurner::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
{
    event->accept();
}

void DiscBurner::dropEvent(QGraphicsSceneDragDropEvent *event)
{
    if (event->mimeData()->objectName() != QString("discburnerlist")) {
        m_droppedUrls = event->mimeData()->urls();

        foreach (const QUrl& path, m_droppedUrls) {
            if (!m_stopDropping) {
                parseDroppedPath(path, event);
            }
        }

        event->acceptProposedAction();
    }
}

void DiscBurner::parseDroppedPath(const QUrl& path, QGraphicsSceneDragDropEvent *event)
{
    QString s_path = path.toLocalFile();
  qDebug() << s_path;

    if (QFileInfo(s_path).isFile()) {
      qDebug() << "file dropped";
        if (s_path.right(3).toLower() == "mp3" || s_path.right(3).toLower() == "wav" || s_path.right(3).toLower() == "ogg" || s_path.right(4).toLower() == "flac" || s_path.right(3).toLower() == "m4a") {
            if (m_hasAudioProjectLoaded || m_hasMP3ProjectLoaded) {
                qDebug() << "file dropped, audio/mp3 project loaded";
                addSong(s_path);
            } else if (m_hasDataCDProjectLoaded || m_hasDataDVDProjectLoaded) {
                qDebug() << "file dropped, data project loaded";
                addFile(s_path);
            } else {
                qDebug() << "file dropped, no project loaded";
                m_newImageMenu->exec(event->screenPos());
            }
        } else if (s_path.right(3) == "mpg" || s_path.right(3) == "avi") {
            if (m_hasVideoCDProjectLoaded) {
                //addVideo(s_path);
            } else if (m_hasDataCDProjectLoaded || m_hasDataDVDProjectLoaded) {
                addFile(s_path);
            } else {
                m_newImageMenu->exec(event->screenPos());
            }
        } else if (s_path.right(3).toLower() == "iso") {
            if (m_hasDataCDProjectLoaded || m_hasDataDVDProjectLoaded) {
                addFile(s_path);
            } else {
              // ask first?
                burnIso(s_path);
            }
        } else {
            if (m_hasAudioProjectLoaded || m_hasMP3ProjectLoaded) {
                qDebug() << "file dropped, audio/mp3 project loaded, nonstandard filetype";
                QMessageBox::information(0, "DiscBurner", "Could not add file: \"" + s_path + "\". Unsupported format.");
            } else if(m_hasDataCDProjectLoaded || m_hasDataDVDProjectLoaded) {
                addFile(s_path);
            } else if (m_hasVideoCDProjectLoaded || m_hasVideoDVDProjectLoaded) {

            } else {
                qDebug() << "67588";
                m_newImageMenu->exec(event->screenPos());
            }
        }
    } else if (QFileInfo(s_path).isDir()) {
      qDebug() << "folder dropped";
        parseDroppedFolder(s_path);
    }
}

void DiscBurner::parseDroppedFolder(const QString& path)
{ // todo: complete project detection/logic
    if (m_hasDataCDProjectLoaded || m_hasDataDVDProjectLoaded) {
        addFolder(path);
        return;
    }

    int mp3_count = 0;
    int ogg_count = 0;
    int wav_count = 0;
    int flac_count = 0;
    int mpg_count = 0;
    int iso_count = 0;
    int rar_count = 0;
    int p7z_count = 0;
    int zip_count = 0;
    int mp4_count = 0;
    int m3u_count = 0;
    int avi_count = 0;
    int nrg_count = 0;
    int bin_count = 0;
    int cue_count = 0;
    int toc_count = 0;
    int jpg_count = 0;

    int audio_files = 0;
    int video_files = 0;
    int compressed_files = 0;
    int image_files = 0;
    int discimage_files = 0;

    QDir dir(path);
    QStringList entries = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);
    foreach (QString str, entries) {
        if (QDir(path + "/" + str).exists()) {
            parseDroppedFolder(path + "/" + str);
        }

        QString strE = str.right(4).toLower();
        if (strE == ".mp3") {
            mp3_count++;
            audio_files++;
        } else if (strE == ".ogg") {
            ogg_count++;
            audio_files++;
        } else if (strE == ".wav") {
            wav_count++;
            audio_files++;
        } else if (strE == "flac") {
            flac_count++;
            audio_files++;
        } else if (strE == ".mpg") {
            mpg_count++;
            video_files++;
        } else if (strE == "mpeg") {
            mpg_count++;
            video_files++;
        } else if (strE == ".iso") {
            iso_count++;
            discimage_files++;
        } else if (strE == ".rar") {
            rar_count++;
            compressed_files++;
        } else if (strE == ".zip") {
            zip_count++;
            compressed_files++;
        } else if (strE == ".mp4") {
            mp4_count++;
            audio_files++;
        } else if (strE == ".m3u") {
            m3u_count++;
            audio_files++;
        } else if (strE == ".avi") {
            avi_count++;
            video_files++;
        } else if (strE == ".nrg") {
            nrg_count++;
            discimage_files++;
        } else if (strE == ".bin") {
            bin_count++;
            discimage_files++;
        } else if (strE == ".cue") {
            cue_count++;
            discimage_files++;
        } else if (strE == ".toc") {
            toc_count++;
            discimage_files++;
        } else if (strE == ".jpg") {
            jpg_count++;
            image_files++;
        } else if (strE == "jpeg") {
            jpg_count++;
            image_files++;
        }
    }

  qDebug() << mp3_count;
  qDebug() << ogg_count;
  qDebug() << wav_count;

    int total = audio_files + 
                image_files + 
                video_files + 
                discimage_files + 
                compressed_files;

    if (audio_files == 0 || total == 0) { return; }

    float audio_percentage = audio_files / total;
    float video_percentage = video_files / total;

  qDebug() << audio_percentage;

    if (audio_percentage > 0.8) {
        qDebug() << "over 80% audio files...";
    }

    if (video_percentage > 0.5) {
        qDebug() << "over 50% video files...";
    }
}

void DiscBurner::updateDrives(const QString& udi)
{
    if (udi == m_currentDiscUdi) {
        m_driveHasDisc = false;
        m_discIcon->setImagePath("discburner/k3b");
        m_currentDiscCapacity = "0";
        m_currentDiscUsage = "0";
        m_currentDiscContentTypeString = "No Disc Found";
        updateCurrentDisc();
        update();
        return;
    }

    m_devicesHash.clear();

    foreach (const Solid::Device &device, Solid::Device::listFromType(Solid::DeviceInterface::OpticalDrive, QString())) {
        const Solid::Block *block_device = device.as<Solid::Block>();

        m_currentDriveUdi = device.udi();
        m_currentDriveDeviceString = block_device->device();

        foreach (const Solid::Device &disc_dev, Solid::Device::listFromType(Solid::DeviceInterface::OpticalDisc, QString())) {
            m_currentDiscUdi = disc_dev.udi();
            m_currentDiscContentType = disc_dev.as<Solid::OpticalDisc>()->availableContent();
            m_currentDiscUsage = QString::number((disc_dev.as<Solid::OpticalDisc>()->size() / 1024) / 1024);
            m_currentDiscCapacity = QString::number((disc_dev.as<Solid::OpticalDisc>()->capacity() / 1024) / 1024);
            m_currentDiscLabelString = disc_dev.as<Solid::StorageVolume>()->label();

            if (m_currentDiscContentType == Solid::OpticalDisc::Audio) {
                m_discIcon->setImagePath("discburner/media-optical-audio");
                m_currentDiscContentTypeString = "Audio Disc";
            } else if (m_currentDiscContentType == Solid::OpticalDisc::Data) {
                m_discIcon->setImagePath("discburner/media-optical");
                m_currentDiscContentTypeString = "Data Disc";
            } else if (disc_dev.as<Solid::OpticalDisc>()->isBlank()) {
                m_discIcon->setImagePath("discburner/media-optical-recordable");
                m_currentDiscContentTypeString = "Blank Disc";
            } else {
                m_discIcon->setImagePath("discburner/media-optical-video");
                m_currentDiscContentTypeString = "Video Disc";
            }
        }

        m_devicesHash.insert(block_device->device(), device.product());
    }

    m_driveCombo->nativeWidget()->clear();

    foreach(const QString& value, m_devicesHash) {
        m_driveCombo->nativeWidget()->addItem(KIcon("drive-optical"), value);
    }

    if (m_devicesHash.isEmpty())
        m_driveCombo->nativeWidget()->addItem(KIcon("drive-optical"), i18n("No Devices Found"));

    updateCurrentDisc();

    update();
}

void DiscBurner::on_createButton_clicked()
{
    m_newImageMenu->exec(QCursor::pos());
}

void DiscBurner::on_burnButton_clicked()
{
    if (m_currentDiscLabelString == "No Disc Found") {
        if (QMessageBox::question(0, i18n("No Disc"), i18n("There is no disc detected, try again?"), QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel) == QMessageBox::Yes) {
            updateDrives();
            on_burnButton_clicked();
        }
        return;
    }

    if (!m_currentDriveDeviceString.isEmpty()) {
        if (m_hasAudioProjectLoaded || m_hasMP3ProjectLoaded || m_hasDataCDProjectLoaded 
                                    || m_hasDataDVDProjectLoaded || m_hasMixedModeProjectLoaded 
                                    || m_hasVideoCDProjectLoaded || m_hasVideoDVDProjectLoaded) {
            hidePopup();
            m_cancelVisible = true;
            m_ejectVisible = false;
            m_busyWidget->setVisible(true);
            m_meter->setVisible(true);
        }

        if (m_hasAudioProjectLoaded) {
            setActionState(Converting);
            ConvertThread *converter = new ConvertThread(this, currentProjectFileList(), "audiocd_wav");
            connect(converter, SIGNAL(totalFrames(int)), this, SLOT(setJobMaximum(int)));
            connect(converter, SIGNAL(currentFrame(int)), this, SLOT(setJobProgress(int)));
            connect(converter, SIGNAL(currentFile(QString)), this, SLOT(setJobStatus(QString)));
            connect(converter, SIGNAL(beginBurning()), this, SLOT(burnCurrentAudioProject()));
            connect(converter, SIGNAL(finished()), this, SLOT(jobCompleted()));
            connect(this, SIGNAL(cancelProcesses()), converter, SLOT(cancelProcess()));
            converter->run();
        } else if (m_hasMP3ProjectLoaded) {
            setActionState(Converting);
            ConvertThread *converter = new ConvertThread(this, currentProjectFileList(), "to_mp3");
            connect(converter, SIGNAL(totalFrames(int)), this, SLOT(setJobMaximum(int)));
            connect(converter, SIGNAL(currentFrame(int)), this, SLOT(setJobProgress(int)));
            connect(converter, SIGNAL(currentFile(QString)), this, SLOT(setJobStatus(QString)));
            connect(converter, SIGNAL(beginBurning()), this, SLOT(burnCurrentMP3CDProject()));
            connect(converter, SIGNAL(finished()), this, SLOT(jobCompleted()));
            connect(this, SIGNAL(cancelProcesses()), converter, SLOT(cancelProcess()));
            converter->run();
        } else if (m_hasDataCDProjectLoaded || m_hasDataDVDProjectLoaded) {
            setActionState(Burning);
            BurnDataImageThread *burner = new BurnDataImageThread(this, m_currentDriveDeviceString, currentProjectFileList());
            connect(burner, SIGNAL(dataSize(int)), this, SLOT(setJobMaximum(int)));
            connect(burner, SIGNAL(dataProgress(int)), this, SLOT(setJobProgress(int)));
            connect(burner, SIGNAL(finished()), this, SLOT(jobCompleted()));
            connect(this, SIGNAL(cancelProcesses()), burner, SLOT(cancelProcess()));
            burner->run();
        } else if (m_hasVideoCDProjectLoaded) {
            // todo
        } else if (m_currentDiscContentTypeString == "Blank Disc") {
            const QString filename = KFileDialog::getOpenFileName(KUrl(QDir::homePath()), "*.iso|ISO9660 Image Files (*.iso)\n*.bin|Binary Image Files (*.bin)\n*.toc|Table of Contents Files (*.toc)\n*.nrg|Nero Image Files (*.nrg)\n*.cue|CloneImage Files (*.cue)", this->widget(), "Select Image File");
            if (!filename.isEmpty()) {
                if (filename.right(3).toLower() == "iso") {
                    burnIso(filename);
                } else {
                    burnIso(filename + ".iso");
                }
            }
        } else {
            QMessageBox::information(0, "No Project/Disc", i18n("'Create' a new project first, or insert a blank disc to burn an image file."));
        }
    }
}

QStringList DiscBurner::currentProjectFileList()
{
    QStringList list;
    int i = 0;
    if (m_hasAudioProjectLoaded || m_hasMP3ProjectLoaded) {
        while (i < m_projectModel->item(0)->rowCount()) {
            list.append(m_projectModel->item(0)->child(i)->data(32).toString());
            i++;
        }
    } else if (m_hasDataCDProjectLoaded || m_hasDataDVDProjectLoaded) {
        while (i < m_projectModel->item(0)->rowCount()) {
            if (m_projectModel->item(0)->child(i)->hasChildren()) {
                int j = 0;
                while (j < m_projectModel->item(0)->child(i)->rowCount()) {
                    list.append(m_projectModel->item(0)->child(i)->child(j)->data(32).toString());
                    j++;
                }
            } else {
                list.append(m_projectModel->item(0)->child(i)->data(32).toString());
            }

            i++;
        }
    }

    qDebug() << "constructed currentFileList: " << list.join(" ");
    return list;
}

void DiscBurner::on_backupButton_clicked()
{
    if (m_currentDriveDeviceString.isEmpty()) {
        return;
    }

    if (m_currentDiscContentTypeString == "Blank Disc") {
        return;
    }
    
    KUrl url ( QDir::homePath() );
    QProcess p(0);
    QString fileName;
    if (m_currentDiscContentType == Solid::OpticalDisc::Audio) {
        if(QMessageBox::question(this->widget(), i18n("Really create .bin?"), i18n("Audio CDs are not ISO filesystems. They are usually decoded ('Rip'ped) into .ogg/.mp3. Continue creating .bin/.toc files? [FOR ADVANCED USERS]"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel) == QMessageBox::Yes) {
            fileName = KFileDialog::getSaveFileName(url, "BIN Files (*.bin)", this->widget(), "Save BIN file");
        }
        else {
            return;
        }
    }
    else {
        fileName = KFileDialog::getSaveFileName(url, "ISO Files (*.iso)", this->widget(), "Save ISO file");
        if (fileName.right(4).toLower() != ".iso")
            fileName.append(".iso");
    }

    if (!m_currentDriveDeviceString.isEmpty()) {
        hidePopup();
        setActionState(Reading);
        m_cancelVisible = true;
        m_ejectVisible = false;
        m_busyWidget->setVisible(true);
        m_meter->setVisible(true);
        setJobMaximum(m_currentDiscUsage.toInt());
        BackupThread *backup = new BackupThread(this->widget(), m_currentDriveDeviceString, fileName, m_currentDiscContentType);
        connect(backup, SIGNAL(discCapacity(int)), this, SLOT(setJobMaximum(int)));
        connect(backup, SIGNAL(progressMonitor(int)), this, SLOT(setJobProgress(int)));
        connect(backup, SIGNAL(finished()), this, SLOT(jobCompleted()));
        connect(this, SIGNAL(cancelProcesses()), backup, SLOT(cancelProcess()));
        backup->run();
        update();
    }
}

void DiscBurner::on_copyButton_clicked()   // todo: check for multiple burners and inquire
{
    if (m_currentDriveDeviceString.isEmpty())
        return;

    hidePopup();
    setActionState(Reading);
    m_cancelVisible = true;
    m_ejectVisible = false;
    m_busyWidget->setVisible(true);
    m_meter->setVisible(true);
    setJobMaximum(m_currentDiscUsage.toInt());
    CopyThread *copier = new CopyThread(this->widget(), m_currentDriveDeviceString, m_currentDiscContentType);
    connect(copier, SIGNAL(discCapacity(int)), this, SLOT(setJobMaximum(int)));
    connect(copier, SIGNAL(progressMonitor(int)), this, SLOT(setJobProgress(int)));
    connect(copier, SIGNAL(ejectTray()), this, SLOT(on_ejectButton_clicked()));
    connect(copier, SIGNAL(finished()), this, SLOT(jobCompleted()));
    connect(this, SIGNAL(cancelProcesses()), copier, SLOT(cancelProcess()));
    connect(this, SIGNAL(blankDiscInserted()), copier, SLOT(blankDiscInserted()));
    copier->run();
    update();
}

void DiscBurner::on_ripButton_clicked()
{
    m_ripToMenu->exec(QCursor::pos());
}

void DiscBurner::ripDisc(const QString& filetype)
{
    if (m_currentDriveDeviceString.isEmpty())
        return;

    hidePopup();
    setActionState(Converting);
    m_cancelVisible = true;
    m_ejectVisible = false;
    m_busyWidget->setVisible(true);
    m_meter->setVisible(true);
    setJobMaximum(m_currentDiscUsage.toInt());
    RipThread *ripper = new RipThread(this->widget(), m_currentDriveDeviceString, filetype, m_currentDiscContentType);
    connect(ripper, SIGNAL(discCapacity(int)), this, SLOT(setJobMaximum(int)));
    connect(ripper, SIGNAL(progressMonitor(int)), this, SLOT(setJobProgress(int)));
    connect(ripper, SIGNAL(trackNumber(QString)), this, SLOT(setJobStatus(QString)));
    connect(ripper, SIGNAL(finished()), this, SLOT(jobCompleted()));
    connect(this, SIGNAL(cancelProcesses()), ripper, SLOT(cancelProcess()));
    ripper->run();
    update();
}

void DiscBurner::ripDiscToMp3()
{
    ripDisc("mp3");
}

void DiscBurner::ripDiscToOgg()
{
    ripDisc("ogg");
}

void DiscBurner::ripDiscToWav()
{
    ripDisc("wav");
}

void DiscBurner::on_formatButton_clicked()
{
    if (m_currentDriveDeviceString.isEmpty())
        return;

    if (m_currentDiscContentTypeString == "Blank Disc") {
        if(QMessageBox::question(this->widget(), i18n("Disc Already Blank"), i18n("This disc appears to already be blank. Format it again anyway?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
            return;
        }
    }

    hidePopup();
    m_cancelVisible = false;
    m_ejectVisible = false;
    m_busyWidget->setVisible(true);
    setActionState(Formatting);
    FormatThread *formatter = new FormatThread(this->widget(), m_currentDriveDeviceString, m_currentDiscCapacity.toInt());
    connect(formatter, SIGNAL(finished()), this, SLOT(jobCompleted()));
    connect(formatter, SIGNAL(jobStatus(QString)), this, SLOT(setJobStatus(QString)));
    connect(this, SIGNAL(cancelProcesses()), formatter, SLOT(cancelProcess()));
    formatter->run();
    update();
}

void DiscBurner::setJobMaximum(int max)
{
  qDebug() << "setJobMaximum() max: " << max;
    m_jobMaximum = max;
}

void DiscBurner::setJobProgress(int progress)
{
  qDebug() << "setJobProgress() progress: " << progress;
    m_toolTipData = new Plasma::ToolTipContent();
    m_toolTipData->setAutohide(true);
    m_toolTipData->setMainText("DiscBurner");

    m_jobProgress = progress;

    if(m_jobMaximum > 0 && m_jobProgress > 0) {
        m_currentProgress = (m_jobProgress * 100) / m_jobMaximum;
      qDebug() << "m_currentProgress: " << m_currentProgress;
    }

    if ((m_currentProgress > 100))
        return;

    if (m_actionState == Reading) {
        m_toolTipData->setMainText("Reading...");
        m_toolTipData->setImage(KIcon("tools-media-optical-burn-image"));
        m_toolTipData->setSubText(i18n("Creating backup...<br>%1% Complete", QString::number(m_currentProgress)));
    }
    else if (m_actionState == Burning) {
        m_toolTipData->setMainText("Burning...");
        m_toolTipData->setImage(KIcon("tools-media-optical-burn"));

        if (m_currentProgress == 0) {
            m_toolTipData->setSubText(i18n("Caching Data"));
        }
        else if (m_currentProgress == 100) {
            m_toolTipData->setSubText(i18n("Finalizing Media"));
        }
        else {
            if (m_hasAudioProjectLoaded) {
                m_toolTipData->setSubText(i18n("Audio Project: %1<br>Track %2: %3%", m_projectModel->item(0)->text(), QString(m_currentJobStatus + " of " + QString::number(currentProjectFileList().count())), QString::number(m_currentProgress)));
            } else if (m_hasVideoCDProjectLoaded) {
                m_toolTipData->setSubText(i18n("%1%", QString::number(m_currentProgress)));
            } else if (m_hasDataCDProjectLoaded) {
                m_toolTipData->setSubText(i18n("%1%", QString::number(m_currentProgress)));
            } else if (m_hasDataDVDProjectLoaded) {
                m_toolTipData->setSubText(i18n("%1%", QString::number(m_currentProgress)));
            } else {
                m_toolTipData->setSubText(i18n("%1%", QString::number(m_currentProgress)));
            }
        }
    }
    else if (m_actionState == Formatting) {
        m_toolTipData->setMainText(i18n("Formatting..."));
        m_toolTipData->setImage(KIcon("tools-media-optical-erase"));
        m_toolTipData->setSubText(i18n("Erasing disc"));
    }
    else if (m_actionState == Converting) {
        m_toolTipData->setMainText(i18n("Converting..."));
        m_toolTipData->setImage(KIcon("tools-wizard"));
        m_toolTipData->setSubText(i18n("%1: %2%", m_currentJobStatus, QString::number(m_currentProgress)));
    }

    Plasma::ToolTipManager::self()->setContent(this, *m_toolTipData);

    m_meter->setMaximum(100);
    m_meter->setValue(m_currentProgress);

    update();
}

void DiscBurner::jobCompleted()
{
    m_jobProgress = m_jobMaximum;
    m_currentProgress = 100;
    m_meter->setMaximum(100);
    m_meter->setValue(m_currentProgress);
    setActionState(IdleSuccess);
    setBusy(false);
    m_cancelButton->setVisible(false);
    m_cancelVisible = false;
    m_ejectVisible = true;
    m_busyWidget->setVisible(false);
    m_meter->setVisible(false);
    m_stopDropping = false;
    on_ejectButton_clicked();
    update();
}

void DiscBurner::setJobStatus(QString status) // todo: a violent hack to catch rogue data
{
  qDebug() << "setJobStatus() status: " << status;
    m_currentJobStatus = status.remove(":");

    if(m_currentJobStatus.at(0) == QChar('0'))
        m_currentJobStatus = m_currentJobStatus.remove(0, 1);
    
    if (m_currentJobStatus == "wiped.dvd+rw") {
        m_discIcon->setImagePath("discburner/media-optical-recordable");
        m_currentDiscContentTypeString = "Blank Disc";
        m_currentJobStatus = "";
    }

}

void DiscBurner::burnIso(const QString& url)
{
    if (!m_currentDriveDeviceString.isEmpty()) {
        m_cancelVisible = true;
        m_ejectVisible = false;
        m_busyWidget->setVisible(true);
        m_meter->setVisible(true);
        setActionState(Burning);
        BurnImageThread *burner = new BurnImageThread(this, m_currentDriveDeviceString, url);
        connect(burner, SIGNAL(imageSize(int)), this, SLOT(setJobMaximum(int)));
        connect(burner, SIGNAL(progress(int)), this, SLOT(setJobProgress(int)));
        connect(burner, SIGNAL(finished()), this, SLOT(jobCompleted()));
        connect(this, SIGNAL(cancelProcesses()), burner, SLOT(cancelProcess()));
        burner->run();
    }
}

void DiscBurner::updateCurrentDisc()
{
    if (m_currentDiscUdi.isEmpty() || m_currentDiscUdi.isNull())
        return;

    if (m_currentDiscContentTypeString == "Audio Disc") {
        m_currentDiscLabel->setIcon("media-optical-audio");
    }
    else if (m_currentDiscContentTypeString == "Data Disc") {
        m_currentDiscLabel->setIcon("media-optical");
    }
    else if (m_currentDiscContentTypeString == "Blank Disc") {
        m_currentDiscLabel->setIcon("media-optical-recordable");
        emit blankDiscInserted();
    }
    else if (m_currentDiscContentTypeString == "Video Disc") {
        m_currentDiscLabel->setIcon("media-optical-video");
    }
    else {
        m_currentDiscLabel->setIcon("k3b");
    }

    m_currentDiscLabel->setText(m_currentDiscLabelString + "     " + m_currentDiscUsage + "/" + m_currentDiscCapacity + " MB    " + m_currentDiscContentTypeString);
    m_currentDiscLabel->setTextBackgroundColor(QColor());
}

void DiscBurner::on_ejectButton_clicked()
{
    Solid::Device current_drive = Solid::Device(m_currentDriveUdi);
    current_drive.as<Solid::OpticalDrive>()->eject();

    updateDrives();
}

void DiscBurner::on_cancelButton_clicked()
{
    emit cancelProcesses();
    m_wasCancelled = true;
}

void DiscBurner::on_newAudioCDImage_clicked() // fix meee
{
    if (m_hasAudioProjectLoaded) {
        if (QMessageBox::question(0, i18n("Overwrite?"), i18n("There is already an open Audio CD project. Start a new project?"), i18n("Yes"), i18n("No")) == 0) {
            QProcess p;
            p.start("rm /tmp/discburner_audioproject -r");
            p.waitForFinished();
        } else {
            return;
        }
    }

    QDir d;
    d.mkdir("/tmp/discburner_audioproject");

    closeOpenProject();

    QStandardItem *item = new QStandardItem;
    item->setText("Audio Disc");
    item->setData("Project: Audio Disc", 32);
    item->setIcon(KIcon("folder-sound"));
    item->setToolTip(i18n("Double-click to change disc label")); // fix meee -w?
    item->setEditable(true);
    item->setSelectable(false);
    item->setDragEnabled(false);
    item->setDropEnabled(true);
    m_projectModel->appendRow(item);
    m_projectModel->invisibleRootItem()->setDropEnabled(false);
    m_tree->nativeWidget()->expand(item->index());

    m_hasAudioProjectLoaded = true;
    m_closeProjectButton->setEnabled(true);

    m_projectMeter->setMaximum(4800);

    if (!m_droppedUrls.isEmpty()) {
        QString s_path = m_droppedUrls.first().toLocalFile();

        if (QFileInfo(s_path).isDir()) {
            parseDroppedFolder(s_path);
        } else if (QFileInfo(s_path).isFile()) {
            if (s_path.right(3).toLower() == "mp3" || s_path.right(3).toLower() == "ogg" || s_path.right(3).toLower() == "wav" || s_path.right(3).toLower() == "wma"|| s_path.right(3).toLower() == "mp4" || s_path.right(4).toLower() == "flac") {
                addSong(s_path);
            }
        }
    }
}

void DiscBurner::on_newMP3CDImage_clicked()
{
    if (m_hasMP3ProjectLoaded) {
        if (QMessageBox::question(0, i18n("Overwrite?"), i18n("There is already an open MP3 CD project. Start a new project?"), i18n("Yes"), i18n("No")) == 0) {

        } else { 
            return;
        }
    }

    closeOpenProject();

    QDir d;
    d.mkdir("/tmp/discburner_mp3cdproject");

    QStandardItem *item = new QStandardItem;
    item->setText("MP3 Disc");
    item->setData("Project: MP3 Disc", 32);
    item->setIcon(KIcon("folder-sound"));
    item->setToolTip("Double-click to change disc label"); // fix meee -w?
    item->setEditable(true);
    item->setSelectable(false);
    item->setDragEnabled(false);
    item->setDropEnabled(true);
    m_projectModel->appendRow(item);
    m_projectModel->invisibleRootItem()->setDropEnabled(false);
    m_tree->nativeWidget()->expand(item->index());

    m_hasMP3ProjectLoaded = true;
    m_closeProjectButton->setEnabled(true);

  qDebug() << m_currentDiscCapacity;
    if(m_currentDiscCapacity.toInt() != 0) {
        m_projectMeter->setMaximum(m_currentDiscCapacity.toInt());	
    } else if (m_currentDiscCapacity.toInt() < 815) {
        m_projectMeter->setMaximum(701);
    } else {
        m_projectMeter->setMaximum(4481);
    }

    if (!m_droppedUrls.isEmpty()) {
        QString s_path = m_droppedUrls.first().toLocalFile();

        if (QFileInfo(s_path).isDir()) {
            parseDroppedFolder(s_path);
        } else if (QFileInfo(s_path).isFile()) {
            if (s_path.right(3).toLower() == "mp3" || s_path.right(3).toLower() == "ogg" || s_path.right(3).toLower() == "wav" || s_path.right(3).toLower() == "wma"|| s_path.right(3).toLower() == "mp4" || s_path.right(4).toLower() == "flac") {
                addSong(s_path);
            }
        }
    }
}

void DiscBurner::on_newVideoCDImage_clicked()
{

}

void DiscBurner::on_newVideoDVDImage_clicked()
{

}

void DiscBurner::on_newDataCDImage_clicked()
{
    if (m_hasDataCDProjectLoaded && (QMessageBox::question(0, i18n("Overwrite?"), i18n("There is already an open Data CD project. Start a new project?"), i18n("Yes"), i18n("No")) == QMessageBox::No)) {
        return;
    }

    closeOpenProject();

    QStandardItem *item = new QStandardItem;
    item->setText("Data CD");
    item->setData("Project: Data CD", 32);
    item->setIcon(KIcon("folder-tar"));
    item->setToolTip("Double-click to change disc label"); // fix meee -w?
    item->setEditable(true);
    item->setSelectable(false);
    item->setDragEnabled(false);
    item->setDropEnabled(true);
    m_projectModel->appendRow(item);
    m_projectModel->invisibleRootItem()->setDropEnabled(false);
    m_tree->nativeWidget()->expand(item->index());

    m_hasDataCDProjectLoaded = true;

    m_closeProjectButton->setEnabled(true);

    m_projectMeter->setMaximum(m_currentDiscCapacity.toInt());

    if (m_projectMeter->maximum() == 0) {
        m_projectMeter->setMaximum(701);
    }

    if(!m_droppedUrls.isEmpty()) {
        QString s_path = m_droppedUrls.first().toLocalFile();

      qDebug() << s_path << " first_droppd_url";

        if (QFileInfo(s_path).isDir()) {
          qDebug() << "s_path.isDir()";
            addFolder(s_path);
        } else if (QFileInfo(s_path).isFile()) {
          qDebug() << "s_path.isFile()";
            addFile(s_path);
        }
    }
}

void DiscBurner::on_newDataDVDImage_clicked()
{
    if (m_hasDataDVDProjectLoaded && (QMessageBox::question(0, i18n("Overwrite?"), i18n("There is already an open Data DVD project. Start a new project?"), i18n("Yes"), i18n("No")) == QMessageBox::No)) {
        return;
    }

    closeOpenProject();

    QStandardItem *item = new QStandardItem;
    item->setText("Data DVD");
    item->setData("Project: Data DVD", 32);
    item->setIcon(KIcon("folder-tar"));
    item->setToolTip(i18n("Double-click to change disc label")); // fix meee -w?
    item->setEditable(true);
    item->setSelectable(false);
    item->setDragEnabled(false);
    item->setDropEnabled(true);
    m_projectModel->appendRow(item);
    m_projectModel->invisibleRootItem()->setDropEnabled(false);
    m_tree->nativeWidget()->expand(item->index());

    m_hasDataDVDProjectLoaded = true;

    m_closeProjectButton->setEnabled(true);

    m_projectMeter->setMaximum(m_currentDiscCapacity.toInt());

    if (m_projectMeter->maximum() == 0) {
        m_projectMeter->setMaximum(4481);
    }

    if(!m_droppedUrls.isEmpty()) {
        QString s_path = m_droppedUrls.first().toLocalFile();

        if (QFileInfo(s_path).isDir()) {
            addFolder(s_path);
        } else if (QFileInfo(s_path).isFile()) {
            addFile(s_path);
        }
    }
}

void DiscBurner::on_newMixedModeImage_clicked()
{

}

void DiscBurner::addSong(const QString& url)
{
    QStandardItem *song = new QStandardItem;
    song->setText(QFileInfo(url).baseName());
    song->setData(url, 32);
    song->setIcon(KIcon("audio-x-wav"));
    song->setDropEnabled(false);
    song->setEditable(false);
    song->setSelectable(true);

    QStandardItem *songArtist = new QStandardItem;
    QStandardItem *songTitle = new QStandardItem;
    QStandardItem *songLength = new QStandardItem;
    QStandardItem *songSize = new QStandardItem;

    AudioFile *songFile = new AudioFile(url);

    songArtist->setText(songFile->trackArtist());
    songArtist->setIcon(KIcon("view-media-artist"));
    songArtist->setDragEnabled(false);
    songArtist->setDropEnabled(false);
    songArtist->setSelectable(false);
    songTitle->setText(songFile->trackTitle());
    songTitle->setIcon(KIcon("mixer-microphone"));
    songTitle->setDragEnabled(false);
    songTitle->setDropEnabled(false);
    songTitle->setSelectable(false);
    songLength->setText(songFile->trackLength());
    songLength->setIcon(KIcon("mixer-pcm-default"));
    songLength->setEditable(false);
    songLength->setDragEnabled(false);
    songLength->setDropEnabled(false);
    songLength->setSelectable(false);
    songSize->setText(songFile->trackSize());
    songSize->setIcon(KIcon("server-database"));
    songSize->setEditable(false);
    songSize->setDragEnabled(false);
    songSize->setDropEnabled(false);
    songSize->setSelectable(false);

    if (m_hasMP3ProjectLoaded) {
        if ((m_currentProjectSize + QFile(url).size()) / 1024 / 1024 > m_projectMeter->maximum()) {
            QMessageBox::critical(0, "Sorry", i18n("Not enough space left for ").append(QFileInfo(url).baseName()));
            m_stopDropping = true;
            return;
        }

        m_currentProjectSize = m_currentProjectSize + QFile(url).size();

        m_projectMeter->setValue((int)(m_currentProjectSize / 1024 / 1024));
    } else {
        if (m_currentProjectSize + songFile->trackLengthInSecs() > m_projectMeter->maximum()) {
            QMessageBox::critical(0, "Sorry", i18n("Not enough space left for ").append(QFileInfo(url).baseName()));
            m_stopDropping = true;
            return;
        }

        m_currentProjectSize = m_currentProjectSize + songFile->trackLengthInSecs();

        m_projectMeter->setValue((int)m_currentProjectSize);
    }

    m_projectModel->item(0)->appendRow(song);
    m_projectModel->invisibleRootItem()->setDropEnabled(false);

    song->appendRow(songArtist);
    song->appendRow(songTitle);
    song->appendRow(songLength);
    song->appendRow(songSize);

    m_stopDropping = false;

    if (url == m_droppedUrls.last().toLocalFile()) {
        m_droppedUrls.clear();
    }
}

void DiscBurner::burnCurrentMP3CDProject()
{
    if (m_currentDriveDeviceString.isEmpty()) {
        return;
    }

    setActionState(Burning);
    BurnDataImageThread *burner = new BurnDataImageThread(this, m_currentDriveDeviceString, currentProjectFileList());
    connect(burner, SIGNAL(dataSize(int)), this, SLOT(setJobMaximum(int)));
    connect(burner, SIGNAL(dataProgress(int)), this, SLOT(setJobProgress(int)));
    connect(burner, SIGNAL(finished()), this, SLOT(jobCompleted()));
    connect(this, SIGNAL(cancelProcesses()), burner, SLOT(cancelProcess()));
    burner->run();  
}

void DiscBurner::burnCurrentAudioProject()
{
    if (m_currentDriveDeviceString.isEmpty()) {
        return;
    }

    setActionState(Burning);
    BurnAudioImageThread *burner = new BurnAudioImageThread(this, m_currentDriveDeviceString, currentProjectFileList());
    connect(burner, SIGNAL(trackSize(int)), this, SLOT(setJobMaximum(int)));
    connect(burner, SIGNAL(trackProgress(int)), this, SLOT(setJobProgress(int)));
    connect(burner, SIGNAL(trackNumber(QString)), this, SLOT(setJobStatus(QString)));
    connect(burner, SIGNAL(finished()), this, SLOT(jobCompleted()));
    connect(this, SIGNAL(cancelProcesses()), burner, SLOT(cancelProcess()));
    burner->run();
}

void DiscBurner::burnCurrentDiscCopy() // fix me. borked.
{
    on_ejectButton_clicked();
    if (QMessageBox::information(0, "Blank Disc", i18n("Please insert a blank disc.")) == QMessageBox::Ok) {
        if (m_currentDiscContentTypeString == "Blank Disc")
            burnIso("/tmp/discburner_copy");
    }
}

void DiscBurner::closeOpenProject()
{
    m_hasAudioProjectLoaded = false;
    m_hasMP3ProjectLoaded = false;
    m_hasMixedModeProjectLoaded = false;
    m_hasDataCDProjectLoaded = false;
    m_hasDataDVDProjectLoaded = false;
    m_hasVideoCDProjectLoaded = false;
    m_hasVideoDVDProjectLoaded = false;
    m_currentProjectSize = 0;
    m_projectModel->clear();
    m_closeProjectButton->setEnabled(false);
    m_projectMeter->setValue(0);
    m_wasCancelled = false;
    m_stopDropping = false;
}

void DiscBurner::addFolder(const QString& url)
{
    QProcess p;
    p.start("du -s \"" + url + "\"");
    p.waitForFinished();
    QString out = p.readAll();
    QString sizeK = QStringList(out.split("\t")).at(0);

    int sizeB = sizeK.toInt() * 1024;
    int sizeM = sizeK.toInt() / 1024;

    if (((m_currentProjectSize / 1024 / 1024) + sizeM) > m_projectMeter->maximum()) {
        QMessageBox::critical(0, "Sorry", i18n("Not enough space left for ").append(QFileInfo(url).baseName()));
        m_stopDropping = true;
        return;
    }

    QStandardItem *dir = new QStandardItem;
    dir->setText(QFileInfo(url).baseName());
    dir->setData(url, 32);
    dir->setIcon(KIcon("folder"));
    dir->setDragEnabled(true);
    dir->setDropEnabled(false);
    dir->setEditable(false);
    dir->setSelectable(true);

    QDir d(url);
    QStringList entries = d.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);

    foreach (QString str, entries) {
        QStandardItem *item = new QStandardItem;
        item->setText(str);
        item->setData(url + "/" + str, 32);
        if (QFileInfo(url + "/" + str).isFile()) {
            item->setIcon(KIcon("application-octet-stream"));
        } else {
            addFolderItem(url + "/" + str, item);
        }
        item->setDragEnabled(true);
        item->setDropEnabled(false);
        item->setEditable(false);
        item->setSelectable(true);
        dir->appendRow(item);
    }

    m_projectModel->item(0)->appendRow(dir);

    m_currentProjectSize = m_currentProjectSize + sizeB;

    m_projectMeter->setValue((int)(m_currentProjectSize / 1024 / 1024));

    m_stopDropping = false;

    if (url == m_droppedUrls.last().toLocalFile()) {
        m_droppedUrls.clear();
    }

}

void DiscBurner::addFolderItem(const QString& url, QStandardItem* item)
{
    QDir d(url);
    QStringList entries = d.entryList(QDir::AllEntries | QDir::NoDotAndDotDot);

    item->setText(QFileInfo(url).baseName());
    item->setData(url, 32);
    item->setIcon(KIcon("folder"));

    foreach (QString str, entries) {
      qDebug() << str;
        QStandardItem *fItem = new QStandardItem;
        fItem->setText(str);
        fItem->setData(url + "/" + str, 32);
        if (QFileInfo(url + "/" + str).isFile()) {
            fItem->setIcon(KIcon("application-octet-stream"));
        } else {
            addFolderItem(url + "/" + str, fItem);
        }
        fItem->setDragEnabled(true);
        fItem->setDropEnabled(false);
        fItem->setEditable(false);
        fItem->setSelectable(true);
        item->appendRow(fItem);
    }
}

void DiscBurner::addFile(const QString& url)
{
    if ((m_currentProjectSize + QFile(url).size()) / 1024 / 1024 > m_projectMeter->maximum()) {
        QMessageBox::critical(0, "Sorry", i18n("Not enough space left for ").append(QFileInfo(url).baseName()));
        m_stopDropping = true;
        return;
    }

    QStandardItem *file = new QStandardItem;
    file->setText(QFileInfo(url).baseName());
    file->setData(url, 32);
    file->setIcon(KIcon("application-octet-stream"));
    file->setDragEnabled(true);
    file->setDropEnabled(false);
    file->setEditable(false);
    file->setSelectable(true);

    m_projectModel->item(0)->appendRow(file);

    m_currentProjectSize = m_currentProjectSize + QFile(url).size();

    m_projectMeter->setValue((int)(m_currentProjectSize / 1024 / 1024));

    m_stopDropping = false;

    if (url == m_droppedUrls.last().toLocalFile()) {
        m_droppedUrls.clear();
    }
}

void DiscBurner::updateApplet()
{
    update();
}

#include "discburner.moc"
