<commit_before>/***
 * Copyright (c) 2013, Dan Hasting
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the organization nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ***/

#include "thegamesdbscraper.h"

#include "../global.h"
#include "../common.h"

#include <QDir>
#include <QEventLoop>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QMessageBox>
#include <QTextStream>
#include <QTimer>
#include <QUrl>

#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>

TheGamesDBScraper::TheGamesDBScraper(QWidget *parent, bool force) : QObject(parent)
{
    this->parent = parent;
    this->force = force;
    this->keepGoing = true;
}

QString TheGamesDBScraper::convertIDs(QJsonObject foundGame, QString typeName, QString listName)
{
    QJsonArray idArray = foundGame.value(typeName).toArray();

    QString cacheFileString = getDataLocation() + "/cache_v2/" + typeName + ".json";
    QFile cacheFile(cacheFileString);

    cacheFile.open(QIODevice::ReadOnly);
    QString data = cacheFile.readAll();
    cacheFile.close();

    QJsonDocument document = QJsonDocument::fromJson(data.toUtf8());
    QJsonObject cache = document.object();

    QString result = "";

    foreach (QJsonValue id, idArray)
    {
        QString entryID = QString::number(id.toInt());
        QString entryName = cache.value(entryID).toObject().value("name").toString();

        if (entryName == "") {
            updateListCache(&cacheFile, listName);
            cacheFile.open(QIODevice::ReadOnly);
            data = cacheFile.readAll();
            cacheFile.close();

            document = QJsonDocument::fromJson(data.toUtf8());
            entryName = cache.value(entryID).toObject().value("name").toString();
        }

        if (entryName != "")
            result += entryName + ", ";
    }

    int pos = result.lastIndexOf(QChar(','));
    return result.left(pos);
}

void TheGamesDBScraper::deleteGameInfo(QString fileName, QString identifier)
{
    QString text;
    text = QString(tr("NOTE: If you are deleting this game's information because the game doesn't "))
                 + tr("exist on TheGamesDB and <AppName> pulled the information for different game, it's ")
                 + tr("better to create an account on")+" TheGamesDB "
                 + tr("and add the game so other users can benefit as well.")
                 + "

"
                 + tr("This will cause <AppName> to not update the information for this game until you ")
                 + tr("force it with \"Download/Update Info...\"")
                 + "

"
                 + tr("Delete the current information for") + " " + fileName + "?";
    text.replace("<AppName>",AppName);

    int answer = QMessageBox::question(parent, tr("Delete Game Information"), text,
                                       QMessageBox::Yes | QMessageBox::No);

    if (answer == QMessageBox::Yes) {
        QString gameCache = getDataLocation() + "/cache_v2/" + identifier.toLower();

        QString dataFile = gameCache + "/data.xml";
        QFile file(dataFile);

        // Remove game information
        file.open(QIODevice::WriteOnly);
        QTextStream stream(&file);
        stream << "NULL";
        file.close();

        // Remove cover image
        QString coverFile = gameCache + "/boxart-front.";

        QFile coverJPG(coverFile + "jpg");
        QFile coverPNG(coverFile + "png");

        if (coverJPG.exists())
            coverJPG.remove();
        if (coverPNG.exists())
            coverPNG.remove();

        coverJPG.open(QIODevice::WriteOnly);
        QTextStream streamImage(&coverJPG);
        streamImage << "";
        coverJPG.close();
    }
}

void TheGamesDBScraper::downloadGameInfo(QString identifier, QString searchName, QString gameID)
{
    if (keepGoing && identifier != "") {
        if (force) parent->setEnabled(false);

        bool updated = false;

        QString gameCache = getDataLocation() + "/cache_v2/" + identifier.toLower();
        QDir cache(gameCache);

        if (!cache.exists()) {
            cache.mkpath(gameCache);
        }

        QString genreCache = getDataLocation() + "/cache_v2/genres.json";
        QFile genres(genreCache);
        if (!genres.exists())
            updateListCache(&genres, "Genres");

        QString developerCache = getDataLocation() + "/cache_v2/developers.json";
        QFile developers(developerCache);
        if (!developers.exists())
            updateListCache(&developers, "Developers");

        QString publisherCache = getDataLocation() + "/cache_v2/publishers.json";
        QFile publishers(publisherCache);
        if (!publishers.exists())
            updateListCache(&publishers, "Publishers");

        //Get game JSON info from thegamesdb.net
        QString dataFile = gameCache + "/data.json";
        QFile file(dataFile);

        if (!file.exists() || file.size() == 0 || force) {
            QUrl url;

            //Remove [!], (U), etc. from GoodName for searching
            searchName.remove(QRegExp("\\W*(\\(|\\[).+(\\)|\\])\\W*"));

            //Few game specific hacks
            //TODO: Contact thegamesdb.net and see if these can be fixed on their end
            if (searchName == "Legend of Zelda, The - Majora's Mask")
                searchName = "Majora's Mask";
            else if (searchName == "Legend of Zelda, The - Ocarina of Time" ||
                     searchName == "THE LEGEND OF ZELDA")
                searchName = "The Legend of Zelda: Ocarina of Time";
            else if (searchName == "Tsumi to Batsu - Hoshi no Keishousha")
                searchName = "Sin and Punishment";
            else if (searchName == "1080 Snowboarding")
                searchName = "1080: TenEighty Snowboarding";
            else if (searchName == "Extreme-G XG2")
                searchName = "Extreme-G 2";
            else if (searchName.contains("Pokemon"))
                searchName.replace("Pokemon", "Pokémon");
            else if (searchName.toLower() == "f-zero x")
                gameID = "10836";

            QString apiFilter = "&filter[platform]=3&include=boxart&fields=game_title,release_date,";
            apiFilter += "developers,publishers,genres,overview,rating,players";

            //If user submits gameID, use that
            if (gameID != "")
                url.setUrl("https://api.thegamesdb.net/Games/ByGameID?apikey=" + TheGamesDBAPIKey + "&id="
                           + gameID + apiFilter);
            else
                url.setUrl("https://api.thegamesdb.net/Games/ByGameName?apikey=" + TheGamesDBAPIKey + "&name="
                           + searchName + apiFilter);

            QString data = getUrlContents(url);

            QJsonDocument document = QJsonDocument::fromJson(data.toUtf8());
            QJsonObject json = document.object();

            if (json.value("code").toInt() != 200 && json.value("code").toInt() != 0) {
                QString status = json.value("status").toString();
                QString message;
                message = QString(tr("The following error from TheGamesDB occured while downloading:"))
                                   + "

" + status + "

";
                showError(message);
                if (force) parent->setEnabled(true);
                return;
            }

            QJsonValue games = json.value("data").toObject().value("games");
            QJsonArray gamesArray = games.toArray();

            int count = 0, found = 0;

            foreach (QJsonValue game, gamesArray)
            {
                QJsonValue title = game.toObject().value("game_title");

                if (force) { //from user dialog
                    QJsonValue date = game.toObject().value("release_date");

                    QString check = "Game: " + title.toString();
                    check.remove(QRegExp(QString("[^A-Za-z 0-9 \\.,\\?'""!@#\\$%\\^&\\*\\")
                                         + "(\\)-_=\\+;:<>\\/\\\\|\\}\\{\\[\\]`~]*"));
                    if (date.toString() != "") check += "\n" + tr("Released on: ") + date.toString();
                    check += "\n\n" + tr("Does this look correct?");

                    int answer = QMessageBox::question(parent, QObject::tr("Game Information Download"),
                                                       check, QMessageBox::Yes | QMessageBox::No);

                    if (answer == QMessageBox::Yes) {
                        found = count;
                        updated = true;
                        break;
                    }
                } else {
                    //We only want one game, so search for a perfect match in the GameTitle element.
                    //Otherwise this will default to 0 (the first game found)
                    if(title.toString() == searchName)
                        found = count;
                }

                count++;
            }

            if (!force || updated) {
                QJsonObject foundGame = gamesArray.at(found).toObject();
                QJsonObject saveData;

                QString gameID = QString::number(foundGame.value("id").toInt());
                QJsonObject boxart = json.value("include").toObject().value("boxart").toObject();

                QString thumbURL = boxart.value("base_url").toObject().value("thumb").toString();
                QJsonArray imgArray = boxart.value("data").toObject().value(gameID).toArray();

                QString frontImg = "";

                foreach (QJsonValue img, imgArray)
                {
                    QString type = img.toObject().value("type").toString();
                    QString side = img.toObject().value("side").toString();
                    QString filename = img.toObject().value("filename").toString();

                    if (type == "boxart" && side == "front")
                        frontImg = thumbURL + filename;
                }

                //Convert IDs from API to text names
                QString genresString = convertIDs(foundGame, "genres", "Genres");
                QString developerString = convertIDs(foundGame, "developers", "Developers");
                QString publisherString = convertIDs(foundGame, "publishers", "Publishers");

                saveData.insert("game_title", foundGame.value("game_title").toString());
                saveData.insert("release_date", foundGame.value("release_date").toString());
                saveData.insert("rating", foundGame.value("rating").toString());
                saveData.insert("overview", foundGame.value("overview").toString());
                saveData.insert("players", QString::number(foundGame.value("players").toInt()));
                saveData.insert("boxart", frontImg);
                saveData.insert("genres", genresString);
                saveData.insert("developer", developerString);
                saveData.insert("publisher", publisherString);

                QJsonDocument document(saveData);

                file.open(QIODevice::WriteOnly);
                file.write(document.toJson());
                file.close();
            }

            if (force && !updated) {
                QString message;

                if (count == 0)
                    message = QObject::tr("No results found.");
                else
                    message = QObject::tr("No more results found.");

                QMessageBox::information(parent, QObject::tr("Game Information Download"), message);
            }
        }

        //Get front cover
        QString boxartURL = "";
        QString boxartExt = "";
        QString coverFile = gameCache + "/boxart-front.";

        QFile coverJPG(coverFile + "jpg");
        QFile coverPNG(coverFile + "png");

        if ((!coverJPG.exists() && !coverPNG.exists()) || (force && updated)) {
            file.open(QIODevice::ReadOnly);
            QString data = file.readAll();
            file.close();

            QJsonDocument document = QJsonDocument::fromJson(data.toUtf8());
            QJsonObject json = document.object();
            QString boxartURL = json.value("boxart").toString();

            if (boxartURL != "") {
                QUrl url(boxartURL);

                //Delete current box art
                QFile::remove(coverFile + "jpg");
                QFile::remove(coverFile + "png");

                //Check to save as JPG or PNG
                boxartExt = QFileInfo(boxartURL).completeSuffix().toLower();
                QFile cover(coverFile + boxartExt);

                cover.open(QIODevice::WriteOnly);
                cover.write(getUrlContents(url));
                cover.close();
            }
        }

        if (updated)
            QMessageBox::information(parent, QObject::tr("Game Information Download"),
                                     QObject::tr("Download Complete!"));

        if (force) parent->setEnabled(true);
    }
}

