/*
    blueROCK - for digital rock
    Copyright (C) 2019  Dorian Zedler

    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 3 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.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "headers/bluerockbackend.h"

BlueRockBackend::BlueRockBackend(QObject *parent) : QObject(parent), _pendingIntentsChecked(false)
{
    this->_shareUtils = new ShareUtils(this);
    connect(this->_shareUtils, &ShareUtils::otherUrlReceived, this, &BlueRockBackend::openedViaUrl);

#if defined(Q_OS_ANDROID)
    connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(onApplicationStateChanged(Qt::ApplicationState)));
#elif defined Q_OS_IOS
    this->_iosPermissionUtils = new IosPermissionUtils();
#endif
}

QVariant BlueRockBackend::getWidgetData(QVariantMap params) {
    QString requestUrl =  "https://www.digitalrock.de/egroupware/ranking/json.php?";
    QStringList nations = {"ICC", "GER", "SUI"};
    if(params["nation"].toString() == "ICC") {
        params["nation"] = "";
    }
    else if(params["nation"].toString() == "") {
        params.remove("nation");
    }
    else if(!nations.contains(params["nation"].toString())) {
        // a non-empty nation which ist not one of the above is invalid
        return QVariantMap({{"status", 404}});
    }

    for(QVariantMap::const_iterator iter = params.begin(); iter != params.end(); ++iter) {
        requestUrl += iter.key() + "=" + iter.value().toString() + "&";
    }

    requestUrl = requestUrl.left(requestUrl.length() - 1); // remove last '&'

    qWarning() << requestUrl;

    QVariantMap ret = this->_senddata(QUrl(requestUrl));

    if(ret["status"] != 200) {
        // request was a failure
        return QVariantMap({{"status", ret["status"]}, {"data", ""}});
    }

    QJsonDocument jsonReply = QJsonDocument::fromJson(ret["text"].toString().toUtf8());

    QVariantMap data = {{"status", 200}, {"data", jsonReply.toVariant()}};

    return data;
}


QVariantMap BlueRockBackend::getParamsFromUrl(QString stringUrl) {
    stringUrl = stringUrl.replace("#!", "?");
    QUrl url(stringUrl);

    if(!url.isValid() || url.isEmpty() || url.host().isEmpty())
        return {{"valid", false},{"params", QVariantMap()}} ;

    QStringList domainFragments = url.host().split(".");
    QString tld = domainFragments.takeLast();
    QString domainName = domainFragments.takeLast();
    QString baseDomain = domainName + "." + tld;

    if(!this->_validBaseDomains.contains(baseDomain))
        return {{"valid", false},{"params", QVariantMap()}};

    QUrlQuery query(url.query());

    QVariantMap params;

    for(QPair<QString, QString> pair : query.queryItems()) {
        if(params.contains(pair.first))
            params[pair.first] = pair.second;
        else
            params.insert(pair.first, pair.second);
    }

    return {{"valid", true},{"params",params}};
}

void BlueRockBackend::shareResultsAsUrl(QString url, QString compName) {
    //% "Check out the results of %1 over here:"
    this->_shareUtils->shareText(qtTrId("#shareResultsLinkText").arg(compName) + " \n", url);
}

void BlueRockBackend::shareResultsAsPoster(QString url, QString compName) {
    QString path = this->_shareUtils->getTemporaryFileLocationPath(); //QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
    if (!QDir(path).exists()) {
        if (QDir("").mkpath(path)) {
            qDebug() << "Created app data /files directory. " << path;
        } else {
            qWarning() << "Failed to create app data /files directory. " << path;
            return;
        }
    }

    QString rawCompName = compName;
    QString escapedCompName = compName.replace("/", " ");
    path += "/" + escapedCompName + ".pdf";

    QFile file(path);
    file.remove();
    if(!file.open(QIODevice::ReadWrite)) {
        qWarning("Could not open File for writing!!");
        return;
    }

    // dimensions
    QRect qrCodeRect = QRect(414, 414, 1650, 1650);

    int compNameTextLineHeight = 64;
    QFont compNameTextFont("OpenSans-Light");
    compNameTextFont.setPixelSize(compNameTextLineHeight);
    QRect compNameTextRect = QRect(
                                 324,
                                 2500,
                                 1835,
                                 150
                             );

    QPdfWriter writer(&file);
    writer.setPageSize(QPageSize(QPageSize::A4));
    writer.setPageMargins(QMargins(0, 0, 0, 0));
    writer.setResolution(300);

    QPainter painter(&writer);
    QPixmap posterTemplate(":/PosterTemplate.png");
    painter.drawPixmap(0,0, writer.width(), writer.height(), posterTemplate);

    QPixmap barcode;
    QZXingEncoderConfig encoderConfig(QZXing::EncoderFormat_QR_CODE, qrCodeRect.size(), QZXing::EncodeErrorCorrectionLevel_H, false, false);
    barcode.convertFromImage(QZXing::encodeData(url, encoderConfig));
    painter.drawPixmap(qrCodeRect, barcode);

    painter.setFont(compNameTextFont);
    painter.setPen(Qt::black);
    painter.drawText(compNameTextRect, Qt::AlignLeft|Qt::AlignBottom|Qt::TextWordWrap, rawCompName);

    painter.end();
    file.close();

    this->_shareUtils->sendFile(path, escapedCompName, "application/pdf", 1);
}

bool BlueRockBackend::isCameraPermissionGranted() {
#ifdef Q_OS_ANDROID
    QtAndroid::PermissionResult cameraAccess = QtAndroid::checkPermission("android.permission.CAMERA");
    return cameraAccess == QtAndroid::PermissionResult::Granted;
#elif defined Q_OS_IOS
    return this->_iosPermissionUtils->isCameraPermissionGranted();
#else
    return true;
#endif
}

bool BlueRockBackend::requestCameraPermission() {
    if(this->isCameraPermissionGranted())
        return true;

#ifdef Q_OS_ANDROID
    // try to get permission
    QtAndroid::PermissionResultMap resultMap = QtAndroid::requestPermissionsSync({"android.permission.CAMERA"});
    bool resultBool = true;
    for(QtAndroid::PermissionResult result : resultMap) {
        if(result != QtAndroid::PermissionResult::Granted) {
            resultBool = false;
        }
    }

    if(resultBool) {
        return true;
    }

    // getting permission the traditional way failed -> open the settings app
    QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;");
    if (activity.isValid())
    {
        // get the package name
        QAndroidJniObject context = QtAndroid::androidContext();
        QAndroidJniObject applicationPackageName = context.callObjectMethod<jstring>("getPackageName");

        QAndroidJniObject param = QAndroidJniObject::fromString("package:" + applicationPackageName.toString());

        // Equivalent to Jave code: 'Uri uri = Uri::parse("...");'
        QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", param.object<jstring>());
        if (!uri.isValid()) {
            qWarning("ERROR: Unable to create Uri object");
            return false;
        }
        QAndroidJniObject packageName = QAndroidJniObject::fromString("android.settings.APPLICATION_DETAILS_SETTINGS");

        QAndroidJniObject intent("android/content/Intent","(Ljava/lang/String;)V", packageName.object<jstring>());
        if (!intent.isValid()) {
            qWarning("ERROR: Unable to create Intent object");
            return false;
        }
        intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;", QAndroidJniObject::fromString("android.intent.category.DEFAULT").object<jstring>());
        intent.callObjectMethod("setData", "(Landroid/net/Uri;)Landroid/content/Intent;", uri.object<jobject>());

        activity.callMethod<void>("startActivity","(Landroid/content/Intent;)V",intent.object<jobject>());
    }
    else {
        qWarning() << "ERROR: Activity not valid!";
        return false;
    }

    return false;
#elif defined Q_OS_IOS
    return this->_iosPermissionUtils->requestCameraPermission();
#else
    return true;
#endif

}

// ------------------------
// --- Helper functions ---
// ------------------------

QVariantMap BlueRockBackend::_senddata(QUrl serviceUrl, QUrlQuery pdata)
{
    // create network manager
    QNetworkAccessManager * networkManager = new QNetworkAccessManager();

    QVariantMap ret; //this is a custom type to store the return-data

    // Create network request
    QNetworkRequest request(serviceUrl);
    request.setHeader(QNetworkRequest::ContentTypeHeader,
                      "application/x-www-form-urlencoded");

    //QSslConfiguration config = QSslConfiguration::defaultConfiguration();
    //config.setProtocol(QSsl::TlsV1_2);
    //request.setSslConfiguration(config);

    //send a POST request with the given url and data to the server

    QNetworkReply *reply;

    if(pdata.isEmpty()) {
        // if no post data is given -> send a GET request
        reply = networkManager->get(request);
    }
    else {
        // if post data is given -> send POST request
        reply = networkManager->post(request, pdata.toString(QUrl::FullyEncoded).toUtf8());
    }

    // loop to wait until the request has finished before processing the data
    QEventLoop loop;
    // timer to cancel the request after 3 seconds
    QTimer timer;
    timer.setSingleShot(true);

    // quit the loop when the request finised
    loop.connect(networkManager, SIGNAL(finished(QNetworkReply*)), SLOT(quit()));
    // or the timer timed out
    loop.connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
    // start the timer
    timer.start(10000);
    // start the loop
    loop.exec();

    //get the status code
    QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);

    ret.insert("status", status_code.toInt());

    //get the full text response
    ret.insert("text", QString::fromUtf8(reply->readAll()));

    // delete the reply object
    delete reply;

    // delete the newtwork access manager object
    delete networkManager;

    //return the data
    return(ret);
}

#if defined(Q_OS_ANDROID)
void BlueRockBackend::onApplicationStateChanged(Qt::ApplicationState applicationState)
{
    qDebug() << "S T A T E changed into: " << applicationState;
    if(applicationState == Qt::ApplicationState::ApplicationSuspended) {
        // nothing to do
        return;
    }
    if(applicationState == Qt::ApplicationState::ApplicationActive) {
        // if App was launched from VIEW or SEND Intent
        // there's a race collision: the event will be lost,
        // because App and UI wasn't completely initialized
        // workaround: QShareActivity remembers that an Intent is pending
        if(!_pendingIntentsChecked) {
            _pendingIntentsChecked = true;
            _shareUtils->checkPendingIntents(this->_shareUtils->getTemporaryFileLocationPath());
        }
    }
}
#endif

// -------------------------
// --- Functions for QML ---
// -------------------------
