/*
 * Cantata
 *
 * Copyright (c) 2011-2022 Craig Drummond <craig.p.drummond@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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "replaygain.h"
#include "jobcontroller.h"
#include <QCoreApplication>
#include <stdio.h>

// Work-around possible locale issues by forcing usage of '.' as separator
static QString formatDouble(double d)
{
    return QString::number(d, 'f', 10).replace(",", ".");
}

ReplayGain::ReplayGain(const QStringList &fileNames)
    : QObject(0)
    , files(fileNames)
    , lastProgress(-1)
    , totalScanned(0)
{
    TrackScanner::init();
    JobController::self()->setMaxActive(8);
}

ReplayGain::~ReplayGain()
{
    clearScanners();
}

void ReplayGain::scan()
{
    for (int i=0; i<files.count(); ++i) {
        if (scanners.count()<100) {
            createScanner(i);
        } else {
            toScan.append(i);
        }
    }
}

void ReplayGain::createScanner(int index)
{
    TrackScanner *s=new TrackScanner(index);
    s->setFile(files.at(index));
    connect(s, SIGNAL(progress(int)), this, SLOT(scannerProgress(int)));
    connect(s, SIGNAL(done()), this, SLOT(scannerDone()));
    scanners.insert(index, s);
    JobController::self()->add(s);
}

void ReplayGain::clearScanners()
{
    JobController::self()->cancel();
    QMap<int, TrackScanner *>::ConstIterator it(scanners.constBegin());
    QMap<int, TrackScanner *>::ConstIterator end(scanners.constEnd());

    for (; it!=end; ++it) {
        it.value()->stop();
    }
    scanners.clear();
    toScan.clear();
    tracks.clear();
}

void ReplayGain::showProgress()
{
    int finished=0;
    quint64 totalProgress=0;
    QMap<int, Track>::iterator it=tracks.begin();
    QMap<int, Track>::iterator end=tracks.end();

    for (; it!=end; ++it) {
        if ((*it).finished) {
            finished++;
        }
        totalProgress+=(*it).finished ? 100 : (*it).progress;
    }
    int progress=(totalProgress/files.count())+0.5;
    progress=(progress/5)*5;
    if (progress!=lastProgress) {
        lastProgress=progress;
        printf("PROGRESS: %02d\n", lastProgress);
        fflush(stdout);
    }
}

void ReplayGain::showResults()
{
    QList<TrackScanner *> okScanners;
    for (int i=0; i<files.count(); ++i) {
        TrackScanner *s=scanners[i];
        const Track &t=tracks[i];
        if (t.success && s->ok()) {
            printf("TRACK: %d %s %s\n", i, formatDouble(TrackScanner::reference(s->results().loudness)).toLatin1().constData(),
                                           formatDouble(s->results().peakValue()).toLatin1().constData());
            okScanners.append(s);
        } else {
            printf("TRACK: %d FAILED\n", i);
        }
    }

    if (okScanners.isEmpty()) {
        printf("ALBUM: FAILED\n");
    } else {
        TrackScanner::Data album=TrackScanner::global(okScanners);
        printf("ALBUM: %s %s\n", formatDouble(TrackScanner::reference(album.loudness)).toLatin1().constData(),
                                 formatDouble(album.peak).toLatin1().constData());
    }
    fflush(stdout);

    QCoreApplication::exit(0);
}

void ReplayGain::scannerProgress(int p)
{
    TrackScanner *s=qobject_cast<TrackScanner *>(sender());
    if (!s) {
        return;
    }

    tracks[s->index()].progress=p;
    showProgress();
}

void ReplayGain::scannerDone()
{
    TrackScanner *s=qobject_cast<TrackScanner *>(sender());
    if (!s) {
        return;
    }
    Track &track=tracks[s->index()];
    if (!track.finished) {
        track.finished=true;
        track.success=s->success();
        track.progress=100;
        showProgress();
        totalScanned++;
    }

    if (toScan.isEmpty()) {
        if (totalScanned==files.count()) {
            showResults();
        }
    } else {
        int index=toScan.takeAt(0);
        createScanner(index);
    }
}

#include "moc_replaygain.cpp"