QByteArray TheGamesDBScraper::getUrlContents(QUrl url)
{
    QNetworkAccessManager *manager = new QNetworkAccessManager;

    QNetworkRequest request;
    request.setUrl(url);
    request.setRawHeader("User-Agent", AppName.toUtf8().constData());
    QNetworkReply *reply = manager->get(request);

    QTimer timer;
    timer.setSingleShot(true);

    QEventLoop loop;
    connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));

    int time = SETTINGS.value("Other/networktimeout", 10).toInt();
    if (time == 0) time = 10;
    time *= 1000;

    timer.start(time);
    loop.exec();

    if(timer.isActive()) { //Got reply
        timer.stop();

        if(reply->error() > 0)
            showError(reply->errorString());
        else
            return reply->readAll();

    } else //Request timed out
        showError(tr("Request timed out. Check your network settings."));

    return QByteArray();
}

void TheGamesDBScraper::showError(QString error)
{
    QString question = "\n\n" + tr("Continue scraping information?");

    if (force)
        QMessageBox::information(parent, tr("Network Error"), error);
    else {
        int answer = QMessageBox::question(parent, tr("Network Error"), error + question,
                                           QMessageBox::Yes | QMessageBox::No);

        if (answer == QMessageBox::No)
            keepGoing = false;
    }
}

void TheGamesDBScraper::updateListCache(QFile *file, QString list)
{
    QUrl url;
    url.setUrl("https://api.thegamesdb.net/" + list + "?apikey=" + TheGamesDBAPIKey);
    QString data = getUrlContents(url);
    QJsonDocument document = QJsonDocument::fromJson(data.toUtf8());
    QJsonDocument result(document.object().value("data").toObject().value(list.toLower()).toObject());

    file->open(QIODevice::WriteOnly);
    file->write(result.toJson());
    file->close();
}
<commit_msg>Fix a small issue<commit_after>/***
 * Copyright (c) 2013, Dan Hasting
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the organization nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ***/

#include "thegamesdbscraper.h"

#include "../global.h"
#include "../common.h"

#include <QDir>
#include <QEventLoop>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QMessageBox>
#include <QTextStream>
#include <QTimer>
#include <QUrl>

#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>

TheGamesDBScraper::TheGamesDBScraper(QWidget *parent, bool force) : QObject(parent)
{
    this->parent = parent;
    this->force = force;
    this->keepGoing = true;
}

QString TheGamesDBScraper::convertIDs(QJsonObject foundGame, QString typeName, QString listName)
{
    QJsonArray idArray = foundGame.value(typeName).toArray();

    QString cacheFileString = getDataLocation() + "/cache_v2/" + typeName + ".json";
    QFile cacheFile(cacheFileString);

    cacheFile.open(QIODevice::ReadOnly);
    QString data = cacheFile.readAll();
    cacheFile.close();

    QJsonDocument document = QJsonDocument::fromJson(data.toUtf8());
    QJsonObject cache = document.object();

    QString result = "";

    foreach (QJsonValue id, idArray)
    {
        QString entryID = QString::number(id.toInt());
        QString entryName = cache.value(entryID).toObject().value("name").toString();

        if (entryName == "") {
            updateListCache(&cacheFile, listName);
            cacheFile.open(QIODevice::ReadOnly);
            data = cacheFile.readAll();
            cacheFile.close();

            document = QJsonDocument::fromJson(data.toUtf8());
            entryName = cache.value(entryID).toObject().value("name").toString();
        }

        if (entryName != "")
            result += entryName + ", ";
    }

    int pos = result.lastIndexOf(QChar(','));
    return result.left(pos);
}

void TheGamesDBScraper::deleteGameInfo(QString fileName, QString identifier)
{
    QString text;
    text = QString(tr("NOTE: If you are deleting this game's information because the game doesn't "))
                 + tr("exist on TheGamesDB and <AppName> pulled the information for different game, it's ")
                 + tr("better to create an account on")+" TheGamesDB "
                 + tr("and add the game so other users can benefit as well.")
                 + "

"
                 + tr("This will cause <AppName> to not update the information for this game until you ")
                 + tr("force it with \"Download/Update Info...\"")
                 + "

"
                 + tr("Delete the current information for") + " " + fileName + "?";
    text.replace("<AppName>",AppName);

    int answer = QMessageBox::question(parent, tr("Delete Game Information"), text,
                                       QMessageBox::Yes | QMessageBox::No);

    if (answer == QMessageBox::Yes) {
        QString gameCache = getDataLocation() + "/cache_v2/" + identifier.toLower();

        QString dataFile = gameCache + "/data.xml";
        QFile file(dataFile);

        // Remove game information
        file.open(QIODevice::WriteOnly);
        QTextStream stream(&file);
        stream << "NULL";
        file.close();

        // Remove cover image
        QString coverFile = gameCache + "/boxart-front.";

        QFile coverJPG(coverFile + "jpg");
        QFile coverPNG(coverFile + "png");

        if (coverJPG.exists())
            coverJPG.remove();
        if (coverPNG.exists())
            coverPNG.remove();

        coverJPG.open(QIODevice::WriteOnly);
        QTextStream streamImage(&coverJPG);
        streamImage << "";
        coverJPG.close();
    }
}

