/****************************************************************************
 ** Copyright (C) 2008-2013 Grigory A. Mozhaev <zcrendel@gmail.com>
 **
 ** This file is part of QMultiRecord (http://qt-apps.org/content/show.php?content=106254).
 **
 ** This file may be used under the terms of the GNU General Public
 ** License version 2.0 as published by the Free Software Foundation
 ** and appearing in the file LICENSE.GPL included in the packaging of
 ** this file.  Please review the following information to ensure GNU
 ** General Public Licensing requirements will be met:
 ** http://www.trolltech.com/products/qt/opensource.html
 **
 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 ****************************************************************************/
//! -*- coding: UTF-8 -*-
#define SOURCE_CODING "UTF-8"

#include "dvdmodel.h"

class BurnThreadPrivate {
public:
    QString m_isoFileName;

    QString m_device;
    int m_speed;
    bool m_streamRecording;
    QString m_buffer;

    bool m_initialized;
    bool m_eject;

    bool m_success;

    DvdModel *m_model;

    bool m_exit;

    BurnThreadPrivate() {
        m_isoFileName = QString::null;
        m_speed = 4;
        m_buffer = QString::null;
        m_initialized = false;
        m_streamRecording = false;
        m_success = false;

        m_model = 0;
        m_exit = false;
    }

    ~BurnThreadPrivate() {

    }
};

BurnThread::BurnThread() {
    m_data = new BurnThreadPrivate;

    Q_ASSERT(m_data!=0);    
}

BurnThread::~BurnThread() {
    if (m_data)
        delete m_data;
}

void BurnThread::init(DvdModel *model) {
    if (!model)
        return ;

    if (model->isoFileName().isNull())
        return ;

    if (model->deviceFile().isNull())
        return ;

    if ((model->speed() < 0) || ((model->speed() % 2) != 0))
        return ;

    if (m_data) {
        m_data->m_model = model;
        m_data->m_isoFileName = model->isoFileName();
        m_data->m_device = model->deviceFile();
        m_data->m_speed = model->speed();
        m_data->m_streamRecording = model->streamRecording();
        m_data->m_buffer = model->buffer();
        m_data->m_initialized = true;
    }
}

void BurnThread::stop() {
    if (m_data)
        m_data->m_exit = true;
}

bool BurnThread::done() {
    return m_data->m_success;
}


// %%%%%%%%%%%%%%%%%%%%%%%% BurnCDThread %%%%%%%%%%%%%%%%%%%%%% //
BurnCDThread::BurnCDThread() :
    BurnThread() {
    
}

BurnCDThread::~BurnCDThread() {
    
}

void BurnCDThread::run() {
    // cdrskin -v speed=4 dev=/dev/sr0 -data ./VS2010ProTrialRUS.iso &> cdrskin_dvd.log
    // "Track 01:   62 of 2518 MB written (fifo 100%) [buf  99%]   4.1x. "

    Q_ASSERT(m_data!=0);

    if (!m_data->m_initialized) {
        m_data->m_success = false;
        return ;
    }

    QString program = "cdrskin";
    QStringList arguments;

    arguments  << QLatin1String("-v");
    if (!m_data->m_buffer.isEmpty()) {
        arguments  << QString("fs=%1").arg(m_data->m_buffer);
    }
    if (m_data->m_streamRecording) {
        arguments  << QString("stream_recording=on");
    } else {
        arguments  << QString("stream_recording=off");
    }
    arguments  << QString("speed=%1").arg(m_data->m_speed)
               << QString("dev=%1").arg(m_data->m_device)
               << QLatin1String("-data")
               << QDir::toNativeSeparators(m_data->m_isoFileName);

    QProcess process;

    process.setReadChannel(QProcess::StandardOutput);
    process.start(program, arguments);

    if (!process.waitForStarted()) {
        return ;
    }

    QRegExp startStopRegEx(QLatin1String("cdrskin: thank you for being patient for.*"));
    bool burnStarted = false;

    while ((!process.waitForFinished(500)) &&
           (process.state() == QProcess::Running)) {

        qApp->processEvents();

        if (m_data->m_exit) {
            process.terminate();
            m_data->m_success = false;
        }

        QString output = process.readAll();

        if (!output.isNull()) {
            QStringList list = output.split("\n",QString::SkipEmptyParts);
            QRegExp regExp(QLatin1String("Track.*:.*of.*MB.*written.*\\(fifo.*\\).*\\[buf.*\\].*x."));
            if (list.size() > 0) {
                if (list.last().indexOf(regExp, 0) >= 0) {
                    QString parse = list.last();
                    QRegExp removeRegExp(QLatin1String("Track.*:"));
                    parse.remove(removeRegExp);
                    removeRegExp.setPattern(QLatin1String("MB.*written.*\\(fifo.*\\).*\\[buf.*\\]"));
                    parse.remove(removeRegExp);
                    parse.remove(QLatin1String("of"));
                    QStringList params = parse.split(" ",QString::SkipEmptyParts);
                    if (params.size() >= 3) {
                        int percent = (params.at(params.count()-2).toInt()*1024) / 100;
                        if (percent) {
                            burnStarted = true;

                            int current = (params.at(params.count()-3).toInt()*1024) / percent;
                            emit(progress(current,
                                          QString("Average speed %1").arg(params.at(params.count()-1))));
                        }
                    }
                } else
                if (list.last().indexOf(startStopRegEx) >= 0) {
                    if (burnStarted) {
                        emit(progress(100, QLatin1String("Finishing...")));
                    } else {
                        emit(progress(0, QLatin1String("Starting...")));
                    }
                }
            }
        }
    }

    bool success = true;
    if (process.exitStatus() == QProcess::CrashExit)
        success = false;
    else if (process.exitCode() != 0)
        success = false;

    program = QLatin1String("eject");
    arguments.clear();
    arguments << m_data->m_device;

    process.start(program, arguments);
    if (process.waitForStarted()) {
        while ((!process.waitForFinished(1000)) &&
               (process.state()==QProcess::Running)) {
        }
    }

    if (!m_data->m_exit) {
        m_data->m_success = success;
    }

    return ;
}