void TheGamesDBScraper::downloadGameInfo(QString identifier, QString searchName, QString gameID)
{
    if (keepGoing && identifier != "") {
        if (force) parent->setEnabled(false);

        bool updated = false;

        QString gameCache = getDataLocation() + "/cache_v2/" + identifier.toLower();
        QDir cache(gameCache);

        if (!cache.exists()) {
            cache.mkpath(gameCache);
        }

        QString genreCache = getDataLocation() + "/cache_v2/genres.json";
        QFile genres(genreCache);
        if (!genres.exists())
            updateListCache(&genres, "Genres");

        QString developerCache = getDataLocation() + "/cache_v2/developers.json";
        QFile developers(developerCache);
        if (!developers.exists())
            updateListCache(&developers, "Developers");

        QString publisherCache = getDataLocation() + "/cache_v2/publishers.json";
        QFile publishers(publisherCache);
        if (!publishers.exists())
            updateListCache(&publishers, "Publishers");

        //Get game JSON info from thegamesdb.net
        QString dataFile = gameCache + "/data.json";
        QFile file(dataFile);

        if (!file.exists() || file.size() == 0 || force) {
            QUrl url;

            //Remove [!], (U), etc. from GoodName for searching
            searchName.remove(QRegExp("\\W*(\\(|\\[).+(\\)|\\])\\W*"));

            //Few game specific hacks
            //TODO: Contact thegamesdb.net and see if these can be fixed on their end
            if (searchName == "Legend of Zelda, The - Majora's Mask")
                searchName = "Majora's Mask";
            else if (searchName == "Legend of Zelda, The - Ocarina of Time" ||
                     searchName == "THE LEGEND OF ZELDA")
                searchName = "The Legend of Zelda: Ocarina of Time";
            else if (searchName == "Tsumi to Batsu - Hoshi no Keishousha")
                searchName = "Sin and Punishment";
            else if (searchName == "1080 Snowboarding")
                searchName = "1080: TenEighty Snowboarding";
            else if (searchName == "Extreme-G XG2")
                searchName = "Extreme-G 2";
            else if (searchName.contains("Pokemon"))
                searchName.replace("Pokemon", "Pokémon");
            else if (searchName.toLower() == "f-zero x")
                gameID = "10836";

            QString apiFilter = "&filter[platform]=3&include=boxart&fields=game_title,release_date,";
            apiFilter += "developers,publishers,genres,overview,rating,players";

            //If user submits gameID, use that
            if (gameID != "")
                url.setUrl("https://api.thegamesdb.net/Games/ByGameID?apikey=" + TheGamesDBAPIKey + "&id="
                           + gameID + apiFilter);
            else
                url.setUrl("https://api.thegamesdb.net/Games/ByGameName?apikey=" + TheGamesDBAPIKey + "&name="
                           + searchName + apiFilter);

            QString data = getUrlContents(url);

            QJsonDocument document = QJsonDocument::fromJson(data.toUtf8());
            QJsonObject json = document.object();

            if (json.value("code").toInt() != 200 && json.value("code").toInt() != 0) {
                QString status = json.value("status").toString();
                QString message;
                message = QString(tr("The following error from TheGamesDB occured while downloading:"))
                                   + "

" + status + "

";
                showError(message);
                if (force) parent->setEnabled(true);
                return;
            }

            QJsonValue games = json.value("data").toObject().value("games");
            QJsonArray gamesArray = games.toArray();

            int count = 0, found = 0;

            foreach (QJsonValue game, gamesArray)
            {
                QJsonValue title = game.toObject().value("game_title");

                if (force) { //from user dialog
                    QJsonValue date = game.toObject().value("release_date");

                    QString check = "Game: " + title.toString();
                    check.remove(QRegExp(QString("[^A-Za-z 0-9 \\.,\\?'""!@#\\$%\\^&\\*\\")
                                         + "(\\)-_=\\+;:<>\\/\\\\|\\}\\{\\[\\]`~]*"));
                    if (date.toString() != "") check += "\n" + tr("Released on: ") + date.toString();
                    check += "\n\n" + tr("Does this look correct?");

                    int answer = QMessageBox::question(parent, QObject::tr("Game Information Download"),
                                                       check, QMessageBox::Yes | QMessageBox::No);

                    if (answer == QMessageBox::Yes) {
                        found = count;
                        updated = true;
                        break;
                    }
                } else {
                    //We only want one game, so search for a perfect match in the GameTitle element.
                    //Otherwise this will default to 0 (the first game found)
                    if(title.toString() == searchName)
                        found = count;
                }

                count++;
            }

            if (!force || updated) {
                QJsonObject foundGame = gamesArray.at(found).toObject();
                QJsonObject saveData;

                QString gameID = QString::number(foundGame.value("id").toInt());
                QJsonObject boxart = json.value("include").toObject().value("boxart").toObject();

                QString thumbURL = boxart.value("base_url").toObject().value("thumb").toString();
                QJsonArray imgArray = boxart.value("data").toObject().value(gameID).toArray();

                QString frontImg = "";

                foreach (QJsonValue img, imgArray)
                {
                    QString type = img.toObject().value("type").toString();
                    QString side = img.toObject().value("side").toString();
                    QString filename = img.toObject().value("filename").toString();

                    if (type == "boxart" && side == "front")
                        frontImg = thumbURL + filename;
                }

                //Convert IDs from API to text names
                QString genresString = convertIDs(foundGame, "genres", "Genres");
                QString developerString = convertIDs(foundGame, "developers", "Developers");
                QString publisherString = convertIDs(foundGame, "publishers", "Publishers");

                QString players = QString::number(foundGame.value("players").toInt());
                if (players == "0") players = "";

                saveData.insert("game_title", foundGame.value("game_title").toString());
                saveData.insert("release_date", foundGame.value("release_date").toString());
                saveData.insert("rating", foundGame.value("rating").toString());
                saveData.insert("overview", foundGame.value("overview").toString());
                saveData.insert("players", players);
                saveData.insert("boxart", frontImg);
                saveData.insert("genres", genresString);
                saveData.insert("developer", developerString);
                saveData.insert("publisher", publisherString);

                QJsonDocument document(saveData);

                file.open(QIODevice::WriteOnly);
                file.write(document.toJson());
                file.close();
            }

            if (force && !updated) {
                QString message;

                if (count == 0)
                    message = QObject::tr("No results found.");
                else
                    message = QObject::tr("No more results found.");

                QMessageBox::information(parent, QObject::tr("Game Information Download"), message);
            }
        }

        //Get front cover
        QString boxartURL = "";
        QString boxartExt = "";
        QString coverFile = gameCache + "/boxart-front.";

        QFile coverJPG(coverFile + "jpg");
        QFile coverPNG(coverFile + "png");

        if ((!coverJPG.exists() && !coverPNG.exists()) || (force && updated)) {
            file.open(QIODevice::ReadOnly);
            QString data = file.readAll();
            file.close();

            QJsonDocument document = QJsonDocument::fromJson(data.toUtf8());
            QJsonObject json = document.object();
            QString boxartURL = json.value("boxart").toString();

            if (boxartURL != "") {
                QUrl url(boxartURL);

                //Delete current box art
                QFile::remove(coverFile + "jpg");
                QFile::remove(coverFile + "png");

                //Check to save as JPG or PNG
                boxartExt = QFileInfo(boxartURL).completeSuffix().toLower();
                QFile cover(coverFile + boxartExt);

                cover.open(QIODevice::WriteOnly);
                cover.write(getUrlContents(url));
                cover.close();
            }
        }

        if (updated)
            QMessageBox::information(parent, QObject::tr("Game Information Download"),
                                     QObject::tr("Download Complete!"));

        if (force) parent->setEnabled(true);
    }
}

QByteArray TheGamesDBScraper::getUrlContents(QUrl url)
{
    QNetworkAccessManager *manager = new QNetworkAccessManager;

    QNetworkRequest request;
    request.setUrl(url);
    request.setRawHeader("User-Agent", AppName.toUtf8().constData());
    QNetworkReply *reply = manager->get(request);

    QTimer timer;
    timer.setSingleShot(true);

    QEventLoop loop;
    connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));

    int time = SETTINGS.value("Other/networktimeout", 10).toInt();
    if (time == 0) time = 10;
    time *= 1000;

    timer.start(time);
    loop.exec();

    if(timer.isActive()) { //Got reply
        timer.stop();

        if(reply->error() > 0)
            showError(reply->errorString());
        else
            return reply->readAll();

    } else //Request timed out
        showError(tr("Request timed out. Check your network settings."));

    return QByteArray();
}

void TheGamesDBScraper::showError(QString error)
{
    QString question = "\n\n" + tr("Continue scraping information?");

    if (force)
        QMessageBox::information(parent, tr("Network Error"), error);
    else {
        int answer = QMessageBox::question(parent, tr("Network Error"), error + question,
                                           QMessageBox::Yes | QMessageBox::No);

        if (answer == QMessageBox::No)
            keepGoing = false;
    }
}

void TheGamesDBScraper::updateListCache(QFile *file, QString list)
{
    QUrl url;
    url.setUrl("https://api.thegamesdb.net/" + list + "?apikey=" + TheGamesDBAPIKey);
    QString data = getUrlContents(url);
    QJsonDocument document = QJsonDocument::fromJson(data.toUtf8());
    QJsonDocument result(document.object().value("data").toObject().value(list.toLower()).toObject());

    file->open(QIODevice::WriteOnly);
    file->write(result.toJson());
    file->close();
}
<|endoftext|>


<commit_before>/******************************************************************
*
* Round for C++
*
* Copyright (C) Satoshi Konno 2015
*
* This is licensed under BSD-style license, see file COPYING.
*
******************************************************************/

#include <sstream>
#include <boost/algorithm/string/replace.hpp>

#include <round/common/encoding/Base64.h>
#include <round/core/Log.h>
#include <round/script/Lua.h>

#if defined(ROUND_SUPPORT_TCL)

const std::string Round::LuaEngine::LANGUAGE = "lua";

////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////

Round::LuaEngine::LuaEngine() : ScriptEngine(LANGUAGE) {
  this->luaState = luaL_newstate();
  luaL_openlibs(this->luaState);
}

////////////////////////////////////////////////
// Destructor
////////////////////////////////////////////////

Round::LuaEngine::~LuaEngine() {
  lua_close(this->luaState);
}

////////////////////////////////////////////////
// compile
////////////////////////////////////////////////

bool Round::LuaEngine::compile(const Script *luaScript) const {
  const byte *scriptCode = luaScript->getCode();
  int loadingResult = luaL_loadstring(this->luaState, (const char *)scriptCode);
  lua_settop(this->luaState, 0);
  return (loadingResult == 0) ? true : false;;
}

////////////////////////////////////////////////
// run
////////////////////////////////////////////////

bool Round::LuaEngine::run(const Script *luaScript, const std::string &params, std::string *results, Error *error) const {
  if (luaL_loadstring(this->luaState, (const char *)luaScript->getCode()) != 0) {
    RPC::JSON::ErrorCodeToError(RPC::JSON::ErrorCodeInternalError, error);
    return false;
  }

  lua_getglobal(this->luaState, luaScript->getName().c_str());
  lua_pushstring(this->luaState, params.c_str());

  int callResult = lua_pcall(this->luaState, 1, 1, 0);
  if (callResult == 0) {
    *results = lua_tostring(this->luaState, -1);
  }
  else {
    RPC::JSON::ErrorCodeToError(RPC::JSON::ErrorCodeInternalError, error);
    error->setMessage(lua_tostring(this->luaState, -1));
  }

  lua_pop(this->luaState, 2);

  return (callResult == 0) ? true : false;
}

#endif
<commit_msg>* Updated LuaEngine::run().<commit_after>/******************************************************************
*
* Round for C++
*
* Copyright (C) Satoshi Konno 2015
*
* This is licensed under BSD-style license, see file COPYING.
*
******************************************************************/

#include <sstream>
#include <boost/algorithm/string/replace.hpp>

#include <round/common/encoding/Base64.h>
#include <round/core/Log.h>
#include <round/script/Lua.h>

#if defined(ROUND_SUPPORT_TCL)

const std::string Round::LuaEngine::LANGUAGE = "lua";

////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////

Round::LuaEngine::LuaEngine() : ScriptEngine(LANGUAGE) {
  this->luaState = luaL_newstate();
  luaL_openlibs(this->luaState);
}

////////////////////////////////////////////////
// Destructor
////////////////////////////////////////////////

Round::LuaEngine::~LuaEngine() {
  lua_close(this->luaState);
}

////////////////////////////////////////////////
// compile
////////////////////////////////////////////////

bool Round::LuaEngine::compile(const Script *luaScript) const {
  const byte *scriptCode = luaScript->getCode();
  int loadingResult = luaL_loadstring(this->luaState, (const char *)scriptCode);
  lua_settop(this->luaState, 0);
  return (loadingResult == 0) ? true : false;;
}

////////////////////////////////////////////////
// run
////////////////////////////////////////////////

bool Round::LuaEngine::run(const Script *luaScript, const std::string &params, std::string *results, Error *error) const {
  int nStack = lua_gettop(this->luaState);

  if (luaL_loadstring(this->luaState, (const char *)luaScript->getCode()) != 0) {
    RPC::JSON::ErrorCodeToError(RPC::JSON::ErrorCodeInternalError, error);
    return false;
  }

  nStack = lua_gettop(this->luaState);

  if(lua_pcall(this->luaState, 0, 0, 0) != 0) {
    RPC::JSON::ErrorCodeToError(RPC::JSON::ErrorCodeInternalError, error);
    error->setMessage(lua_tostring(this->luaState, -1));
    lua_pop(this->luaState, 1);
    return false;
  }

  nStack = lua_gettop(this->luaState);

  lua_getglobal(this->luaState, luaScript->getName().c_str());
  lua_pushstring(this->luaState, params.c_str());

  nStack = lua_gettop(this->luaState);

  int callResult = lua_pcall(this->luaState, 1, 1, 0);
  if (callResult == 0) {
    *results = lua_tostring(this->luaState, -1);
  }
  else {
    RPC::JSON::ErrorCodeToError(RPC::JSON::ErrorCodeInternalError, error);
    error->setMessage(lua_tostring(this->luaState, -1));
  }

  nStack = lua_gettop(this->luaState);

  lua_pop(this->luaState, 1);

  nStack = lua_gettop(this->luaState);

  return (callResult == 0) ? true : false;
}

#endif
<|endoftext|>


<commit_before>#include "server/request_handler.hpp"

#include "server/api_grammar.hpp"
#include "server/http/reply.hpp"
#include "server/http/request.hpp"

#include "util/json_renderer.hpp"
#include "util/simple_logger.hpp"
#include "util/string_util.hpp"
#include "util/typedefs.hpp"

#include "engine/route_parameters.hpp"
#include "util/json_container.hpp"
#include "osrm/osrm.hpp"

#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>

#include <ctime>

#include <algorithm>
#include <iostream>
#include <string>

namespace osrm
{
namespace server
{

RequestHandler::RequestHandler() : routing_machine(nullptr) {}

void RequestHandler::handle_request(const http::request &current_request,
                                    http::reply &current_reply)
{
    util::json::Object json_result;

    // parse command
    try
    {
        std::string request_string;
        util::URIDecode(current_request.uri, request_string);

        // deactivated as GCC apparently does not implement that, not even in 4.9
        // std::time_t t = std::time(nullptr);
        // util::SimpleLogger().Write() << std::put_time(std::localtime(&t), "%m-%d-%Y %H:%M:%S") <<
        //     " " << current_request.endpoint.to_string() << " " <<
        //     current_request.referrer << ( 0 == current_request.referrer.length() ? "- " :" ") <<
        //     current_request.agent << ( 0 == current_request.agent.length() ? "- " :" ") <<
        //     request;

        time_t ltime;
        struct tm *time_stamp;

        ltime = time(nullptr);
        time_stamp = localtime(&ltime);

        // log timestamp
        util::SimpleLogger().Write()
            << (time_stamp->tm_mday < 10 ? "0" : "") << time_stamp->tm_mday << "-"
            << (time_stamp->tm_mon + 1 < 10 ? "0" : "") << (time_stamp->tm_mon + 1) << "-"
            << 1900 + time_stamp->tm_year << " " << (time_stamp->tm_hour < 10 ? "0" : "")
            << time_stamp->tm_hour << ":" << (time_stamp->tm_min < 10 ? "0" : "")
            << time_stamp->tm_min << ":" << (time_stamp->tm_sec < 10 ? "0" : "")
            << time_stamp->tm_sec << " " << current_request.endpoint.to_string() << " "
            << current_request.referrer << (0 == current_request.referrer.length() ? "- " : " ")
            << current_request.agent << (0 == current_request.agent.length() ? "- " : " ")
            << request_string;

        engine::RouteParameters route_parameters;
        APIGrammarParser api_parser(&route_parameters);

        auto api_iterator = request_string.begin();
        const bool result =
            boost::spirit::qi::parse(api_iterator, request_string.end(), api_parser);

        // check if the was an error with the request
        if (result && api_iterator == request_string.end())
        {
            // parsing done, lets call the right plugin to handle the request
            BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");

            if (!route_parameters.jsonp_parameter.empty())
            { // prepend response with jsonp parameter
                const std::string json_p = (route_parameters.jsonp_parameter + "(");
                current_reply.content.insert(current_reply.content.end(), json_p.begin(),
                                             json_p.end());
            }

            const int return_code = routing_machine->RunQuery(route_parameters, json_result);
            json_result.values["status"] = return_code;
            // 4xx bad request return code
            if (return_code / 100 == 4)
            {
                current_reply.status = http::reply::bad_request;
                current_reply.content.clear();
                route_parameters.output_format.clear();
            }
            else
            {
                // 2xx valid request
                BOOST_ASSERT(return_code / 100 == 2);
            }
        }
        else
        {
            const auto position = std::distance(request_string.begin(), api_iterator);

            current_reply.status = http::reply::bad_request;
            json_result.values["status"] = http::reply::bad_request;
            json_result.values["status_message"] =
                "Query string malformed close to position " + std::to_string(position);
        }

        current_reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
        current_reply.headers.emplace_back("Access-Control-Allow-Methods", "GET");
        current_reply.headers.emplace_back("Access-Control-Allow-Headers",
                                           "X-Requested-With, Content-Type");

        if (route_parameters.service == "tile") {

            /*
            std::istringstream is(json_result.values["pbf"].get<osrm::util::json::String>().value);
            boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
            //in.push(boost::iostreams::gzip_compressor());
            in.push(boost::iostreams::zlib_compressor());
            in.push(is);

            std::ostringstream os;

            boost::iostreams::copy(in,os);

            auto s = os.str();

            std::copy(s.cbegin(),s.cend(), std::back_inserter(current_reply.content));
            */
            std::copy(json_result.values["pbf"].get<osrm::util::json::String>().value.cbegin(),
                      json_result.values["pbf"].get<osrm::util::json::String>().value.cend(),
                      std::back_inserter(current_reply.content));

            //current_reply.content.append(json_result.values["pbf"].get<osrm::util::json::String>().value
            current_reply.headers.emplace_back("Content-Type",
                                               "application/x-protobuf");
        }
        else if (route_parameters.jsonp_parameter.empty())
        { // json file
            util::json::render(current_reply.content, json_result);
            current_reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
            current_reply.headers.emplace_back("Content-Disposition",
                                               "inline; filename=\"response.json\"");
        }
        else
        { // jsonp
            util::json::render(current_reply.content, json_result);
            current_reply.headers.emplace_back("Content-Type", "text/javascript; charset=UTF-8");
            current_reply.headers.emplace_back("Content-Disposition",
                                               "inline; filename=\"response.js\"");
        }
        current_reply.headers.emplace_back("Content-Length",
                                           std::to_string(current_reply.content.size()));
        if (!route_parameters.jsonp_parameter.empty())
        { // append brace to jsonp response
            current_reply.content.push_back(')');
        }
    }
    catch (const std::exception &e)
    {
        current_reply = http::reply::stock_reply(http::reply::internal_server_error);
        util::SimpleLogger().Write(logWARNING) << "[server error] code: " << e.what()
                                               << ", uri: " << current_request.uri;
    }
}

void RequestHandler::RegisterRoutingMachine(OSRM *osrm) { routing_machine = osrm; }
}
}
<commit_msg>Use the correct type when pulling object from variant<commit_after>#include "server/request_handler.hpp"

#include "server/api_grammar.hpp"
#include "server/http/reply.hpp"
#include "server/http/request.hpp"

#include "util/json_renderer.hpp"
#include "util/simple_logger.hpp"
#include "util/string_util.hpp"
#include "util/typedefs.hpp"

#include "engine/route_parameters.hpp"
#include "util/json_container.hpp"
#include "osrm/osrm.hpp"

#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>

#include <ctime>

#include <algorithm>
#include <iostream>
#include <string>

namespace osrm
{
namespace server
{

RequestHandler::RequestHandler() : routing_machine(nullptr) {}

void RequestHandler::handle_request(const http::request &current_request,
                                    http::reply &current_reply)
{
    util::json::Object json_result;

    // parse command
    try
    {
        std::string request_string;
        util::URIDecode(current_request.uri, request_string);

        // deactivated as GCC apparently does not implement that, not even in 4.9
        // std::time_t t = std::time(nullptr);
        // util::SimpleLogger().Write() << std::put_time(std::localtime(&t), "%m-%d-%Y %H:%M:%S") <<
        //     " " << current_request.endpoint.to_string() << " " <<
        //     current_request.referrer << ( 0 == current_request.referrer.length() ? "- " :" ") <<
        //     current_request.agent << ( 0 == current_request.agent.length() ? "- " :" ") <<
        //     request;

        time_t ltime;
        struct tm *time_stamp;

        ltime = time(nullptr);
        time_stamp = localtime(&ltime);

        // log timestamp
        util::SimpleLogger().Write()
            << (time_stamp->tm_mday < 10 ? "0" : "") << time_stamp->tm_mday << "-"
            << (time_stamp->tm_mon + 1 < 10 ? "0" : "") << (time_stamp->tm_mon + 1) << "-"
            << 1900 + time_stamp->tm_year << " " << (time_stamp->tm_hour < 10 ? "0" : "")
            << time_stamp->tm_hour << ":" << (time_stamp->tm_min < 10 ? "0" : "")
            << time_stamp->tm_min << ":" << (time_stamp->tm_sec < 10 ? "0" : "")
            << time_stamp->tm_sec << " " << current_request.endpoint.to_string() << " "
            << current_request.referrer << (0 == current_request.referrer.length() ? "- " : " ")
            << current_request.agent << (0 == current_request.agent.length() ? "- " : " ")
            << request_string;

        engine::RouteParameters route_parameters;
        APIGrammarParser api_parser(&route_parameters);

        auto api_iterator = request_string.begin();
        const bool result =
            boost::spirit::qi::parse(api_iterator, request_string.end(), api_parser);

        // check if the was an error with the request
        if (result && api_iterator == request_string.end())
        {
            // parsing done, lets call the right plugin to handle the request
            BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");

            if (!route_parameters.jsonp_parameter.empty())
            { // prepend response with jsonp parameter
                const std::string json_p = (route_parameters.jsonp_parameter + "(");
                current_reply.content.insert(current_reply.content.end(), json_p.begin(),
                                             json_p.end());
            }

            const int return_code = routing_machine->RunQuery(route_parameters, json_result);
            json_result.values["status"] = return_code;
            // 4xx bad request return code
            if (return_code / 100 == 4)
            {
                current_reply.status = http::reply::bad_request;
                current_reply.content.clear();
                route_parameters.output_format.clear();
            }
            else
            {
                // 2xx valid request
                BOOST_ASSERT(return_code / 100 == 2);
            }
        }
        else
        {
            const auto position = std::distance(request_string.begin(), api_iterator);

            current_reply.status = http::reply::bad_request;
            json_result.values["status"] = http::reply::bad_request;
            json_result.values["status_message"] =
                "Query string malformed close to position " + std::to_string(position);
        }

        current_reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
        current_reply.headers.emplace_back("Access-Control-Allow-Methods", "GET");
        current_reply.headers.emplace_back("Access-Control-Allow-Headers",
                                           "X-Requested-With, Content-Type");

        if (route_parameters.service == "tile") {

            /*
            std::istringstream is(json_result.values["pbf"].get<osrm::util::json::String>().value);
            boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
            //in.push(boost::iostreams::gzip_compressor());
            in.push(boost::iostreams::zlib_compressor());
            in.push(is);

            std::ostringstream os;

            boost::iostreams::copy(in,os);

            auto s = os.str();

            std::copy(s.cbegin(),s.cend(), std::back_inserter(current_reply.content));
            */
            std::copy(json_result.values["pbf"].get<osrm::util::json::Buffer>().value.cbegin(),
                      json_result.values["pbf"].get<osrm::util::json::Buffer>().value.cend(),
                      std::back_inserter(current_reply.content));

            //current_reply.content.append(json_result.values["pbf"].get<osrm::util::json::String>().value
            current_reply.headers.emplace_back("Content-Type",
                                               "application/x-protobuf");
        }
        else if (route_parameters.jsonp_parameter.empty())
        { // json file
            util::json::render(current_reply.content, json_result);
            current_reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
            current_reply.headers.emplace_back("Content-Disposition",
                                               "inline; filename=\"response.json\"");
        }
        else
        { // jsonp
            util::json::render(current_reply.content, json_result);
            current_reply.headers.emplace_back("Content-Type", "text/javascript; charset=UTF-8");
            current_reply.headers.emplace_back("Content-Disposition",
                                               "inline; filename=\"response.js\"");
        }
        current_reply.headers.emplace_back("Content-Length",
                                           std::to_string(current_reply.content.size()));
        if (!route_parameters.jsonp_parameter.empty())
        { // append brace to jsonp response
            current_reply.content.push_back(')');
        }
    }
    catch (const std::exception &e)
    {
        current_reply = http::reply::stock_reply(http::reply::internal_server_error);
        util::SimpleLogger().Write(logWARNING) << "[server error] code: " << e.what()
                                               << ", uri: " << current_request.uri;
    }
}

void RequestHandler::RegisterRoutingMachine(OSRM *osrm) { routing_machine = osrm; }
}
}
<|endoftext|>


<commit_before>#ifndef FMINCL_LINE_SEARCH_COMPUTE_STEP_HPP_
#define FMINCL_LINE_SEARCH_COMPUTE_STEP_HPP_

#include <viennacl/vector.hpp>
#include <viennacl/linalg/inner_prod.hpp>

#include "interpolate.hpp"
#include "termination.hpp"
#include "utils.hpp"

namespace fmincl{

    namespace line_search{

        template<class FUN>
        class step_computer{
        private:
            double zoom(double alo, double ahi, strong_wolf_powell const & termination, viennacl::vector<double> const & x, viennacl::vector<double> const & p) const{
                viennacl::vector<double> xi(x.size());
                viennacl::vector<double> grad(x.size());
                double phi_alo, phi_ahi, dphi_alo, dphi_ahi;
                double aj, phi_aj, dphi_aj;
                while(1){
                    xi = x + alo*p; viennacl::ocl::get_queue().finish(); phi_alo = fun_(xi, &grad); dphi_alo = viennacl::linalg::inner_prod(grad,p);
                    xi = x + ahi*p; viennacl::ocl::get_queue().finish(); phi_ahi = fun_(xi, &grad); dphi_ahi = viennacl::linalg::inner_prod(grad,p);
                    if(alo < ahi)
                        aj = interpolator::cubicmin(alo, ahi, phi_alo, phi_ahi, dphi_alo, dphi_ahi);
                    else
                        aj = interpolator::cubicmin(ahi, alo, phi_ahi, phi_alo, dphi_ahi, dphi_alo);
                    xi = x + aj*p; viennacl::ocl::get_queue().finish(); phi_aj = fun_(xi, NULL);
                    if(!termination.sufficient_decrease(aj,phi_aj) || phi_aj >= phi_alo){
                        ahi = aj;
                    }
                    else{
                        phi_aj = fun_(xi, &grad); dphi_aj = viennacl::linalg::inner_prod(grad,p);
                        if(termination.curvature(dphi_aj))
                            return aj;
                        if(dphi_aj*(ahi - alo) >= 0)
                            ahi = alo;
                        alo = aj;
                    }
                }
            }

        public:
            step_computer(FUN const & fun) : fun_(fun){ }
            double operator()(double phi_0
                              , double dphi_0
                              , double ai
                              , viennacl::vector<double> const & x
                              , viennacl::vector<double> const & p) const{
                size_t dim = x.size();
                double aim1 = 0;
                double phi_aim1 = phi_0;
                double dphi_aim1 = dphi_0;
                strong_wolf_powell termination(phi_0, dphi_0);
                double amax = 2;
                viennacl::vector<double> gi(dim);
                viennacl::vector<double> xi(dim);
                double phi_ai, dphi_ai;
                for(unsigned int i = 1 ; i<10 ; ++i){
                    xi = x + ai*p;
                    phi_ai = fun_(xi, NULL);

                    //Tests sufficient decrease
                    if(!termination.sufficient_decrease(ai, phi_ai) || (i>1 && phi_ai >= phi_aim1))
                        return zoom(aim1, ai, termination, x, p);
                    fun_(xi, &gi);
                    dphi_ai = viennacl::linalg::inner_prod(gi,p);

                    //Tests curvature
                    if(termination.curvature(dphi_ai))
                        return ai;
                    if(dphi_ai>=0)
                        return zoom(ai, aim1, termination, x, p);

                    //Updates states
                    aim1 = ai;
                    phi_aim1 = phi_ai;
                    dphi_aim1 = dphi_ai;

                    ai = 0.5*(aim1+amax);
                }
                std::cout << "failed" << std::endl;
            }
        private:
            FUN const & fun_;
        };

    }

}

#endif
<commit_msg>Various changes<commit_after>#ifndef FMINCL_LINE_SEARCH_COMPUTE_STEP_HPP_
#define FMINCL_LINE_SEARCH_COMPUTE_STEP_HPP_

#include <viennacl/vector.hpp>
#include <viennacl/linalg/inner_prod.hpp>

#include "interpolate.hpp"
#include "termination.hpp"
#include "utils.hpp"

namespace fmincl{

    namespace line_search{

        template<class FUN>
        class step_computer{
        private:
            double zoom(double alo, double ahi, strong_wolf_powell const & termination, viennacl::vector<double> const & x, viennacl::vector<double> const & p) const{
                viennacl::vector<double> xi(x.size());
                viennacl::vector<double> grad(x.size());
                double phi_alo, phi_ahi, dphi_alo, dphi_ahi;
                double aj, phi_aj, dphi_aj;
                while(1){
                    xi = x + alo*p; viennacl::ocl::get_queue().finish(); phi_alo = fun_(xi, &grad); dphi_alo = viennacl::linalg::inner_prod(grad,p);
                    xi = x + ahi*p; viennacl::ocl::get_queue().finish(); phi_ahi = fun_(xi, &grad); dphi_ahi = viennacl::linalg::inner_prod(grad,p);
                    if(alo < ahi)
                        aj = interpolator::cubicmin(alo, ahi, phi_alo, phi_ahi, dphi_alo, dphi_ahi);
                    else
                        aj = interpolator::cubicmin(ahi, alo, phi_ahi, phi_alo, dphi_ahi, dphi_alo);
                    xi = x + aj*p; viennacl::ocl::get_queue().finish(); phi_aj = fun_(xi, NULL);
                    if(!termination.sufficient_decrease(aj,phi_aj) || phi_aj >= phi_alo){
                        ahi = aj;
                    }
                    else{
                        phi_aj = fun_(xi, &grad); dphi_aj = viennacl::linalg::inner_prod(grad,p);
                        if(termination.curvature(dphi_aj))
                            return aj;
                        if(dphi_aj*(ahi - alo) >= 0)
                            ahi = alo;
                        alo = aj;
                    }
                }
            }

        public:
            step_computer(FUN const & fun) : fun_(fun){ }
            double operator()(double phi_0
                              , double dphi_0
                              , double ai
                              , viennacl::vector<double> const & x
                              , viennacl::vector<double> const & p) const{
                size_t dim = x.size();
                double aim1 = 0;
                double phi_aim1 = phi_0;
                double dphi_aim1 = dphi_0;
                strong_wolf_powell termination(phi_0, dphi_0);
                double amax = 2;
                viennacl::vector<double> gi(dim);
                viennacl::vector<double> xi(dim);
                double phi_ai, dphi_ai;
                for(unsigned int i = 1 ; i<10 ; ++i){
                    xi = x + ai*p;
                    phi_ai = fun_(xi, NULL);

                    //Tests sufficient decrease
                    if(!termination.sufficient_decrease(ai, phi_ai) || (i>1 && phi_ai >= phi_aim1))
                        return zoom(aim1, ai, termination, x, p);
                    fun_(xi, &gi);
                    dphi_ai = viennacl::linalg::inner_prod(gi,p);

                    //Tests curvature
                    if(termination.curvature(dphi_ai))
                        return ai;
                    if(dphi_ai>=0)
                        return zoom(ai, aim1, termination, x, p);

                    //Updates states
                    aim1 = ai;
                    phi_aim1 = phi_ai;
                    dphi_aim1 = dphi_ai;
                    ai = 1.4*ai;
                    if(ai>amax || ai<1e-4)
                        return amax;
                }
            }
        private:
            FUN const & fun_;
        };

    }

}

#endif
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Microsoft Corporation
 *
 * -=- Robust Distributed System Nucleus (rDSN) -=-
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
# include <dsn/internal/task_worker.h>
# include "task_engine.h"
# include <sstream>
# include <errno.h>

# ifdef _WIN32

# else
# include <pthread.h>
//# include <sys/prctl.h>
# endif

# ifdef __TITLE__
# undef __TITLE__
# endif
# define __TITLE__ task.worker

namespace dsn {

join_point<void, task_worker*> task_worker::on_start("task_worker::on_start");
join_point<void, task_worker*> task_worker::on_create("task_worker::on_create");

task_worker::task_worker(task_worker_pool* pool, task_queue* q, int index, task_worker* inner_provider)
{
    _owner_pool = pool;
    _input_queue = q;
    _index = index;
    _native_tid = ::dsn::utils::get_invalid_tid();

    char name[256];
    sprintf(name, "%5s.%s.%u", pool->node()->name(), pool->spec().name.c_str(), index);
    _name = std::string(name);
    _is_running = false;

    _thread = nullptr;
}

task_worker::~task_worker()
{
    stop();
}

void task_worker::start()
{
    if (_is_running)
        return;

    _is_running = true;

    _thread = new std::thread(std::bind(&task_worker::run_internal, this));

    _started.wait();
}

void task_worker::stop()
{
    if (!_is_running)
        return;

    _is_running = false;

    _thread->join();
    delete _thread;
    _thread = nullptr;

    _is_running = false;
}

void task_worker::set_name()
{
# ifdef _WIN32

    #ifndef MS_VC_EXCEPTION
    #define MS_VC_EXCEPTION 0x406D1388
    #endif

    typedef struct tagTHREADNAME_INFO
    {
        uint32_t  dwType; // Must be 0x1000.
        LPCSTR szName; // Pointer to name (in user addr space).
        uint32_t  dwThreadID; // Thread ID (-1=caller thread).
        uint32_t  dwFlags; // Reserved for future use, must be zero.
    }THREADNAME_INFO;

    THREADNAME_INFO info;
    info.dwType = 0x1000;
    info.szName = name().c_str();
    info.dwThreadID = (uint32_t)-1;
    info.dwFlags = 0;

    __try
    {
        ::RaiseException (MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(uint32_t), (ULONG_PTR*)&info);
    }
    __except(EXCEPTION_CONTINUE_EXECUTION)
    {
    }

# else
//    prctl(PR_SET_NAME, name(), 0, 0, 0)
# endif
}

void task_worker::set_priority(worker_priority_t pri)
{
# ifdef DSN_PLATFORM_POSIX
    static int policy = SCHED_OTHER;
    static int prio_max =
    #ifdef __linux__
        -20;
    #else
        sched_get_priority_max(policy);
    #endif
    static int prio_min =
    #ifdef __linux__
        19;
    #else
        sched_get_priority_min(policy);
    #endif
    static int prio_middle = ((prio_min + prio_max + 1) / 2);
#endif

    static int g_thread_priority_map[] =
    {
# ifdef _WIN32
        THREAD_PRIORITY_LOWEST,
        THREAD_PRIORITY_BELOW_NORMAL,
        THREAD_PRIORITY_NORMAL,
        THREAD_PRIORITY_ABOVE_NORMAL,
        THREAD_PRIORITY_HIGHEST
# elif defined(DSN_PLATFORM_POSIX)
        prio_min,
        (prio_min + prio_middle) / 2,
        prio_middle,
        (prio_middle + prio_max) / 2,
        prio_max
# endif
    };

    static_assert(ARRAYSIZE(g_thread_priority_map) == THREAD_xPRIORITY_COUNT,
        "ARRAYSIZE(g_thread_priority_map) != THREAD_xPRIORITY_COUNT");

    int prio = g_thread_priority_map[static_cast<int>(pri)];
    bool succ = true;
# if defined(DSN_PLATFORM_POSIX) && !defined(__linux__)
    struct sched_param param;
    memset(&param, 0, sizeof(struct sched_param));
    param.sched_priority = prio;
# endif
    errno = 0;

# ifdef _WIN32
    succ = (::SetThreadPriority(_thread->native_handle(), prio) == TRUE);
# elif defined(__linux__)
    if ((nice(prio) == -1) && (errno != 0))
    {
        succ = false;
    }
# elif defined(DSN_PLATFORM_POSIX)
    succ = (pthread_setschedparam(pthread_self(), policy, &param) == 0);
//# error "not implemented"
# endif

    if (!succ)
    {
        dwarn("You may need priviledge to set thread priority. errno = %d.\n", errno);
    }
}

void task_worker::set_affinity(uint64_t affinity)
{
# ifdef _WIN32
    ::SetThreadAffinityMask(_thread->native_handle(), static_cast<DWORD_PTR>(affinity));
# else
//# error "not implemented"
# endif
}

void task_worker::run_internal()
{
    while (_thread == nullptr)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }

    task::set_current_worker(this);

    _native_tid = ::dsn::utils::get_current_tid();
    set_name();
    set_priority(pool_spec().worker_priority);

    if (true == pool_spec().worker_share_core)
    {
        if (pool_spec().worker_affinity_mask > 0)
        {
            set_affinity(pool_spec().worker_affinity_mask);
        }
    }
    else
    {
        uint64_t current_mask = pool_spec().worker_affinity_mask;
        for (int i = 0; i < _index; ++i)
        {
            current_mask &= (current_mask - 1);
            if (0 == current_mask)
            {
                current_mask = pool_spec().worker_affinity_mask;
            }
        }
        current_mask -= (current_mask & (current_mask - 1));

        set_affinity(current_mask);
    }

    _started.notify();

    on_start.execute(this);

    loop();
}

void task_worker::loop()
{
    task_queue* q = queue();

    //try {
        while (_is_running)
        {
            task_ptr task = q->dequeue();
            if (task != nullptr)
            {
                task->exec_internal();
            }
        }
    /*}
    catch (std::exception& ex)
    {
        dassert (false, "%s: unhandled exception '%s'", name().c_str(), ex.what());
    }*/
}

const threadpool_spec& task_worker::pool_spec() const
{
    return pool()->spec();
}

} // end namespace
<commit_msg>1. Use _thread->native_handle() to set thread priority instead of pthread_self(). 2. Implement setting thread names for pthread.<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Microsoft Corporation
 *
 * -=- Robust Distributed System Nucleus (rDSN) -=-
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
# include <dsn/internal/task_worker.h>
# include "task_engine.h"
# include <sstream>
# include <errno.h>

# ifdef _WIN32

# else
# include <pthread.h>
//# include <sys/prctl.h>
# endif

# ifdef __TITLE__
# undef __TITLE__
# endif
# define __TITLE__ task.worker

namespace dsn {

join_point<void, task_worker*> task_worker::on_start("task_worker::on_start");
join_point<void, task_worker*> task_worker::on_create("task_worker::on_create");

task_worker::task_worker(task_worker_pool* pool, task_queue* q, int index, task_worker* inner_provider)
{
    _owner_pool = pool;
    _input_queue = q;
    _index = index;
    _native_tid = ::dsn::utils::get_invalid_tid();

    char name[256];
    sprintf(name, "%5s.%s.%u", pool->node()->name(), pool->spec().name.c_str(), index);
    _name = std::string(name);
    _is_running = false;

    _thread = nullptr;
}

task_worker::~task_worker()
{
    stop();
}

void task_worker::start()
{
    if (_is_running)
        return;

    _is_running = true;

    _thread = new std::thread(std::bind(&task_worker::run_internal, this));

    _started.wait();
}

void task_worker::stop()
{
    if (!_is_running)
        return;

    _is_running = false;

    _thread->join();
    delete _thread;
    _thread = nullptr;

    _is_running = false;
}

void task_worker::set_name()
{
# ifdef _WIN32

    #ifndef MS_VC_EXCEPTION
    #define MS_VC_EXCEPTION 0x406D1388
    #endif

    typedef struct tagTHREADNAME_INFO
    {
        uint32_t  dwType; // Must be 0x1000.
        LPCSTR szName; // Pointer to name (in user addr space).
        uint32_t  dwThreadID; // Thread ID (-1=caller thread).
        uint32_t  dwFlags; // Reserved for future use, must be zero.
    }THREADNAME_INFO;

    THREADNAME_INFO info;
    info.dwType = 0x1000;
    info.szName = name().c_str();
    info.dwThreadID = (uint32_t)-1;
    info.dwFlags = 0;

    __try
    {
        ::RaiseException (MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(uint32_t), (ULONG_PTR*)&info);
    }
    __except(EXCEPTION_CONTINUE_EXECUTION)
    {
    }

# elif defined(DSN_PLATFORM_POSIX)
    const size_t len = 16;
    std::string thread_name = name().substr(0, (len - 1));
    int ret = pthread_setname_np(_thread->native_handle(), thread_name.c_str());
    if (ret != 0)
    {
        dwarn("Fail to set pthread name. ret = %d", ret);
    }
# else
//    prctl(PR_SET_NAME, name(), 0, 0, 0)
# endif
}

void task_worker::set_priority(worker_priority_t pri)
{
# ifdef DSN_PLATFORM_POSIX
    static int policy = SCHED_OTHER;
    static int prio_max =
    #ifdef __linux__
        -20;
    #else
        sched_get_priority_max(policy);
    #endif
    static int prio_min =
    #ifdef __linux__
        19;
    #else
        sched_get_priority_min(policy);
    #endif
    static int prio_middle = ((prio_min + prio_max + 1) / 2);
#endif

    static int g_thread_priority_map[] =
    {
# ifdef _WIN32
        THREAD_PRIORITY_LOWEST,
        THREAD_PRIORITY_BELOW_NORMAL,
        THREAD_PRIORITY_NORMAL,
        THREAD_PRIORITY_ABOVE_NORMAL,
        THREAD_PRIORITY_HIGHEST
# elif defined(DSN_PLATFORM_POSIX)
        prio_min,
        (prio_min + prio_middle) / 2,
        prio_middle,
        (prio_middle + prio_max) / 2,
        prio_max
# endif
    };

    static_assert(ARRAYSIZE(g_thread_priority_map) == THREAD_xPRIORITY_COUNT,
        "ARRAYSIZE(g_thread_priority_map) != THREAD_xPRIORITY_COUNT");

    int prio = g_thread_priority_map[static_cast<int>(pri)];
    bool succ = true;
# if defined(DSN_PLATFORM_POSIX) && !defined(__linux__)
    struct sched_param param;
    memset(&param, 0, sizeof(struct sched_param));
    param.sched_priority = prio;
# endif
    errno = 0;

# ifdef _WIN32
    succ = (::SetThreadPriority(_thread->native_handle(), prio) == TRUE);
# elif defined(__linux__)
    if ((nice(prio) == -1) && (errno != 0))
    {
        succ = false;
    }
# elif defined(DSN_PLATFORM_POSIX)
    succ = (pthread_setschedparam(_thread->native_handle(), policy, &param) == 0);
//# error "not implemented"
# endif

    if (!succ)
    {
        dwarn("You may need priviledge to set thread priority. errno = %d.\n", errno);
    }
}

void task_worker::set_affinity(uint64_t affinity)
{
# ifdef _WIN32
    ::SetThreadAffinityMask(_thread->native_handle(), static_cast<DWORD_PTR>(affinity));
# else
//# error "not implemented"
# endif
}

void task_worker::run_internal()
{
    while (_thread == nullptr)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }

    task::set_current_worker(this);

    _native_tid = ::dsn::utils::get_current_tid();
    set_name();
    set_priority(pool_spec().worker_priority);

    if (true == pool_spec().worker_share_core)
    {
        if (pool_spec().worker_affinity_mask > 0)
        {
            set_affinity(pool_spec().worker_affinity_mask);
        }
    }
    else
    {
        uint64_t current_mask = pool_spec().worker_affinity_mask;
        for (int i = 0; i < _index; ++i)
        {
            current_mask &= (current_mask - 1);
            if (0 == current_mask)
            {
                current_mask = pool_spec().worker_affinity_mask;
            }
        }
        current_mask -= (current_mask & (current_mask - 1));

        set_affinity(current_mask);
    }

    _started.notify();

    on_start.execute(this);

    loop();
}

void task_worker::loop()
{
    task_queue* q = queue();

    //try {
        while (_is_running)
        {
            task_ptr task = q->dequeue();
            if (task != nullptr)
            {
                task->exec_internal();
            }
        }
    /*}
    catch (std::exception& ex)
    {
        dassert (false, "%s: unhandled exception '%s'", name().c_str(), ex.what());
    }*/
}

const threadpool_spec& task_worker::pool_spec() const
{
    return pool()->spec();
}

} // end namespace
<|endoftext|>


<commit_before>#include "dlangdebughelper.h"

#include <QDebug>
#include <QElapsedTimer>

#include <limits>

using namespace DlangEditor;

namespace {
class TotalStatistics
{
public:

    ~TotalStatistics() {
        qDebug() << "Total statistics: \n";
        for (StatisticsMap::const_iterator it = counters.begin(); it != counters.end(); ++it) {
            qDebug() << it.key() << ":\tmin = " << it.value().min() << "\tmax = "
                     << it.value().max() << "\tnum = " << it.value().num() << "\tavg = " << it.value().avg();
        }
    }

    void AddElapsedTime(const QString& s, int t) {
        counters[s].addValue(t);
    }

private:
    struct Statistics {
        int m_sum;
        int m_num;
        int m_max;
        int m_min;
        void addValue(int v) {
            m_sum += v;
            if (v > m_max) m_max = v;
            if (v < m_min) m_min = v;
            ++m_num;
        }

        double avg() const {
            return static_cast<double>(m_sum)/m_num;
        }

        int max() const {
            return m_max;
        }

        int min() const {
            return m_num ? m_min : 0;
        }

        int num() const {
            return m_num;
        }

        Statistics() : m_sum(0), m_num(0), m_max(0), m_min(std::numeric_limits<int>::max()) {}
    };

    typedef QMap<QString, Statistics> StatisticsMap;
    StatisticsMap counters;
};

TotalStatistics *staticStats = 0;

TotalStatistics& stat() {
    if (!staticStats) {
        staticStats = new TotalStatistics;
    }
    return *staticStats;
}
}

DlangDebugHelper::DlangDebugHelper(const char *func, const char *str)
    : str(str), func(func)
{
    init();
}

DlangDebugHelper::DlangDebugHelper(const char *func, const QString &str)
    : str(str), func(func)
{
    init();
}

DlangDebugHelper::~DlangDebugHelper()
{
    qint64 t = timer.elapsed();
    qDebug() << "[out] " << func << " time=" << t;
    stat().AddElapsedTime(func, t);
}

void DlangDebugHelper::init()
{
    qDebug() << "[in] " << func << ' ' << str;
    timer.start();
}
<commit_msg>Fix build on windows<commit_after>#include "dlangdebughelper.h"

#include <QDebug>
#include <QElapsedTimer>

#include <limits>

using namespace DlangEditor;

namespace {
class TotalStatistics
{
public:

    ~TotalStatistics() {
        qDebug() << "Total statistics: \n";
        for (StatisticsMap::const_iterator it = counters.begin(); it != counters.end(); ++it) {
            qDebug() << it.key() << ":\tmin = " << it.value().min() << "\tmax = "
                     << it.value().max() << "\tnum = " << it.value().num() << "\tavg = " << it.value().avg();
        }
    }

    void AddElapsedTime(const QString& s, int t) {
        counters[s].addValue(t);
    }

private:
    struct Statistics {
        int m_sum;
        int m_num;
        int m_max;
        int m_min;
        void addValue(int v) {
            m_sum += v;
            if (v > m_max) m_max = v;
            if (v < m_min) m_min = v;
            ++m_num;
        }

        double avg() const {
            return static_cast<double>(m_sum)/m_num;
        }

        int max() const {
            return m_max;
        }

        int min() const {
            return m_num ? m_min : 0;
        }

        int num() const {
            return m_num;
        }

        Statistics() : m_sum(0), m_num(0), m_max(0), m_min(std::numeric_limits<int>::max()) {}
    };

    typedef QMap<QString, Statistics> StatisticsMap;
    StatisticsMap counters;
};

TotalStatistics *staticStats = 0;

TotalStatistics& totalStat() {
    if (!staticStats) {
        staticStats = new TotalStatistics;
    }
    return *staticStats;
}
}

DlangDebugHelper::DlangDebugHelper(const char *func, const char *str)
    : str(str), func(func)
{
    init();
}

DlangDebugHelper::DlangDebugHelper(const char *func, const QString &str)
    : str(str), func(func)
{
    init();
}

DlangDebugHelper::~DlangDebugHelper()
{
    qint64 t = timer.elapsed();
    qDebug() << "[out] " << func << " time=" << t;
    totalStat().AddElapsedTime(func, t);
}

void DlangDebugHelper::init()
{
    qDebug() << "[in] " << func << ' ' << str;
    timer.start();
}
<|endoftext|>


<commit_before>/*
    Persons Model
    Copyright (C) 2012  Aleix Pol Gonzalez <aleixpol@blue-systems.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "duplicatesfinder.h"
#include "persons-model.h"
#include <QDebug>

DuplicatesFinder::DuplicatesFinder(PersonsModel* model, QObject* parent)
    : KJob(parent)
    , m_model(model)
{
    m_compareRoles << PersonsModel::NameRole << PersonsModel::EmailRole << PersonsModel::NickRole << PersonsModel::PhoneRole << PersonsModel::IMRole;
}

void DuplicatesFinder::start()
{
    QMetaObject::invokeMethod(this, "doSearch", Qt::QueuedConnection);
}

void DuplicatesFinder::doSearch()
{
    //NOTE: This can probably optimized. I'm just trying to get the semantics right at the moment
    //maybe using nepomuk for the matching would help?

    QVector< QVariantList > collectedValues;
    m_matches.clear();

    int count = m_model->rowCount();
    for(int i=0; i<count; i++) {
        QModelIndex idx = m_model->index(i, 0);

        //we gather the values
        QVariantList values;
        for(int role=0; role<m_compareRoles.size(); role++) {
            values += idx.data(m_compareRoles[role]);
        }
        Q_ASSERT(values.size()==m_compareRoles.size());

        //we check if it matches
        int j=0;
        foreach(const QVariantList& valueToCompare, collectedValues) {
            QList< int > matchedRoles = matchAt(values, valueToCompare);
            if(!matchedRoles.isEmpty())
                m_matches.append(Match(matchedRoles, i, j));
            j++;
        }

        //we add our data for comparing later
        collectedValues.append(values);
    }
    emitResult();
}

QList<int> DuplicatesFinder::matchAt(const QVariantList& value, const QVariantList& toCompare) const
{
    QList<int> ret;
    Q_ASSERT(value.size()==toCompare.size());
    for(int i=0; i<toCompare.size(); i++) {
        if(!value[i].isNull() && value[i]==toCompare[i])
            ret += m_compareRoles[i];
    }
    return ret;
}

QList< Match > DuplicatesFinder::results() const
{
    return m_matches;
}
<commit_msg>add todo<commit_after>/*
    Persons Model
    Copyright (C) 2012  Aleix Pol Gonzalez <aleixpol@blue-systems.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "duplicatesfinder.h"
#include "persons-model.h"
#include <QDebug>

DuplicatesFinder::DuplicatesFinder(PersonsModel* model, QObject* parent)
    : KJob(parent)
    , m_model(model)
{
    m_compareRoles << PersonsModel::NameRole << PersonsModel::EmailRole << PersonsModel::NickRole << PersonsModel::PhoneRole << PersonsModel::IMRole;
}

void DuplicatesFinder::start()
{
    QMetaObject::invokeMethod(this, "doSearch", Qt::QueuedConnection);
}

//TODO: start providing partial results so that we can start processing matches while it's not done
void DuplicatesFinder::doSearch()
{
    //NOTE: This can probably optimized. I'm just trying to get the semantics right at the moment
    //maybe using nepomuk for the matching would help?

    QVector< QVariantList > collectedValues;
    m_matches.clear();

    int count = m_model->rowCount();
    for(int i=0; i<count; i++) {
        QModelIndex idx = m_model->index(i, 0);

        //we gather the values
        QVariantList values;
        for(int role=0; role<m_compareRoles.size(); role++) {
            values += idx.data(m_compareRoles[role]);
        }
        Q_ASSERT(values.size()==m_compareRoles.size());

        //we check if it matches
        int j=0;
        foreach(const QVariantList& valueToCompare, collectedValues) {
            QList< int > matchedRoles = matchAt(values, valueToCompare);
            if(!matchedRoles.isEmpty())
                m_matches.append(Match(matchedRoles, i, j));
            j++;
        }

        //we add our data for comparing later
        collectedValues.append(values);
    }
    emitResult();
}

QList<int> DuplicatesFinder::matchAt(const QVariantList& value, const QVariantList& toCompare) const
{
    QList<int> ret;
    Q_ASSERT(value.size()==toCompare.size());
    for(int i=0; i<toCompare.size(); i++) {
        if(!value[i].isNull() && value[i]==toCompare[i])
            ret += m_compareRoles[i];
    }
    return ret;
}

QList< Match > DuplicatesFinder::results() const
{
    return m_matches;
}
<|endoftext|>


<commit_before>#include "precompiled.h"

#include "engine/math/vec2.h"

#include "engine/math/random.h"

vec2::vec2() : x(0), y(0) {

}

vec2::vec2(const int newX, const int newY) : x(newX), y(newY) {

}

vec2::vec2(const vec2& vec) : x(vec.x), y(vec.y) {

}

vec2& vec2::operator +=(const vec2 &rhs) {
	this->x += rhs.x;
	this->y += rhs.y;
	return *this;
}

vec2& vec2::operator -=(const vec2 &rhs) {
	this->x -= rhs.x;
	this->y -= rhs.y;
	return *this;
}

vec2& vec2::operator *=(int rhs) {
	this->x *= rhs;
	this->y *= rhs;
	return *this;
}

vec2& vec2::operator /=(int rhs) {
	this->x /= rhs;
	this->y /= rhs;
	return *this;
}

bool vec2::operator ==(const vec2 &rhs) {
	return this->x == rhs.x && this->y == rhs.y;
}

bool vec2::operator !=(const vec2 &rhs) {
	return this->x != rhs.x || this->y != rhs.y;
}

vec2 vec2::operator +(const vec2 &rhs) {
	return vec2(*this) += rhs;
}

vec2 vec2::operator -(const vec2 &rhs) {
	return vec2(*this) -= rhs;
}

vec2 vec2::operator *(int rhs) {
	return vec2(*this) *= rhs;
}

vec2 vec2::operator /(int rhs) {
	return vec2(*this) /= rhs;
}

int vec2::operator *(const vec2 &rhs) {
	return this->x * rhs.x + this->y * rhs.y;
}

int vec2::lengthSquared() const {
	return x * x + y * y;
}

double vec2::length() const {
	return sqrt((double) lengthSquared());
}

bool vec2::operator <(const vec2 & rhs) const {
	return lengthSquared() < rhs.lengthSquared();
}

bool vec2::operator >(const vec2 & rhs) const {
	return lengthSquared() > rhs.lengthSquared();
}

/**
 * set vector to random n / s / e / w direction with speed 1
 */
void vec2::randomNSWE() {
	switch(randomRange(0,3)){
	case 0:
		x = 1; y = 0;
		break;
	case 1:
		x = -1; y = 0;
		break;
	case 2:
		x = 0; y = -1;
		break;
	case 3:
		x = 0; y = 1;
		break;
	default:
		x = 1; y = 0;
		break;
	}
}
<commit_msg>Visual enhancements to the vec2 class.<commit_after>#include "precompiled.h"

#include "engine/math/vec2.h"

#include "engine/math/random.h"

vec2::vec2()
	: x(0)
	, y(0)
{ }

vec2::vec2(const int newX, const int newY)
	: x(newX)
	, y(newY)
{ }

vec2::vec2(const vec2& vec)
	: x(vec.x)
	, y(vec.y)
{ }

vec2& vec2::operator +=(const vec2 &rhs) {
	this->x += rhs.x;
	this->y += rhs.y;
	return *this;
}

vec2& vec2::operator -=(const vec2 &rhs) {
	this->x -= rhs.x;
	this->y -= rhs.y;
	return *this;
}

vec2& vec2::operator *=(int rhs) {
	this->x *= rhs;
	this->y *= rhs;
	return *this;
}

vec2& vec2::operator /=(int rhs) {
	this->x /= rhs;
	this->y /= rhs;
	return *this;
}

bool vec2::operator ==(const vec2 &rhs) {
	return this->x == rhs.x && this->y == rhs.y;
}

bool vec2::operator !=(const vec2 &rhs) {
	return this->x != rhs.x || this->y != rhs.y;
}

vec2 vec2::operator +(const vec2 &rhs) {
	return vec2(*this) += rhs;
}

vec2 vec2::operator -(const vec2 &rhs) {
	return vec2(*this) -= rhs;
}

vec2 vec2::operator *(int rhs) {
	return vec2(*this) *= rhs;
}

vec2 vec2::operator /(int rhs) {
	return vec2(*this) /= rhs;
}

int vec2::operator *(const vec2 &rhs) {
	return this->x * rhs.x + this->y * rhs.y;
}

int vec2::lengthSquared() const {
	return x * x + y * y;
}

double vec2::length() const {
	return sqrt((double) lengthSquared());
}

bool vec2::operator <(const vec2 & rhs) const {
	return lengthSquared() < rhs.lengthSquared();
}

bool vec2::operator >(const vec2 & rhs) const {
	return lengthSquared() > rhs.lengthSquared();
}

/**
 * set vector to random n / s / e / w direction with speed 1
 */
void vec2::randomNSWE() {
	switch(randomRange(0,3)){
	case 0:
		x = 1; y = 0;
		break;
	case 1:
		x = -1; y = 0;
		break;
	case 2:
		x = 0; y = -1;
		break;
	case 3:
		x = 0; y = 1;
		break;
	default:
		x = 1; y = 0;
		break;
	}
}
<|endoftext|>